View Javadoc

1   /**
2    * This source code file is part of a direct port of Stan Birchfield's implementation
3    * of a Kanade-Lucas-Tomasi feature tracker. The original implementation can be found
4    * here: http://www.ces.clemson.edu/~stb/klt/
5    *
6    * As per the original code, the source code is in the public domain, available
7    * for both commercial and non-commercial use.
8    */
9   package org.openimaj.video.tracking.klt;
10  
11  import java.io.DataInput;
12  import java.io.DataOutput;
13  import java.io.DataOutputStream;
14  import java.io.IOException;
15  import java.io.PrintWriter;
16  import java.util.Scanner;
17  
18  import org.openimaj.math.geometry.point.Point2d;
19  
20  import Jama.Matrix;
21  
22  /**
23   * A tracked feature
24   *
25   * @author Stan Birchfield
26   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
27   */
28  public class Feature implements Point2d, Cloneable {
29  	/**
30  	 * x ordinate of feature
31  	 */
32  	public float x;
33  
34  	/**
35  	 * y ordinate of feature
36  	 */
37  	public float y;
38  
39  	/**
40  	 * value of feature
41  	 */
42  	public int val;
43  
44  	/* for affine mapping */
45  	// public FImage aff_img;
46  	// public FImage aff_img_gradx;
47  	// public FImage aff_img_grady;
48  	// public float aff_x;
49  	// public float aff_y;
50  	// public float aff_Axx;
51  	// public float aff_Ayx;
52  	// public float aff_Axy;
53  	// public float aff_Ayy;
54  
55  	/**
56  	 * Convert to string representation with the given format
57  	 * 
58  	 * @param format
59  	 * @param type
60  	 * @return formatted string
61  	 */
62  	public String toString(String format, String type) {
63  		assert (type.equals("f") || type.equals("d"));
64  		String s = "";
65  
66  		if (type.equals("f"))
67  			s += String.format(format, x, y, val);
68  		else if (type.equals("d")) {
69  			/* Round x & y to nearest integer, unless negative */
70  			float _x = x;
71  			float _y = y;
72  			if (_x >= 0.0)
73  				_x += 0.5;
74  			if (_y >= 0.0)
75  				_y += 0.5;
76  			s += String.format(format, (int) x, (int) y, val);
77  		}
78  
79  		return s;
80  	}
81  
82  	/**
83  	 * Write feature as binary data
84  	 * 
85  	 * @param os
86  	 * @throws IOException
87  	 */
88  	public void writeFeatureBin(DataOutputStream os) throws IOException {
89  		os.writeFloat(x);
90  		os.writeFloat(y);
91  		os.writeInt(val);
92  	}
93  
94  	@Override
95  	public float getX() {
96  		return x;
97  	}
98  
99  	@Override
100 	public float getY() {
101 		return y;
102 	}
103 
104 	@Override
105 	public void setX(float x) {
106 		this.x = x;
107 	}
108 
109 	@Override
110 	public void setY(float y) {
111 		this.y = y;
112 	}
113 
114 	@Override
115 	public Feature clone() {
116 		final Feature f = new Feature();
117 
118 		f.x = x;
119 		f.y = y;
120 		f.val = val;
121 		// f.aff_img = aff_img;
122 		// f.aff_img_gradx = aff_img_gradx;
123 		// f.aff_img_grady = aff_img_grady;
124 		// f.aff_x = aff_x;
125 		// f.aff_y = aff_y;
126 		// f.aff_Axx = aff_Axx;
127 		// f.aff_Ayx = aff_Ayx;
128 		// f.aff_Axy = aff_Axy;
129 		// f.aff_Ayy = aff_Ayy;
130 
131 		return f;
132 	}
133 
134 	@Override
135 	public boolean equals(Object o) {
136 		if (this == o)
137 			return true;
138 		if (!(o instanceof Feature))
139 			return false;
140 
141 		if (((Feature) o).x == x && ((Feature) o).y == y && ((Feature) o).val == val)
142 			return true;
143 		return false;
144 	}
145 
146 	@Override
147 	public int hashCode() {
148 		int hash = 17;
149 		hash = (int) ((31 * hash) + x);
150 		hash = (int) ((31 * hash) + y);
151 		hash = ((31 * hash) + val);
152 		// hash = (int) ((31 * hash) + aff_img;
153 		// hash = (int) ((31 * hash) + aff_img_gradx;
154 		// hash = (int) ((31 * hash) + aff_img_grady;
155 		// hash = (int) ((31 * hash) + aff_x;
156 		// hash = (int) ((31 * hash) + aff_y;
157 		// hash = (int) ((31 * hash) + aff_Axx;
158 		// hash = (int) ((31 * hash) + aff_Ayx;
159 		// hash = (int) ((31 * hash) + aff_Axy;
160 		// hash = (int) ((31 * hash) + aff_Ayy;
161 
162 		return hash;
163 	}
164 
165 	@Override
166 	public String toString() {
167 		return "Feature(" + x + ", " + y + ", " + val + ")";
168 	}
169 
170 	@Override
171 	public void copyFrom(Point2d p)
172 	{
173 		setX(p.getX());
174 		setY(p.getY());
175 	}
176 
177 	@Override
178 	public Float getOrdinate(int dimension) {
179 		if (dimension == 0)
180 			return x;
181 		return y;
182 	}
183 
184 	@Override
185 	public int getDimensions() {
186 		return 2;
187 	}
188 
189 	@Override
190 	public void translate(float x, float y) {
191 		this.x += x;
192 		this.y += y;
193 	}
194 
195 	@Override
196 	public Feature transform(Matrix transform) {
197 		if (transform.getRowDimension() == 3) {
198 			float xt = (float) transform.get(0, 0) * getX() + (float) transform.get(0, 1) * getY()
199 					+ (float) transform.get(0, 2);
200 			float yt = (float) transform.get(1, 0) * getX() + (float) transform.get(1, 1) * getY()
201 					+ (float) transform.get(1, 2);
202 			final float zt = (float) transform.get(2, 0) * getX() + (float) transform.get(2, 1) * getY()
203 					+ (float) transform.get(2, 2);
204 
205 			xt /= zt;
206 			yt /= zt;
207 
208 			final Feature f = this.clone();
209 			f.x = xt;
210 			f.y = yt;
211 			return f;
212 		} else if (transform.getRowDimension() == 2) {
213 			final float xt = (float) transform.get(0, 0) * getX() + (float) transform.get(0, 1) * getY();
214 			final float yt = (float) transform.get(1, 0) * getX() + (float) transform.get(1, 1) * getY();
215 
216 			final Feature f = this.clone();
217 			f.x = xt;
218 			f.y = yt;
219 			return f;
220 		}
221 		throw new IllegalArgumentException("Transform matrix has unexpected size");
222 	}
223 
224 	@Override
225 	public Point2d minus(Point2d a) {
226 		final Point2d p = this.clone();
227 		p.setX(this.getX() - a.getX());
228 		p.setY(this.getY() - a.getY());
229 		return p;
230 	}
231 
232 	@Override
233 	public void readASCII(Scanner in) throws IOException {
234 		x = in.nextFloat();
235 		y = in.nextFloat();
236 		val = in.nextInt();
237 	}
238 
239 	@Override
240 	public String asciiHeader() {
241 		return this.getClass().getName();
242 	}
243 
244 	@Override
245 	public void readBinary(DataInput in) throws IOException {
246 		x = in.readFloat();
247 		y = in.readFloat();
248 		val = in.readInt();
249 	}
250 
251 	@Override
252 	public byte[] binaryHeader() {
253 		return this.getClass().getName().getBytes();
254 	}
255 
256 	@Override
257 	public void writeASCII(PrintWriter out) throws IOException {
258 		out.format("%f %f %d", x, y, val);
259 	}
260 
261 	@Override
262 	public void writeBinary(DataOutput out) throws IOException {
263 		out.writeFloat(x);
264 		out.writeFloat(y);
265 		out.writeInt(val);
266 	}
267 
268 	@Override
269 	public void translate(Point2d v) {
270 		this.translate(v.getX(), v.getY());
271 	}
272 
273 	@Override
274 	public Feature copy() {
275 		return clone();
276 	}
277 
278 	@Override
279 	public void setOrdinate(int dimension, Number value) {
280 		if (dimension == 0)
281 			x = value.floatValue();
282 		if (dimension == 1)
283 			y = value.floatValue();
284 	}
285 }