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.File;
12  import java.io.IOException;
13  import java.util.Arrays;
14  import java.util.BitSet;
15  import java.util.Comparator;
16  
17  import org.openimaj.image.FImage;
18  import org.openimaj.image.ImageUtilities;
19  import org.openimaj.image.processing.convolution.FGaussianConvolve;
20  import org.openimaj.math.geometry.point.Point2d;
21  import org.openimaj.math.geometry.point.Point2dImpl;
22  
23  /**
24   * The KLT tracker
25   * 
26   * @author Stan Birchfield
27   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
28   */
29  public class KLTTracker {
30  	protected int KLT_verbose = 0;
31  
32  	/**
33  	 * The feature was tracked
34  	 */
35  	public static final int KLT_TRACKED = 0;
36  	/**
37  	 * The feature was not found
38  	 */
39  	public static final int KLT_NOT_FOUND = -1;
40  	/**
41  	 * The determinant was too small
42  	 */
43  	public static final int KLT_SMALL_DET = -2;
44  	/**
45  	 * The maximum number of iterations was exceeded
46  	 */
47  	public static final int KLT_MAX_ITERATIONS = -3;
48  	/**
49  	 * The feature was out of bouns
50  	 */
51  	public static final int KLT_OOB = -4;
52  	/**
53  	 * The residue was too large
54  	 */
55  	public static final int KLT_LARGE_RESIDUE = -5;
56  
57  	/**
58  	 * Modes of operation for selecting features.
59  	 */
60  	public enum SelectionMode {
61  		/**
62  		 * selecting all features
63  		 */
64  		SELECTING_ALL,
65  		/**
66  		 * Replacing some features
67  		 */
68  		REPLACING_SOME
69  	}
70  
71  	TrackingContext tc;
72  	FeatureList featurelist;
73  	boolean isNorm = true; // true if input images are in [0..1] range, false if
74  							// [0..255]
75  
76  	/**
77  	 * Construct with the given target number of features.
78  	 * 
79  	 * @param nfeatures
80  	 */
81  	public KLTTracker(int nfeatures) {
82  		this.tc = new TrackingContext();
83  		this.featurelist = new FeatureList(nfeatures);
84  	}
85  
86  	/**
87  	 * Construct with the given context and feature list
88  	 * 
89  	 * @param tc
90  	 * @param featurelist
91  	 */
92  	public KLTTracker(TrackingContext tc, FeatureList featurelist) {
93  		this.tc = tc;
94  		this.featurelist = featurelist;
95  	}
96  
97  	/*********************************************************************/
98  	private void _fillFeaturemap(int x, int y, BitSet featuremap, int mindist, int ncols, int nrows)
99  	{
100 		int ix, iy;
101 
102 		for (iy = y - mindist; iy <= y + mindist; iy++)
103 			for (ix = x - mindist; ix <= x + mindist; ix++)
104 				if (ix >= 0 && ix < ncols && iy >= 0 && iy < nrows)
105 					featuremap.set(iy * ncols + ix);
106 	}
107 
108 	/*********************************************************************
109 	 * _enforceMinimumDistance
110 	 * 
111 	 * Removes features that are within close proximity to better features.
112 	 * 
113 	 * INPUTS featurelist: A list of features. The nFeatures property is used.
114 	 * 
115 	 * OUTPUTS featurelist: Is overwritten. Nearby "redundant" features are
116 	 * removed. Writes -1's into the remaining elements.
117 	 * 
118 	 * RETURNS The number of remaining features.
119 	 */
120 	private void _enforceMinimumDistance(
121 			int[][] pointlist, /* featurepoints */
122 			int ncols, int nrows, /* size of images */
123 			int mindist, /* min. dist b/w features */
124 			int min_eigenvalue, /* min. eigenvalue */
125 			boolean overwriteAllFeatures)
126 	{
127 		final int npoints = pointlist.length;
128 
129 		int indx; /* Index into features */
130 		int x, y, val; /*
131 						 * Location and trackability of pixel under
132 						 * consideration
133 						 */
134 		BitSet featuremap; /* Boolean array recording proximity of features */
135 		int ptr;
136 
137 		/* Cannot add features with an eigenvalue less than one */
138 		if (min_eigenvalue < 1)
139 			min_eigenvalue = 1;
140 
141 		/* Allocate memory for feature map and clear it */
142 		featuremap = new BitSet(ncols * nrows);
143 
144 		/* Necessary because code below works with (mindist-1) */
145 		mindist--;
146 
147 		/*
148 		 * If we are keeping all old good features, then add them to the
149 		 * featuremap
150 		 */
151 		if (!overwriteAllFeatures)
152 			for (indx = 0; indx < featurelist.features.length; indx++)
153 				if (featurelist.features[indx].val >= 0) {
154 					x = (int) featurelist.features[indx].x;
155 					y = (int) featurelist.features[indx].y;
156 					_fillFeaturemap(x, y, featuremap, mindist, ncols, nrows);
157 				}
158 
159 		/* For each feature point, in descending order of importance, do ... */
160 		ptr = 0;
161 		indx = 0;
162 		while (true) {
163 			/*
164 			 * If we can't add all the points, then fill in the rest of the
165 			 * featurelist with -1's
166 			 */
167 			if (ptr >= npoints) {
168 				while (indx < featurelist.features.length) {
169 					if (overwriteAllFeatures ||
170 							featurelist.features[indx].val < 0)
171 					{
172 						featurelist.features[indx].x = -1;
173 						featurelist.features[indx].y = -1;
174 						featurelist.features[indx].val = KLT_NOT_FOUND;
175 						// featurelist.features[indx].aff_img = null;
176 						// featurelist.features[indx].aff_img_gradx = null;
177 						// featurelist.features[indx].aff_img_grady = null;
178 						// featurelist.features[indx].aff_x = -1.0f;
179 						// featurelist.features[indx].aff_y = -1.0f;
180 						// featurelist.features[indx].aff_Axx = 1.0f;
181 						// featurelist.features[indx].aff_Ayx = 0.0f;
182 						// featurelist.features[indx].aff_Axy = 0.0f;
183 						// featurelist.features[indx].aff_Ayy = 1.0f;
184 					}
185 					indx++;
186 				}
187 				break;
188 			}
189 
190 			x = pointlist[ptr][0];
191 			y = pointlist[ptr][1];
192 			val = pointlist[ptr][2];
193 			ptr++;
194 
195 			/* Ensure that feature is in-bounds */
196 			assert (x >= 0);
197 			assert (x < ncols);
198 			assert (y >= 0);
199 			assert (y < nrows);
200 
201 			while (!overwriteAllFeatures &&
202 					indx < featurelist.features.length &&
203 					featurelist.features[indx].val >= 0)
204 				indx++;
205 
206 			if (indx >= featurelist.features.length)
207 				break;
208 
209 			/*
210 			 * If no neighbor has been selected, and if the minimum eigenvalue
211 			 * is large enough, then add feature to the current list
212 			 */
213 			if (!featuremap.get(y * ncols + x) && val >= min_eigenvalue) {
214 				featurelist.features[indx].x = x;
215 				featurelist.features[indx].y = y;
216 				featurelist.features[indx].val = val;
217 				// featurelist.features[indx].aff_img = null;
218 				// featurelist.features[indx].aff_img_gradx = null;
219 				// featurelist.features[indx].aff_img_grady = null;
220 				// featurelist.features[indx].aff_x = -1.0f;
221 				// featurelist.features[indx].aff_y = -1.0f;
222 				// featurelist.features[indx].aff_Axx = 1.0f;
223 				// featurelist.features[indx].aff_Ayx = 0.0f;
224 				// featurelist.features[indx].aff_Axy = 0.0f;
225 				// featurelist.features[indx].aff_Ayy = 1.0f;
226 				indx++;
227 
228 				/*
229 				 * Fill in surrounding region of feature map, but make sure that
230 				 * pixels are in-bounds
231 				 */
232 				_fillFeaturemap(x, y, featuremap, mindist, ncols, nrows);
233 			}
234 		}
235 	}
236 
237 	/*********************************************************************
238 	 * _sortPointList
239 	 */
240 	private void _sortPointList(int[][] pointlist)
241 	{
242 		Arrays.sort(pointlist, new Comparator<int[]>() {
243 			@Override
244 			public int compare(int[] o1, int[] o2) {
245 				final int v1 = o1[2];
246 				final int v2 = o2[2];
247 
248 				if (v1 > v2)
249 					return (-1);
250 				else if (v1 < v2)
251 					return (1);
252 				else
253 					return (0);
254 			}
255 		});
256 	}
257 
258 	/*********************************************************************
259 	 * _minEigenvalue
260 	 * 
261 	 * Given the three distinct elements of the symmetric 2x2 matrix [gxx gxy]
262 	 * [gxy gyy], Returns the minimum eigenvalue of the matrix.
263 	 */
264 	private float _minEigenvalue(float gxx, float gxy, float gyy)
265 	{
266 		return (float) ((gxx + gyy - Math.sqrt((gxx - gyy) * (gxx - gyy) + 4 * gxy * gxy)) / 2.0f);
267 	}
268 
269 	/**
270 	 * @throws IOException
271 	 *******************************************************************/
272 	private void _selectGoodFeatures(
273 			FImage img,
274 			SelectionMode mode)
275 	{
276 		final int nrows = img.height, ncols = img.width;
277 		FImage floatimg, gradx, grady;
278 		int window_hw, window_hh;
279 		int[][] pointlist;
280 
281 		final boolean overwriteAllFeatures = (mode == SelectionMode.SELECTING_ALL) ? true : false;
282 		// boolean floatimages_created = false;
283 
284 		/* Check window size (and correct if necessary) */
285 		if (tc.window_width % 2 != 1) {
286 			tc.window_width = tc.window_width + 1;
287 			System.err.format("Tracking context's window width must be odd.  Changing to %d.\n", tc.window_width);
288 		}
289 		if (tc.window_height % 2 != 1) {
290 			tc.window_height = tc.window_height + 1;
291 			System.err.format("Tracking context's window height must be odd.  Changing to %d.\n", tc.window_height);
292 		}
293 		if (tc.window_width < 3) {
294 			tc.window_width = 3;
295 			System.err.format("Tracking context's window width must be at least three.  \nChanging to %d.\n",
296 					tc.window_width);
297 		}
298 		if (tc.window_height < 3) {
299 			tc.window_height = 3;
300 			System.err.format("Tracking context's window height must be at least three.  \nChanging to %d.\n",
301 					tc.window_height);
302 		}
303 		window_hw = tc.window_width / 2;
304 		window_hh = tc.window_height / 2;
305 
306 		/* Create pointlist, which is a simplified version of a featurelist, */
307 		/* for speed. Contains only integer locations and values. */
308 		pointlist = new int[ncols * nrows][3];
309 
310 		/* Create temporary images, etc. */
311 		final PyramidSet ppSet = tc.previousPyramidSet();
312 		if (mode == SelectionMode.REPLACING_SOME &&
313 				tc.sequentialMode && ppSet != null)
314 		{
315 			floatimg = ppSet.imgPyr.img[0];
316 			gradx = ppSet.gradx.img[0];
317 			grady = ppSet.grady.img[0];
318 			assert (gradx != null);
319 			assert (grady != null);
320 		} else {
321 			// floatimages_created = true;
322 			floatimg = new FImage(ncols, nrows);
323 			gradx = new FImage(ncols, nrows);
324 			grady = new FImage(ncols, nrows);
325 			if (tc.smoothBeforeSelecting) {
326 				floatimg = img.process(new FGaussianConvolve(tc.computeSmoothSigma()));
327 			} else {
328 				floatimg = img.clone();
329 			}
330 
331 			/* Compute gradient of image in x and y direction */
332 			tc.computeGradients(floatimg, tc.grad_sigma, gradx, grady);
333 		}
334 
335 		/* Write internal images */
336 		if (tc.writeInternalImages) {
337 			try {
338 				ImageUtilities.write(floatimg, "png", new File("kltimg_sgfrlf.png"));
339 				ImageUtilities.write(gradx, "png", new File("kltimg_sgfrlf_gx.png"));
340 				ImageUtilities.write(grady, "png", new File("kltimg_sgfrlf_gy.png"));
341 			} catch (final IOException e) {
342 
343 			}
344 		}
345 
346 		/*
347 		 * Compute trackability of each image pixel as the minimum of the two
348 		 * eigenvalues of the Z matrix
349 		 */
350 		{
351 			float gx, gy;
352 			float gxx, gxy, gyy;
353 			int xx, yy;
354 			int ptr;
355 			float val;
356 			int limit = 1;
357 			int borderx = tc.borderx; /* Must not touch cols */
358 			int bordery = tc.bordery; /* lost by convolution */
359 			int x, y;
360 
361 			if (borderx < window_hw)
362 				borderx = window_hw;
363 			if (bordery < window_hh)
364 				bordery = window_hh;
365 
366 			/* Find largest value of an int */
367 			limit = Integer.MAX_VALUE / 2 - 1;
368 
369 			/* For most of the pixels in the image, do ... */
370 			ptr = 0;
371 			for (y = bordery; y < nrows - bordery; y += tc.nSkippedPixels + 1)
372 				for (x = borderx; x < ncols - borderx; x += tc.nSkippedPixels + 1) {
373 					if (tc.getTargetArea() != null) {
374 						final Point2d point = new Point2dImpl(x, y);
375 						if (!tc.getTargetArea().isInside(point))
376 							continue;
377 					}
378 					/* Sum the gradients in the surrounding window */
379 					gxx = 0;
380 					gxy = 0;
381 					gyy = 0;
382 					for (yy = y - window_hh; yy <= y + window_hh; yy++)
383 						for (xx = x - window_hw; xx <= x + window_hw; xx++) {
384 							gx = gradx.pixels[yy][xx];
385 							gy = grady.pixels[yy][xx];
386 							gxx += gx * gx;
387 							gxy += gx * gy;
388 							gyy += gy * gy;
389 						}
390 
391 					/*
392 					 * Store the trackability of the pixel as the minimum of the
393 					 * two eigenvalues
394 					 */
395 					pointlist[ptr][0] = x;
396 					pointlist[ptr][1] = y;
397 					val = _minEigenvalue(gxx, gxy, gyy);
398 					if (val > limit) {
399 						System.err
400 								.format("(_KLTSelectGoodFeatures) minimum eigenvalue %f is greater than the capacity of an int; setting to maximum value",
401 										val);
402 						val = limit;
403 					}
404 					pointlist[ptr][2] = (int) val;
405 					++ptr;
406 				}
407 		}
408 
409 		/* Sort the features */
410 		_sortPointList(pointlist);
411 
412 		/* Check tc.mindist */
413 		if (tc.mindist < 0) {
414 			System.err.format(
415 					"(_KLTSelectGoodFeatures) Tracking context field tc.mindist is negative (%d); setting to zero",
416 					tc.mindist);
417 			tc.mindist = 0;
418 		}
419 
420 		/* Enforce minimum distance between features */
421 		_enforceMinimumDistance(
422 				pointlist,
423 				ncols, nrows,
424 				tc.mindist,
425 				tc.min_eigenvalue,
426 				overwriteAllFeatures);
427 	}
428 
429 	/*********************************************************************
430 	 * KLTSelectGoodFeatures
431 	 * 
432 	 * Main routine, visible to the outside. Finds the good features in an
433 	 * image.
434 	 * 
435 	 * INPUTS tc: Contains parameters used in computation (size of image, size
436 	 * of window, min distance b/w features, sigma to compute image gradients, #
437 	 * of features desired).
438 	 * 
439 	 * @param img
440 	 *            Pointer to the data of an image (probably unsigned chars).
441 	 * 
442 	 *            OUTPUTS features: List of features. The member nFeatures is
443 	 *            computed.
444 	 */
445 	public void selectGoodFeatures(FImage img) {
446 		if (isNorm)
447 			img = img.multiply(255f);
448 
449 		if (KLT_verbose >= 1) {
450 			System.err.format("(KLT) Selecting the %d best features from a %d by %d image...  ",
451 					featurelist.features.length, img.width, img.height);
452 		}
453 
454 		_selectGoodFeatures(img, SelectionMode.SELECTING_ALL);
455 
456 		if (KLT_verbose >= 1) {
457 			System.err.format("\n\t%d features found.\n", featurelist.countRemainingFeatures());
458 			if (tc.writeInternalImages)
459 				System.err.format("\tWrote images to 'kltimg_sgfrlf*.pgm'.\n");
460 		}
461 	}
462 
463 	/*********************************************************************
464 	 * KLTReplaceLostFeatures
465 	 * 
466 	 * Main routine, visible to the outside. Replaces the lost features in an
467 	 * image.
468 	 * 
469 	 * INPUTS tc: Contains parameters used in computation (size of image, size
470 	 * of window, min distance b/w features, sigma to compute image gradients, #
471 	 * of features desired).
472 	 * 
473 	 * @param img
474 	 *            Pointer to the data of an image (probably unsigned chars).
475 	 * 
476 	 *            OUTPUTS features: List of features. The member nFeatures is
477 	 *            computed.
478 	 */
479 	public void replaceLostFeatures(FImage img)
480 	{
481 		if (isNorm)
482 			img = img.multiply(255f);
483 
484 		final int nLostFeatures = featurelist.features.length - featurelist.countRemainingFeatures();
485 
486 		if (KLT_verbose >= 1) {
487 			System.err.format("(KLT) Attempting to replace %d features in a %d by %d image...  ", nLostFeatures,
488 					img.width, img.height);
489 		}
490 
491 		/* If there are any lost features, replace them */
492 		if (nLostFeatures > 0)
493 			_selectGoodFeatures(img, SelectionMode.REPLACING_SOME);
494 
495 		if (KLT_verbose >= 1) {
496 			System.err.format("\n\t%d features replaced.\n",
497 					nLostFeatures - featurelist.features.length + featurelist.countRemainingFeatures());
498 			if (tc.writeInternalImages)
499 				System.err.format("\tWrote images to 'kltimg_sgfrlf*.pgm'.\n");
500 		}
501 	}
502 
503 	/*********************************************************************
504 	 * KLTSetVerbosity
505 	 * 
506 	 * @param verbosity
507 	 */
508 	public void setVerbosity(int verbosity)
509 	{
510 		KLT_verbose = verbosity;
511 	}
512 
513 	/*********************************************************************
514 	 * _interpolate
515 	 * 
516 	 * Given a point (x,y) in an image, computes the bilinear interpolated
517 	 * gray-level value of the point in the image.
518 	 */
519 	private float _interpolate(float x, float y, FImage img)
520 	{
521 		final int xt = (int) x; /* coordinates of top-left corner */
522 		final int yt = (int) y;
523 		final float ax = x - xt;
524 		final float ay = y - yt;
525 
526 		final float x0y0 = img.pixels[yt][xt];
527 		final float x1y0 = img.pixels[yt][xt + 1];
528 		final float x0y1 = img.pixels[yt + 1][xt];
529 		final float x1y1 = img.pixels[yt + 1][xt + 1];
530 
531 		return ((1 - ax) * (1 - ay) * x0y0 +
532 				ax * (1 - ay) * x1y0 +
533 				(1 - ax) * ay * x0y1 + ax * ay * x1y1);
534 	}
535 
536 	/*********************************************************************
537 	 * _computeIntensityDifference
538 	 * 
539 	 * Given two images and the window center in both images, aligns the images
540 	 * wrt the window and computes the difference between the two overlaid
541 	 * images.
542 	 */
543 	private void _computeIntensityDifference(
544 			FImage img1, /* images */
545 			FImage img2,
546 			float x1, float y1, /* center of window in 1st img */
547 			float x2, float y2, /* center of window in 2nd img */
548 			int width, int height, /* size of window */
549 			float[] imgdiff) /* output */
550 	{
551 		final int hw = width / 2, hh = height / 2;
552 		float g1, g2;
553 		int i, j;
554 
555 		/* Compute values */
556 		int idx = 0;
557 		for (j = -hh; j <= hh; j++)
558 			for (i = -hw; i <= hw; i++) {
559 				g1 = _interpolate(x1 + i, y1 + j, img1);
560 				g2 = _interpolate(x2 + i, y2 + j, img2);
561 				imgdiff[idx++] = g1 - g2;
562 			}
563 	}
564 
565 	/*********************************************************************
566 	 * _computeGradientSum
567 	 * 
568 	 * Given two gradients and the window center in both images, aligns the
569 	 * gradients wrt the window and computes the sum of the two overlaid
570 	 * gradients.
571 	 */
572 	private void _computeGradientSum(
573 			FImage gradx1, /* gradient images */
574 			FImage grady1,
575 			FImage gradx2,
576 			FImage grady2,
577 			float x1, float y1, /* center of window in 1st img */
578 			float x2, float y2, /* center of window in 2nd img */
579 			int width, int height, /* size of window */
580 			float[] gradx, /* output */
581 			float[] grady) /* " */
582 	{
583 		final int hw = width / 2, hh = height / 2;
584 		float g1, g2;
585 		int i, j;
586 
587 		int gx = 0, gy = 0;
588 		/* Compute values */
589 		for (j = -hh; j <= hh; j++)
590 			for (i = -hw; i <= hw; i++) {
591 				g1 = _interpolate(x1 + i, y1 + j, gradx1);
592 				g2 = _interpolate(x2 + i, y2 + j, gradx2);
593 				// *gradx++ = g1 + g2;
594 				gradx[gx++] = g1 + g2;
595 				g1 = _interpolate(x1 + i, y1 + j, grady1);
596 				g2 = _interpolate(x2 + i, y2 + j, grady2);
597 				// *grady++ = g1 + g2;
598 				grady[gy++] = g1 + g2;
599 			}
600 	}
601 
602 	/*********************************************************************
603 	 * _computeIntensityDifferenceLightingInsensitive
604 	 * 
605 	 * Given two images and the window center in both images, aligns the images
606 	 * wrt the window and computes the difference between the two overlaid
607 	 * images; normalizes for overall gain and bias.
608 	 */
609 	private void _computeIntensityDifferenceLightingInsensitive(
610 			FImage img1, /* images */
611 			FImage img2,
612 			float x1, float y1, /* center of window in 1st img */
613 			float x2, float y2, /* center of window in 2nd img */
614 			int width, int height, /* size of window */
615 			float[] imgdiff) /* output */
616 	{
617 		final int hw = width / 2, hh = height / 2;
618 		float g1, g2, sum1_squared = 0, sum2_squared = 0;
619 		int i, j;
620 
621 		float sum1 = 0, sum2 = 0;
622 		float mean1, mean2, alpha, belta;
623 		/* Compute values */
624 		for (j = -hh; j <= hh; j++)
625 			for (i = -hw; i <= hw; i++) {
626 				g1 = _interpolate(x1 + i, y1 + j, img1);
627 				g2 = _interpolate(x2 + i, y2 + j, img2);
628 				sum1 += g1;
629 				sum2 += g2;
630 				sum1_squared += g1 * g1;
631 				sum2_squared += g2 * g2;
632 			}
633 		mean1 = sum1_squared / (width * height);
634 		mean2 = sum2_squared / (width * height);
635 		alpha = (float) Math.sqrt(mean1 / mean2);
636 		mean1 = sum1 / (width * height);
637 		mean2 = sum2 / (width * height);
638 		belta = mean1 - alpha * mean2;
639 
640 		int id = 0;
641 		for (j = -hh; j <= hh; j++)
642 			for (i = -hw; i <= hw; i++) {
643 				g1 = _interpolate(x1 + i, y1 + j, img1);
644 				g2 = _interpolate(x2 + i, y2 + j, img2);
645 				// *imgdiff++ = g1- g2*alpha-belta;
646 				imgdiff[id++] = g1 - g2 * alpha - belta;
647 			}
648 	}
649 
650 	/*********************************************************************
651 	 * _computeGradientSumLightingInsensitive
652 	 * 
653 	 * Given two gradients and the window center in both images, aligns the
654 	 * gradients wrt the window and computes the sum of the two overlaid
655 	 * gradients; normalizes for overall gain and bias.
656 	 */
657 	private void _computeGradientSumLightingInsensitive(
658 			FImage gradx1, /* gradient images */
659 			FImage grady1,
660 			FImage gradx2,
661 			FImage grady2,
662 			FImage img1, /* images */
663 			FImage img2,
664 
665 			float x1, float y1, /* center of window in 1st img */
666 			float x2, float y2, /* center of window in 2nd img */
667 			int width, int height, /* size of window */
668 			float[] gradx, /* output */
669 			float[] grady) /* " */
670 	{
671 		final int hw = width / 2, hh = height / 2;
672 		float g1, g2, sum1_squared = 0, sum2_squared = 0;
673 		int i, j;
674 
675 		// float sum1 = 0, sum2 = 0;
676 		float mean1, mean2, alpha;
677 		for (j = -hh; j <= hh; j++)
678 			for (i = -hw; i <= hw; i++) {
679 				g1 = _interpolate(x1 + i, y1 + j, img1);
680 				g2 = _interpolate(x2 + i, y2 + j, img2);
681 				sum1_squared += g1;
682 				sum2_squared += g2;
683 			}
684 		mean1 = sum1_squared / (width * height);
685 		mean2 = sum2_squared / (width * height);
686 		alpha = (float) Math.sqrt(mean1 / mean2);
687 
688 		int gx = 0, gy = 0;
689 		/* Compute values */
690 		for (j = -hh; j <= hh; j++)
691 			for (i = -hw; i <= hw; i++) {
692 				g1 = _interpolate(x1 + i, y1 + j, gradx1);
693 				g2 = _interpolate(x2 + i, y2 + j, gradx2);
694 				// *gradx++ = g1 + g2*alpha;
695 				gradx[gx++] = g1 + g2 * alpha;
696 				g1 = _interpolate(x1 + i, y1 + j, grady1);
697 				g2 = _interpolate(x2 + i, y2 + j, grady2);
698 				// *grady++ = g1+ g2*alpha;
699 				grady[gy++] = g1 + g2 * alpha;
700 			}
701 	}
702 
703 	/*********************************************************************
704 	 * _compute2by2GradientMatrix
705 	 * 
706 	 */
707 	private float[] _compute2by2GradientMatrix(
708 			float[] gradx,
709 			float[] grady,
710 			int width, /* size of window */
711 			int height
712 			)
713 
714 	{
715 		float gx, gy;
716 		int i;
717 
718 		float gxx; /* return values */
719 		float gxy;
720 		float gyy;
721 
722 		/* Compute values */
723 		gxx = 0.0f;
724 		gxy = 0.0f;
725 		gyy = 0.0f;
726 		for (i = 0; i < width * height; i++) {
727 			// gx = *gradx++;
728 			gx = gradx[i];
729 			// gy = *grady++;
730 			gy = grady[i];
731 			gxx += gx * gx;
732 			gxy += gx * gy;
733 			gyy += gy * gy;
734 		}
735 
736 		return new float[] { gxx, gxy, gyy };
737 	}
738 
739 	/*********************************************************************
740 	 * _compute2by1ErrorVector
741 	 * 
742 	 */
743 
744 	private float[] _compute2by1ErrorVector(
745 			float[] imgdiff,
746 			float[] gradx,
747 			float[] grady,
748 			int width, /* size of window */
749 			int height,
750 			float step_factor /*
751 							 * 2.0 comes from equations, 1.0 seems to avoid
752 							 * overshooting
753 							 */
754 			)
755 	{
756 		float diff;
757 		int i;
758 
759 		float ex, ey;
760 
761 		/* Compute values */
762 		ex = 0;
763 		ey = 0;
764 		for (i = 0; i < width * height; i++) {
765 			diff = imgdiff[i];
766 			ex += diff * gradx[i];
767 			ey += diff * grady[i];
768 		}
769 		ex *= step_factor;
770 		ey *= step_factor;
771 
772 		return new float[] { ex, ey };
773 	}
774 
775 	/*********************************************************************
776 	 * _solveEquation
777 	 * 
778 	 * Solves the 2x2 matrix equation [gxx gxy] [dx] = [ex] [gxy gyy] [dy] =
779 	 * [ey] for dx and dy.
780 	 * 
781 	 * Returns KLT_TRACKED on success and KLT_SMALL_DET on failure
782 	 */
783 	private int _solveEquation(
784 			float gxx, float gxy, float gyy,
785 			float ex, float ey,
786 			float small,
787 			float[] output)
788 	{
789 		final float det = gxx * gyy - gxy * gxy;
790 
791 		if (det < small)
792 			return KLT_SMALL_DET;
793 
794 		output[0] = (gyy * ex - gxy * ey) / det; // dx
795 		output[1] = (gxx * ey - gxy * ex) / det; // dy
796 		return KLT_TRACKED;
797 	}
798 
799 	/*********************************************************************
800 	 * _sumAbsFloatWindow
801 	 */
802 	private float _sumAbsFloatWindow(
803 			float[] fw,
804 			int width,
805 			int height)
806 	{
807 		float sum = 0.0f;
808 
809 		for (int i = 0; i < height * width; i++)
810 			sum += Math.abs(fw[i]);
811 
812 		return sum;
813 	}
814 
815 	/*********************************************************************
816 	 * _trackFeature
817 	 * 
818 	 * Tracks a feature point from one image to the next.
819 	 * 
820 	 * RETURNS KLT_SMALL_DET if feature is lost, KLT_MAX_ITERATIONS if tracking
821 	 * stopped because iterations timed out, KLT_TRACKED otherwise.
822 	 */
823 	private int _trackFeature(
824 			float x1, /* location of window in first image */
825 			float y1,
826 			float[] xy2, /* starting location of search in second image */
827 			FImage img1,
828 			FImage gradx1,
829 			FImage grady1,
830 			FImage img2,
831 			FImage gradx2,
832 			FImage grady2,
833 			int width, /* size of window */
834 			int height,
835 			float step_factor, /*
836 								 * 2.0 comes from equations, 1.0 seems to avoid
837 								 * overshooting
838 								 */
839 			int max_iterations,
840 			float small, /* determinant threshold for declaring KLT_SMALL_DET */
841 			float th, /* displacement threshold for stopping */
842 			float max_residue, /*
843 								 * residue threshold for declaring
844 								 * KLT_LARGE_RESIDUE
845 								 */
846 			boolean lighting_insensitive) /*
847 										 * whether to normalize for gain and
848 										 * bias
849 										 */
850 	{
851 		float[] imgdiff, gradx, grady;
852 		float gxx, gxy, gyy, ex, ey, dx, dy;
853 		int iteration = 0;
854 		int status;
855 		final int hw = width / 2;
856 		final int hh = height / 2;
857 		final int nc = img1.width;
858 		final int nr = img1.height;
859 		final float one_plus_eps = 1.001f; /* To prevent rounding errors */
860 
861 		/* Allocate memory for windows */
862 		imgdiff = new float[height * width];
863 		gradx = new float[height * width];
864 		grady = new float[height * width];
865 
866 		/* Iteratively update the window position */
867 		do {
868 
869 			/* If out of bounds, exit loop */
870 			if (x1 - hw < 0.0f || nc - (x1 + hw) < one_plus_eps ||
871 					xy2[0] - hw < 0.0f || nc - (xy2[0] + hw) < one_plus_eps ||
872 					y1 - hh < 0.0f || nr - (y1 + hh) < one_plus_eps ||
873 					xy2[1] - hh < 0.0f || nr - (xy2[1] + hh) < one_plus_eps)
874 			{
875 				status = KLT_OOB;
876 				break;
877 			}
878 
879 			/* Compute gradient and difference windows */
880 			if (lighting_insensitive) {
881 				_computeIntensityDifferenceLightingInsensitive(img1, img2, x1, y1, xy2[0], xy2[1], width, height, imgdiff);
882 				_computeGradientSumLightingInsensitive(gradx1, grady1, gradx2, grady2, img1, img2, x1, y1, xy2[0],
883 						xy2[1], width, height, gradx, grady);
884 			} else {
885 				_computeIntensityDifference(img1, img2, x1, y1, xy2[0], xy2[1], width, height, imgdiff);
886 				_computeGradientSum(gradx1, grady1, gradx2, grady2, x1, y1, xy2[0], xy2[1], width, height, gradx, grady);
887 			}
888 
889 			/* Use these windows to construct matrices */
890 			float[] tmp = _compute2by2GradientMatrix(gradx, grady, width, height);
891 			gxx = tmp[0];
892 			gxy = tmp[1];
893 			gyy = tmp[2];
894 
895 			tmp = _compute2by1ErrorVector(imgdiff, gradx, grady, width, height, step_factor);
896 			ex = tmp[0];
897 			ey = tmp[1];
898 
899 			/* Using matrices, solve equation for new displacement */
900 			tmp = new float[2];
901 			status = _solveEquation(gxx, gxy, gyy, ex, ey, small, tmp);
902 			dx = tmp[0];
903 			dy = tmp[1];
904 			if (status == KLT_SMALL_DET)
905 				break;
906 
907 			xy2[0] += dx;
908 			xy2[1] += dy;
909 			iteration++;
910 
911 		} while ((Math.abs(dx) >= th || Math.abs(dy) >= th) && iteration < max_iterations);
912 
913 		/* Check whether window is out of bounds */
914 		if (xy2[0] - hw < 0.0f || nc - (xy2[0] + hw) < one_plus_eps ||
915 				xy2[1] - hh < 0.0f || nr - (xy2[1] + hh) < one_plus_eps)
916 			status = KLT_OOB;
917 
918 		/* Check whether residue is too large */
919 		if (status == KLT_TRACKED) {
920 			if (lighting_insensitive)
921 				_computeIntensityDifferenceLightingInsensitive(img1, img2, x1, y1, xy2[0], xy2[1], width, height, imgdiff);
922 			else
923 				_computeIntensityDifference(img1, img2, x1, y1, xy2[0], xy2[1], width, height, imgdiff);
924 			if (_sumAbsFloatWindow(imgdiff, width, height) / (width * height) > max_residue)
925 				status = KLT_LARGE_RESIDUE;
926 		}
927 
928 		/* Return appropriate value */
929 		if (status == KLT_SMALL_DET)
930 			return KLT_SMALL_DET;
931 		else if (status == KLT_OOB)
932 			return KLT_OOB;
933 		else if (status == KLT_LARGE_RESIDUE)
934 			return KLT_LARGE_RESIDUE;
935 		else if (iteration >= max_iterations)
936 			return KLT_MAX_ITERATIONS;
937 		else
938 			return KLT_TRACKED;
939 	}
940 
941 	/*********************************************************************/
942 
943 	private boolean _outOfBounds(
944 			float x,
945 			float y,
946 			int ncols,
947 			int nrows,
948 			int borderx,
949 			int bordery)
950 	{
951 		return (x < borderx || x > ncols - 1 - borderx ||
952 				y < bordery || y > nrows - 1 - bordery);
953 	}
954 
955 	// /**********************************************************************
956 	// * CONSISTENCY CHECK OF FEATURES BY AFFINE MAPPING (BEGIN)
957 	// *
958 	// * Created by: Thorsten Thormaehlen (University of Hannover) June 2004
959 	// * thormae@tnt.uni-hannover.de
960 	// *
961 	// * Permission is granted to any individual or institution to use, copy,
962 	// modify,
963 	// * and distribute this part of the software, provided that this complete
964 	// authorship
965 	// * and permission notice is maintained, intact, in all copies.
966 	// *
967 	// * This software is provided "as is" without express or implied warranty.
968 	// *
969 	// *
970 	// * The following static functions are helpers for the affine mapping.
971 	// * They all start with "_am".
972 	// * There are also small changes in other files for the
973 	// * affine mapping these are all marked by "for affine mapping"
974 	// *
975 	// * Thanks to Kevin Koeser (koeser@mip.informatik.uni-kiel.de) for fixing a
976 	// bug
977 	// */
978 	//
979 	// #define SWAP_ME(X,Y) {temp=(X);(X)=(Y);(Y)=temp;}
980 	//
981 	// static float **_am_matrix(long nr, long nc)
982 	// {
983 	// float **m;
984 	// int a;
985 	// m = (float **) malloc((size_t)(nr*sizeof(float*)));
986 	// m[0] = (float *) malloc((size_t)((nr*nc)*sizeof(float)));
987 	// for(a = 1; a < nr; a++) m[a] = m[a-1]+nc;
988 	// return m;
989 	// }
990 	//
991 	// static void _am_free_matrix(float **m)
992 	// {
993 	// free(m[0]);
994 	// free(m);
995 	// }
996 	//
997 	//
998 	// static int _am_gauss_jordan_elimination(float **a, int n, float **b, int
999 	// m)
1000 	// {
1001 	// /* re-implemented from Numerical Recipes in C */
1002 	// int *indxc,*indxr,*ipiv;
1003 	// int i,j,k,l,ll;
1004 	// float big,dum,pivinv,temp;
1005 	// int col = 0;
1006 	// int row = 0;
1007 	//
1008 	// indxc=(int *)malloc((size_t) (n*sizeof(int)));
1009 	// indxr=(int *)malloc((size_t) (n*sizeof(int)));
1010 	// ipiv=(int *)malloc((size_t) (n*sizeof(int)));
1011 	// for (j=0;j<n;j++) ipiv[j]=0;
1012 	// for (i=0;i<n;i++) {
1013 	// big=0.0;
1014 	// for (j=0;j<n;j++)
1015 	// if (ipiv[j] != 1)
1016 	// for (k=0;k<n;k++) {
1017 	// if (ipiv[k] == 0) {
1018 	// if (fabs(a[j][k]) >= big) {
1019 	// big= (float) fabs(a[j][k]);
1020 	// row=j;
1021 	// col=k;
1022 	// }
1023 	// } else if (ipiv[k] > 1) return KLT_SMALL_DET;
1024 	// }
1025 	// ++(ipiv[col]);
1026 	// if (row != col) {
1027 	// for (l=0;l<n;l++) SWAP_ME(a[row][l],a[col][l])
1028 	// for (l=0;l<m;l++) SWAP_ME(b[row][l],b[col][l])
1029 	// }
1030 	// indxr[i]=row;
1031 	// indxc[i]=col;
1032 	// if (a[col][col] == 0.0) return KLT_SMALL_DET;
1033 	// pivinv=1.0f/a[col][col];
1034 	// a[col][col]=1.0;
1035 	// for (l=0;l<n;l++) a[col][l] *= pivinv;
1036 	// for (l=0;l<m;l++) b[col][l] *= pivinv;
1037 	// for (ll=0;ll<n;ll++)
1038 	// if (ll != col) {
1039 	// dum=a[ll][col];
1040 	// a[ll][col]=0.0;
1041 	// for (l=0;l<n;l++) a[ll][l] -= a[col][l]*dum;
1042 	// for (l=0;l<m;l++) b[ll][l] -= b[col][l]*dum;
1043 	// }
1044 	// }
1045 	// for (l=n-1;l>=0;l--) {
1046 	// if (indxr[l] != indxc[l])
1047 	// for (k=0;k<n;k++)
1048 	// SWAP_ME(a[k][indxr[l]],a[k][indxc[l]]);
1049 	// }
1050 	// free(ipiv);
1051 	// free(indxr);
1052 	// free(indxc);
1053 	//
1054 	// return KLT_TRACKED;
1055 	// }
1056 	//
1057 	// /*********************************************************************
1058 	// * _am_getGradientWinAffine
1059 	// *
1060 	// * aligns the gradients with the affine transformed window
1061 	// */
1062 	//
1063 	// static void _am_getGradientWinAffine(
1064 	// FImage in_gradx,
1065 	// FImage in_grady,
1066 	// float x, float y, /* center of window*/
1067 	// float Axx, float Ayx , float Axy, float Ayy, /* affine mapping */
1068 	// int width, int height, /* size of window */
1069 	// _FloatWindow out_gradx, /* output */
1070 	// _FloatWindow out_grady) /* output */
1071 	// {
1072 	// int hw = width/2, hh = height/2;
1073 	// int i, j;
1074 	// float mi, mj;
1075 	//
1076 	// /* Compute values */
1077 	// for (j = -hh ; j <= hh ; j++)
1078 	// for (i = -hw ; i <= hw ; i++) {
1079 	// mi = Axx * i + Axy * j;
1080 	// mj = Ayx * i + Ayy * j;
1081 	// *out_gradx++ = _interpolate(x+mi, y+mj, in_gradx);
1082 	// *out_grady++ = _interpolate(x+mi, y+mj, in_grady);
1083 	// }
1084 	//
1085 	// }
1086 	//
1087 	// /*********************************************************************
1088 	// * _computeAffineMappedImage
1089 	// * used only for DEBUG output
1090 	// *
1091 	// */
1092 	//
1093 	// static void _am_computeAffineMappedImage(
1094 	// FImage img, /* images */
1095 	// float x, float y, /* center of window */
1096 	// float Axx, float Ayx , float Axy, float Ayy, /* affine mapping */
1097 	// int width, int height, /* size of window */
1098 	// _FloatWindow imgdiff) /* output */
1099 	// {
1100 	// int hw = width/2, hh = height/2;
1101 	// int i, j;
1102 	// float mi, mj;
1103 	//
1104 	// /* Compute values */
1105 	// for (j = -hh ; j <= hh ; j++)
1106 	// for (i = -hw ; i <= hw ; i++) {
1107 	// mi = Axx * i + Axy * j;
1108 	// mj = Ayx * i + Ayy * j;
1109 	// *imgdiff++ = _interpolate(x+mi, y+mj, img);
1110 	// }
1111 	// }
1112 	//
1113 	//
1114 	// /*********************************************************************
1115 	// * _getSubFloatImage
1116 	// */
1117 	//
1118 	// static void _am_getSubFloatImage(
1119 	// FImage img, /* image */
1120 	// float x, float y, /* center of window */
1121 	// FImage window) /* output */
1122 	// {
1123 	// int hw = window.ncols/2, hh = window.nrows/2;
1124 	// int x0 = (int) x;
1125 	// int y0 = (int) y;
1126 	// float * windata = window.data;
1127 	// int offset;
1128 	// int i, j;
1129 	//
1130 	// assert(x0 - hw >= 0);
1131 	// assert(y0 - hh >= 0);
1132 	// assert(x0 + hw <= img.ncols);
1133 	// assert(y0 + hh <= img.nrows);
1134 	//
1135 	// /* copy values */
1136 	// for (j = -hh ; j <= hh ; j++)
1137 	// for (i = -hw ; i <= hw ; i++) {
1138 	// offset = (j+y0)*img.ncols + (i+x0);
1139 	// *windata++ = *(img.data+offset);
1140 	// }
1141 	// }
1142 	//
1143 	// /*********************************************************************
1144 	// * _am_computeIntensityDifferenceAffine
1145 	// *
1146 	// * Given two images and the window center in both images,
1147 	// * aligns the images with the window and computes the difference
1148 	// * between the two overlaid images using the affine mapping.
1149 	// * A = [ Axx Axy]
1150 	// * [ Ayx Ayy]
1151 	// */
1152 	//
1153 	// static void _am_computeIntensityDifferenceAffine(
1154 	// FImage img1, /* images */
1155 	// FImage img2,
1156 	// float x1, float y1, /* center of window in 1st img */
1157 	// float x2, float y2, /* center of window in 2nd img */
1158 	// float Axx, float Ayx , float Axy, float Ayy, /* affine mapping */
1159 	// int width, int height, /* size of window */
1160 	// _FloatWindow imgdiff) /* output */
1161 	// {
1162 	// int hw = width/2, hh = height/2;
1163 	// float g1, g2;
1164 	// int i, j;
1165 	// float mi, mj;
1166 	//
1167 	// /* Compute values */
1168 	// for (j = -hh ; j <= hh ; j++)
1169 	// for (i = -hw ; i <= hw ; i++) {
1170 	// g1 = _interpolate(x1+i, y1+j, img1);
1171 	// mi = Axx * i + Axy * j;
1172 	// mj = Ayx * i + Ayy * j;
1173 	// g2 = _interpolate(x2+mi, y2+mj, img2);
1174 	// *imgdiff++ = g1 - g2;
1175 	// }
1176 	// }
1177 	//
1178 	// /*********************************************************************
1179 	// * _am_compute6by6GradientMatrix
1180 	// *
1181 	// */
1182 	//
1183 	// static void _am_compute6by6GradientMatrix(
1184 	// _FloatWindow gradx,
1185 	// _FloatWindow grady,
1186 	// int width, /* size of window */
1187 	// int height,
1188 	// float **T) /* return values */
1189 	// {
1190 	// int hw = width/2, hh = height/2;
1191 	// int i, j;
1192 	// float gx, gy, gxx, gxy, gyy, x, y, xx, xy, yy;
1193 	//
1194 	//
1195 	// /* Set values to zero */
1196 	// for (j = 0 ; j < 6 ; j++) {
1197 	// for (i = j ; i < 6 ; i++) {
1198 	// T[j][i] = 0.0;
1199 	// }
1200 	// }
1201 	//
1202 	// for (j = -hh ; j <= hh ; j++) {
1203 	// for (i = -hw ; i <= hw ; i++) {
1204 	// gx = *gradx++;
1205 	// gy = *grady++;
1206 	// gxx = gx * gx;
1207 	// gxy = gx * gy;
1208 	// gyy = gy * gy;
1209 	// x = (float) i;
1210 	// y = (float) j;
1211 	// xx = x * x;
1212 	// xy = x * y;
1213 	// yy = y * y;
1214 	//
1215 	// T[0][0] += xx * gxx;
1216 	// T[0][1] += xx * gxy;
1217 	// T[0][2] += xy * gxx;
1218 	// T[0][3] += xy * gxy;
1219 	// T[0][4] += x * gxx;
1220 	// T[0][5] += x * gxy;
1221 	//
1222 	// T[1][1] += xx * gyy;
1223 	// T[1][2] += xy * gxy;
1224 	// T[1][3] += xy * gyy;
1225 	// T[1][4] += x * gxy;
1226 	// T[1][5] += x * gyy;
1227 	//
1228 	// T[2][2] += yy * gxx;
1229 	// T[2][3] += yy * gxy;
1230 	// T[2][4] += y * gxx;
1231 	// T[2][5] += y * gxy;
1232 	//
1233 	// T[3][3] += yy * gyy;
1234 	// T[3][4] += y * gxy;
1235 	// T[3][5] += y * gyy;
1236 	//
1237 	// T[4][4] += gxx;
1238 	// T[4][5] += gxy;
1239 	//
1240 	// T[5][5] += gyy;
1241 	// }
1242 	// }
1243 	//
1244 	// for (j = 0 ; j < 5 ; j++) {
1245 	// for (i = j+1 ; i < 6 ; i++) {
1246 	// T[i][j] = T[j][i];
1247 	// }
1248 	// }
1249 	//
1250 	// }
1251 	//
1252 	//
1253 	//
1254 	// /*********************************************************************
1255 	// * _am_compute6by1ErrorVector
1256 	// *
1257 	// */
1258 	//
1259 	// static void _am_compute6by1ErrorVector(
1260 	// _FloatWindow imgdiff,
1261 	// _FloatWindow gradx,
1262 	// _FloatWindow grady,
1263 	// int width, /* size of window */
1264 	// int height,
1265 	// float **e) /* return values */
1266 	// {
1267 	// int hw = width/2, hh = height/2;
1268 	// int i, j;
1269 	// float diff, diffgradx, diffgrady;
1270 	//
1271 	// /* Set values to zero */
1272 	// for(i = 0; i < 6; i++) e[i][0] = 0.0;
1273 	//
1274 	// /* Compute values */
1275 	// for (j = -hh ; j <= hh ; j++) {
1276 	// for (i = -hw ; i <= hw ; i++) {
1277 	// diff = *imgdiff++;
1278 	// diffgradx = diff * (*gradx++);
1279 	// diffgrady = diff * (*grady++);
1280 	// e[0][0] += diffgradx * i;
1281 	// e[1][0] += diffgrady * i;
1282 	// e[2][0] += diffgradx * j;
1283 	// e[3][0] += diffgrady * j;
1284 	// e[4][0] += diffgradx;
1285 	// e[5][0] += diffgrady;
1286 	// }
1287 	// }
1288 	//
1289 	// for(i = 0; i < 6; i++) e[i][0] *= 0.5;
1290 	//
1291 	// }
1292 	//
1293 	//
1294 	// /*********************************************************************
1295 	// * _am_compute4by4GradientMatrix
1296 	// *
1297 	// */
1298 	//
1299 	// static void _am_compute4by4GradientMatrix(
1300 	// _FloatWindow gradx,
1301 	// _FloatWindow grady,
1302 	// int width, /* size of window */
1303 	// int height,
1304 	// float **T) /* return values */
1305 	// {
1306 	// int hw = width/2, hh = height/2;
1307 	// int i, j;
1308 	// float gx, gy, x, y;
1309 	//
1310 	//
1311 	// /* Set values to zero */
1312 	// for (j = 0 ; j < 4 ; j++) {
1313 	// for (i = 0 ; i < 4 ; i++) {
1314 	// T[j][i] = 0.0;
1315 	// }
1316 	// }
1317 	//
1318 	// for (j = -hh ; j <= hh ; j++) {
1319 	// for (i = -hw ; i <= hw ; i++) {
1320 	// gx = *gradx++;
1321 	// gy = *grady++;
1322 	// x = (float) i;
1323 	// y = (float) j;
1324 	// T[0][0] += (x*gx+y*gy) * (x*gx+y*gy);
1325 	// T[0][1] += (x*gx+y*gy)*(x*gy-y*gx);
1326 	// T[0][2] += (x*gx+y*gy)*gx;
1327 	// T[0][3] += (x*gx+y*gy)*gy;
1328 	//
1329 	// T[1][1] += (x*gy-y*gx) * (x*gy-y*gx);
1330 	// T[1][2] += (x*gy-y*gx)*gx;
1331 	// T[1][3] += (x*gy-y*gx)*gy;
1332 	//
1333 	// T[2][2] += gx*gx;
1334 	// T[2][3] += gx*gy;
1335 	//
1336 	// T[3][3] += gy*gy;
1337 	// }
1338 	// }
1339 	//
1340 	// for (j = 0 ; j < 3 ; j++) {
1341 	// for (i = j+1 ; i < 4 ; i++) {
1342 	// T[i][j] = T[j][i];
1343 	// }
1344 	// }
1345 	//
1346 	// }
1347 	//
1348 	// /*********************************************************************
1349 	// * _am_compute4by1ErrorVector
1350 	// *
1351 	// */
1352 	//
1353 	// static void _am_compute4by1ErrorVector(
1354 	// _FloatWindow imgdiff,
1355 	// _FloatWindow gradx,
1356 	// _FloatWindow grady,
1357 	// int width, /* size of window */
1358 	// int height,
1359 	// float **e) /* return values */
1360 	// {
1361 	// int hw = width/2, hh = height/2;
1362 	// int i, j;
1363 	// float diff, diffgradx, diffgrady;
1364 	//
1365 	// /* Set values to zero */
1366 	// for(i = 0; i < 4; i++) e[i][0] = 0.0;
1367 	//
1368 	// /* Compute values */
1369 	// for (j = -hh ; j <= hh ; j++) {
1370 	// for (i = -hw ; i <= hw ; i++) {
1371 	// diff = *imgdiff++;
1372 	// diffgradx = diff * (*gradx++);
1373 	// diffgrady = diff * (*grady++);
1374 	// e[0][0] += diffgradx * i + diffgrady * j;
1375 	// e[1][0] += diffgrady * i - diffgradx * j;
1376 	// e[2][0] += diffgradx;
1377 	// e[3][0] += diffgrady;
1378 	// }
1379 	// }
1380 	//
1381 	// for(i = 0; i < 4; i++) e[i][0] *= 0.5;
1382 	//
1383 	// }
1384 	//
1385 	//
1386 	//
1387 	// /*********************************************************************
1388 	// * _am_trackFeatureAffine
1389 	// *
1390 	// * Tracks a feature point from the image of first occurrence to the actual
1391 	// image.
1392 	// *
1393 	// * RETURNS
1394 	// * KLT_SMALL_DET or KLT_LARGE_RESIDUE or KLT_OOB if feature is lost,
1395 	// * KLT_TRACKED otherwise.
1396 	// */
1397 	//
1398 	// /* if you enalbe the DEBUG_AFFINE_MAPPING make sure you have created a
1399 	// directory "./debug" */
1400 	// /* #define DEBUG_AFFINE_MAPPING */
1401 	//
1402 	// #ifdef DEBUG_AFFINE_MAPPING
1403 	// static int counter = 0;
1404 	// static int glob_index = 0;
1405 	// #endif
1406 	//
1407 	// static int _am_trackFeatureAffine(
1408 	// float x1, /* location of window in first image */
1409 	// float y1,
1410 	// float *x2, /* starting location of search in second image */
1411 	// float *y2,
1412 	// FImage img1,
1413 	// FImage gradx1,
1414 	// FImage grady1,
1415 	// FImage img2,
1416 	// FImage gradx2,
1417 	// FImage grady2,
1418 	// int width, /* size of window */
1419 	// int height,
1420 	// float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid
1421 	// overshooting */
1422 	// int max_iterations,
1423 	// float small, /* determinant threshold for declaring KLT_SMALL_DET */
1424 	// float th, /* displacement threshold for stopping */
1425 	// float th_aff,
1426 	// float max_residue, /* residue threshold for declaring KLT_LARGE_RESIDUE
1427 	// */
1428 	// int lighting_insensitive, /* whether to normalize for gain and bias */
1429 	// int affine_map, /* whether to evaluates the consistency of features with
1430 	// affine mapping */
1431 	// float mdd, /* difference between the displacements */
1432 	// float *Axx, float *Ayx,
1433 	// float *Axy, float *Ayy) /* used affine mapping */
1434 	// {
1435 	//
1436 	//
1437 	// _FloatWindow imgdiff, gradx, grady;
1438 	// float gxx, gxy, gyy, ex, ey, dx, dy;
1439 	// int iteration = 0;
1440 	// int status = 0;
1441 	// int hw = width/2;
1442 	// int hh = height/2;
1443 	// int nc1 = img1.ncols;
1444 	// int nr1 = img1.nrows;
1445 	// int nc2 = img2.ncols;
1446 	// int nr2 = img2.nrows;
1447 	// float **a;
1448 	// float **T;
1449 	// float one_plus_eps = 1.001f; /* To prevent rounding errors */
1450 	// float old_x2 = *x2;
1451 	// float old_y2 = *y2;
1452 	// boolean convergence = false;
1453 	//
1454 	// #ifdef DEBUG_AFFINE_MAPPING
1455 	// char fname[80];
1456 	// FImage aff_diff_win = _KLTCreateFloatImage(width,height);
1457 	// printf("starting location x2=%f y2=%f\n", *x2, *y2);
1458 	// #endif
1459 	//
1460 	// /* Allocate memory for windows */
1461 	// imgdiff = new float[height * width];
1462 	// gradx = new float[height * width];
1463 	// grady = new float[height * width];
1464 	// T = _am_matrix(6,6);
1465 	// a = _am_matrix(6,1);
1466 	//
1467 	// /* Iteratively update the window position */
1468 	// do {
1469 	// if(!affine_map) {
1470 	// /* pure translation tracker */
1471 	//
1472 	// /* If out of bounds, exit loop */
1473 	// if ( x1-hw < 0.0f || nc1-( x1+hw) < one_plus_eps ||
1474 	// *x2-hw < 0.0f || nc2-(*x2+hw) < one_plus_eps ||
1475 	// y1-hh < 0.0f || nr1-( y1+hh) < one_plus_eps ||
1476 	// *y2-hh < 0.0f || nr2-(*y2+hh) < one_plus_eps) {
1477 	// status = KLT_OOB;
1478 	// break;
1479 	// }
1480 	//
1481 	// /* Compute gradient and difference windows */
1482 	// if (lighting_insensitive) {
1483 	// _computeIntensityDifferenceLightingInsensitive(img1, img2, x1, y1, *x2,
1484 	// *y2,
1485 	// width, height, imgdiff);
1486 	// _computeGradientSumLightingInsensitive(gradx1, grady1, gradx2, grady2,
1487 	// img1, img2, x1, y1, *x2, *y2, width, height, gradx, grady);
1488 	// } else {
1489 	// _computeIntensityDifference(img1, img2, x1, y1, *x2, *y2,
1490 	// width, height, imgdiff);
1491 	// _computeGradientSum(gradx1, grady1, gradx2, grady2,
1492 	// x1, y1, *x2, *y2, width, height, gradx, grady);
1493 	// }
1494 	//
1495 	// #ifdef DEBUG_AFFINE_MAPPING
1496 	// aff_diff_win.data = imgdiff;
1497 	// fname = String.format("./debug/kltimg_trans_diff_win%03d.%03d.pgm",
1498 	// glob_index, counter);
1499 	// printf("%s\n", fname);
1500 	// _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0);
1501 	// printf("iter = %d translation tracker res: %f\n", iteration,
1502 	// _sumAbsFloatWindow(imgdiff, width, height)/(width*height));
1503 	// #endif
1504 	//
1505 	// /* Use these windows to construct matrices */
1506 	// _compute2by2GradientMatrix(gradx, grady, width, height,
1507 	// &gxx, &gxy, &gyy);
1508 	// _compute2by1ErrorVector(imgdiff, gradx, grady, width, height,
1509 	// step_factor,
1510 	// &ex, &ey);
1511 	//
1512 	// /* Using matrices, solve equation for new displacement */
1513 	// status = _solveEquation(gxx, gxy, gyy, ex, ey, small, &dx, &dy);
1514 	//
1515 	// convergence = (fabs(dx) < th && fabs(dy) < th);
1516 	//
1517 	// *x2 += dx;
1518 	// *y2 += dy;
1519 	//
1520 	// }else{
1521 	// /* affine tracker */
1522 	//
1523 	// float ul_x = *Axx * (-hw) + *Axy * hh + *x2; /* upper left corner */
1524 	// float ul_y = *Ayx * (-hw) + *Ayy * hh + *y2;
1525 	// float ll_x = *Axx * (-hw) + *Axy * (-hh) + *x2; /* lower left corner */
1526 	// float ll_y = *Ayx * (-hw) + *Ayy * (-hh) + *y2;
1527 	// float ur_x = *Axx * hw + *Axy * hh + *x2; /* upper right corner */
1528 	// float ur_y = *Ayx * hw + *Ayy * hh + *y2;
1529 	// float lr_x = *Axx * hw + *Axy * (-hh) + *x2; /* lower right corner */
1530 	// float lr_y = *Ayx * hw + *Ayy * (-hh) + *y2;
1531 	//
1532 	// /* If out of bounds, exit loop */
1533 	// if ( x1-hw < 0.0f || nc1-(x1+hw) < one_plus_eps ||
1534 	// y1-hh < 0.0f || nr1-(y1+hh) < one_plus_eps ||
1535 	// ul_x < 0.0f || nc2-(ul_x ) < one_plus_eps ||
1536 	// ll_x < 0.0f || nc2-(ll_x ) < one_plus_eps ||
1537 	// ur_x < 0.0f || nc2-(ur_x ) < one_plus_eps ||
1538 	// lr_x < 0.0f || nc2-(lr_x ) < one_plus_eps ||
1539 	// ul_y < 0.0f || nr2-(ul_y ) < one_plus_eps ||
1540 	// ll_y < 0.0f || nr2-(ll_y ) < one_plus_eps ||
1541 	// ur_y < 0.0f || nr2-(ur_y ) < one_plus_eps ||
1542 	// lr_y < 0.0f || nr2-(lr_y ) < one_plus_eps) {
1543 	// status = KLT_OOB;
1544 	// break;
1545 	// }
1546 	//
1547 	// #ifdef DEBUG_AFFINE_MAPPING
1548 	// counter++;
1549 	// _am_computeAffineMappedImage(img1, x1, y1, 1.0, 0.0 , 0.0, 1.0, width,
1550 	// height, imgdiff);
1551 	// aff_diff_win.data = imgdiff;
1552 	// fname = String.format("./debug/kltimg_aff_diff_win%03d.%03d_1.pgm",
1553 	// glob_index, counter);
1554 	// printf("%s\n", fname);
1555 	// _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0);
1556 	//
1557 	// _am_computeAffineMappedImage(img2, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy,
1558 	// width, height, imgdiff);
1559 	// aff_diff_win.data = imgdiff;
1560 	// fname = String.format("./debug/kltimg_aff_diff_win%03d.%03d_2.pgm",
1561 	// glob_index, counter);
1562 	// printf("%s\n", fname);
1563 	// _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0);
1564 	// #endif
1565 	//
1566 	// _am_computeIntensityDifferenceAffine(img1, img2, x1, y1, *x2, *y2, *Axx,
1567 	// *Ayx , *Axy, *Ayy,
1568 	// width, height, imgdiff);
1569 	// #ifdef DEBUG_AFFINE_MAPPING
1570 	// aff_diff_win.data = imgdiff;
1571 	// fname = String.format("./debug/kltimg_aff_diff_win%03d.%03d_3.pgm",
1572 	// glob_index,counter);
1573 	// printf("%s\n", fname);
1574 	// _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0);
1575 	//
1576 	// printf("iter = %d affine tracker res: %f\n", iteration,
1577 	// _sumAbsFloatWindow(imgdiff, width, height)/(width*height));
1578 	// #endif
1579 	//
1580 	// _am_getGradientWinAffine(gradx2, grady2, *x2, *y2, *Axx, *Ayx , *Axy,
1581 	// *Ayy,
1582 	// width, height, gradx, grady);
1583 	//
1584 	// switch(affine_map){
1585 	// case 1:
1586 	// _am_compute4by1ErrorVector(imgdiff, gradx, grady, width, height, a);
1587 	// _am_compute4by4GradientMatrix(gradx, grady, width, height, T);
1588 	//
1589 	// status = _am_gauss_jordan_elimination(T,4,a,1);
1590 	//
1591 	// *Axx += a[0][0];
1592 	// *Ayx += a[1][0];
1593 	// *Ayy = *Axx;
1594 	// *Axy = -(*Ayx);
1595 	//
1596 	// dx = a[2][0];
1597 	// dy = a[3][0];
1598 	//
1599 	// break;
1600 	// case 2:
1601 	// _am_compute6by1ErrorVector(imgdiff, gradx, grady, width, height, a);
1602 	// _am_compute6by6GradientMatrix(gradx, grady, width, height, T);
1603 	//
1604 	// status = _am_gauss_jordan_elimination(T,6,a,1);
1605 	//
1606 	// *Axx += a[0][0];
1607 	// *Ayx += a[1][0];
1608 	// *Axy += a[2][0];
1609 	// *Ayy += a[3][0];
1610 	//
1611 	// dx = a[4][0];
1612 	// dy = a[5][0];
1613 	//
1614 	// break;
1615 	// }
1616 	//
1617 	// *x2 += dx;
1618 	// *y2 += dy;
1619 	//
1620 	// /* old upper left corner - new upper left corner */
1621 	// ul_x -= *Axx * (-hw) + *Axy * hh + *x2;
1622 	// ul_y -= *Ayx * (-hw) + *Ayy * hh + *y2;
1623 	// /* old lower left corner - new lower left corner */
1624 	// ll_x -= *Axx * (-hw) + *Axy * (-hh) + *x2;
1625 	// ll_y -= *Ayx * (-hw) + *Ayy * (-hh) + *y2;
1626 	// /* old upper right corner - new upper right corner */
1627 	// ur_x -= *Axx * hw + *Axy * hh + *x2;
1628 	// ur_y -= *Ayx * hw + *Ayy * hh + *y2;
1629 	// /* old lower right corner - new lower right corner */
1630 	// lr_x -= *Axx * hw + *Axy * (-hh) + *x2;
1631 	// lr_y -= *Ayx * hw + *Ayy * (-hh) + *y2;
1632 	//
1633 	// #ifdef DEBUG_AFFINE_MAPPING
1634 	// printf
1635 	// ("iter = %d, ul_x=%f ul_y=%f ll_x=%f ll_y=%f ur_x=%f ur_y=%f lr_x=%f lr_y=%f \n",
1636 	// iteration, ul_x, ul_y, ll_x, ll_y, ur_x, ur_y, lr_x, lr_y);
1637 	// #endif
1638 	//
1639 	// convergence = (fabs(dx) < th && fabs(dy) < th &&
1640 	// fabs(ul_x) < th_aff && fabs(ul_y) < th_aff &&
1641 	// fabs(ll_x) < th_aff && fabs(ll_y) < th_aff &&
1642 	// fabs(ur_x) < th_aff && fabs(ur_y) < th_aff &&
1643 	// fabs(lr_x) < th_aff && fabs(lr_y) < th_aff);
1644 	// }
1645 	//
1646 	// if (status == KLT_SMALL_DET) break;
1647 	// iteration++;
1648 	// #ifdef DEBUG_AFFINE_MAPPING
1649 	// printf
1650 	// ("iter = %d, x1=%f, y1=%f, x2=%f, y2=%f,  Axx=%f, Ayx=%f , Axy=%f, Ayy=%f \n",iteration,
1651 	// x1, y1, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy);
1652 	// #endif
1653 	// } while ( !convergence && iteration < max_iterations);
1654 	// /*} while ( (fabs(dx)>=th || fabs(dy)>=th || (affine_map && iteration <
1655 	// 8) ) && iteration < max_iterations); */
1656 	// _am_free_matrix(T);
1657 	// _am_free_matrix(a);
1658 	//
1659 	// /* Check whether window is out of bounds */
1660 	// if (*x2-hw < 0.0f || nc2-(*x2+hw) < one_plus_eps ||
1661 	// *y2-hh < 0.0f || nr2-(*y2+hh) < one_plus_eps)
1662 	// status = KLT_OOB;
1663 	//
1664 	// /* Check whether feature point has moved to much during iteration*/
1665 	// if ( (*x2-old_x2) > mdd || (*y2-old_y2) > mdd )
1666 	// status = KLT_OOB;
1667 	//
1668 	// /* Check whether residue is too large */
1669 	// if (status == KLT_TRACKED) {
1670 	// if(!affine_map){
1671 	// _computeIntensityDifference(img1, img2, x1, y1, *x2, *y2,
1672 	// width, height, imgdiff);
1673 	// }else{
1674 	// _am_computeIntensityDifferenceAffine(img1, img2, x1, y1, *x2, *y2, *Axx,
1675 	// *Ayx , *Axy, *Ayy,
1676 	// width, height, imgdiff);
1677 	// }
1678 	// #ifdef DEBUG_AFFINE_MAPPING
1679 	// printf("iter = %d final_res = %f\n", iteration,
1680 	// _sumAbsFloatWindow(imgdiff, width, height)/(width*height));
1681 	// #endif
1682 	// if (_sumAbsFloatWindow(imgdiff, width, height)/(width*height) >
1683 	// max_residue)
1684 	// status = KLT_LARGE_RESIDUE;
1685 	// }
1686 	//
1687 	// /* Free memory */
1688 	// free(imgdiff); free(gradx); free(grady);
1689 	//
1690 	// #ifdef DEBUG_AFFINE_MAPPING
1691 	// printf("iter = %d status=%d\n", iteration, status);
1692 	// _KLTFreeFloatImage( aff_diff_win );
1693 	// #endif
1694 	//
1695 	// /* Return appropriate value */
1696 	// return status;
1697 	// }
1698 	//
1699 	// /*
1700 	// * CONSISTENCY CHECK OF FEATURES BY AFFINE MAPPING (END)
1701 	// **********************************************************************/
1702 	//
1703 	//
1704 	//
1705 	/*********************************************************************
1706 	 * KLTTrackFeatures
1707 	 * 
1708 	 * Tracks feature points from one image to the next.
1709 	 * 
1710 	 * @param img1
1711 	 * @param img2
1712 	 */
1713 	public void trackFeatures(FImage img1, FImage img2)
1714 	{
1715 		if (isNorm) {
1716 			img1 = img1.multiply(255f);
1717 			img2 = img2.multiply(255f);
1718 		}
1719 		PyramidSet pyr1, pyr2;
1720 		int i;
1721 		final int nrows = img1.height, ncols = img1.width;
1722 
1723 		if (KLT_verbose >= 1) {
1724 			System.out.println(String.format("(KLT) Tracking %d features in a %d by %d image...  ",
1725 					featurelist.countRemainingFeatures(), ncols, nrows));
1726 		}
1727 
1728 		/* Check window size (and correct if necessary) */
1729 		if (tc.window_width % 2 != 1) {
1730 			tc.window_width = tc.window_width + 1;
1731 			System.out.println(String.format("Tracking context's window width must be odd.  Changing to %d.\n",
1732 					tc.window_width));
1733 		}
1734 		if (tc.window_height % 2 != 1) {
1735 			tc.window_height = tc.window_height + 1;
1736 			System.out.println(String.format("Tracking context's window height must be odd.  Changing to %d.\n",
1737 					tc.window_height));
1738 		}
1739 		if (tc.window_width < 3) {
1740 			tc.window_width = 3;
1741 			System.out.println(String.format(
1742 					"Tracking context's window width must be at least three.  \nChanging to %d.\n", tc.window_width));
1743 		}
1744 		if (tc.window_height < 3) {
1745 			tc.window_height = 3;
1746 			System.out.println(String.format(
1747 					"Tracking context's window height must be at least three.  \nChanging to %d.\n", tc.window_height));
1748 		}
1749 
1750 		/* Process first image by converting to float, smoothing, computing */
1751 		/* pyramid, and computing gradient pyramids */
1752 		final PyramidSet ppSet = tc.previousPyramidSet();
1753 		if (tc.sequentialMode && ppSet != null) {
1754 			Pyramid pyramid1, pyramid1_gradx, pyramid1_grady;
1755 			pyramid1 = ppSet.imgPyr;
1756 			pyramid1_gradx = ppSet.gradx;
1757 			pyramid1_grady = ppSet.grady;
1758 			if (pyramid1.ncols[0] != ncols || pyramid1.nrows[0] != nrows)
1759 				throw new RuntimeException(
1760 						String.format("(KLTTrackFeatures) Size of incoming image (%d by %d) is different from size " +
1761 								"of previous image (%d by %d)\n", ncols, nrows, pyramid1.ncols[0], pyramid1.nrows[0]));
1762 			assert (pyramid1_gradx != null);
1763 			assert (pyramid1_grady != null);
1764 			pyr1 = ppSet;
1765 		} else {
1766 			pyr1 = new PyramidSet(img1, tc);
1767 
1768 		}
1769 
1770 		/* Do the same thing with second image */
1771 		pyr2 = new PyramidSet(img2, tc);
1772 
1773 		/* Write internal images */
1774 		if (tc.writeInternalImages) {
1775 			String fname;
1776 			for (i = 0; i < tc.nPyramidLevels; i++) {
1777 				try {
1778 					fname = String.format("kltimg_tf_i%d.png", i);
1779 					ImageUtilities.write(pyr1.imgPyr.img[i], "png", new File(fname));
1780 					fname = String.format("kltimg_tf_i%d_gx.png", i);
1781 					ImageUtilities.write(pyr1.gradx.img[i], "png", new File(fname));
1782 					fname = String.format("kltimg_tf_i%d_gy.png", i);
1783 					ImageUtilities.write(pyr1.grady.img[i], "png", new File(fname));
1784 					fname = String.format("kltimg_tf_j%d.png", i);
1785 					ImageUtilities.write(pyr2.imgPyr.img[i], "png", new File(fname));
1786 					fname = String.format("kltimg_tf_j%d_gx.png", i);
1787 					ImageUtilities.write(pyr2.gradx.img[i], "png", new File(fname));
1788 					fname = String.format("kltimg_tf_j%d_gy.png", i);
1789 					ImageUtilities.write(pyr2.grady.img[i], "png", new File(fname));
1790 				} catch (final IOException e) {
1791 
1792 				}
1793 			}
1794 		}
1795 
1796 		trackFeatures(img1, img2, pyr1, pyr2);
1797 
1798 		if (tc.sequentialMode) {
1799 			tc.setPreviousPyramid(pyr2);
1800 		}
1801 
1802 		if (KLT_verbose >= 1) {
1803 			System.err.println(String.format("\n\t%d features successfully tracked.\n",
1804 					featurelist.countRemainingFeatures()));
1805 			if (tc.writeInternalImages)
1806 				System.err.println("\tWrote images to 'kltimg_tf*.pgm'.\n");
1807 		}
1808 	}
1809 
1810 	/**
1811 	 * KLTTrackFeatures
1812 	 * 
1813 	 * Tracks feature points from one image to the next. Also takes in image
1814 	 * pyramids and gradient pyramids for both images.
1815 	 * 
1816 	 * @param img1
1817 	 * @param img2
1818 	 * @param pyr1
1819 	 * @param pyr2
1820 	 */
1821 	public void trackFeatures(FImage img1, FImage img2, PyramidSet pyr1, PyramidSet pyr2) {
1822 		float xloc, yloc, xlocout, ylocout;
1823 		int val = -1;
1824 		int indx, r;
1825 		final float subsampling = tc.subsampling;
1826 		final int nrows = img1.height, ncols = img1.width;
1827 		/* For each feature, do ... */
1828 		for (indx = 0; indx < featurelist.features.length; indx++) {
1829 
1830 			/* Only track features that are not lost */
1831 			if (featurelist.features[indx].val >= 0) {
1832 
1833 				xloc = featurelist.features[indx].x;
1834 				yloc = featurelist.features[indx].y;
1835 
1836 				/* Transform location to coarsest resolution */
1837 				for (r = tc.nPyramidLevels - 1; r >= 0; r--) {
1838 					xloc /= subsampling;
1839 					yloc /= subsampling;
1840 				}
1841 				xlocout = xloc;
1842 				ylocout = yloc;
1843 
1844 				/* Beginning with coarsest resolution, do ... */
1845 				for (r = tc.nPyramidLevels - 1; r >= 0; r--) {
1846 
1847 					/* Track feature at current resolution */
1848 					xloc *= subsampling;
1849 					yloc *= subsampling;
1850 					xlocout *= subsampling;
1851 					ylocout *= subsampling;
1852 
1853 					final float[] xylocout = new float[2];
1854 					xylocout[0] = xlocout;
1855 					xylocout[1] = ylocout;
1856 
1857 					val = _trackFeature(xloc, yloc,
1858 							xylocout,
1859 							pyr1.imgPyr.img[r],
1860 							pyr1.gradx.img[r], pyr1.grady.img[r],
1861 							pyr2.imgPyr.img[r],
1862 							pyr2.gradx.img[r], pyr2.grady.img[r],
1863 							tc.window_width, tc.window_height,
1864 							tc.step_factor,
1865 							tc.max_iterations,
1866 							tc.min_determinant,
1867 							tc.min_displacement,
1868 							tc.max_residue,
1869 							tc.lighting_insensitive);
1870 
1871 					xlocout = xylocout[0];
1872 					ylocout = xylocout[1];
1873 
1874 					if (val == KLT_SMALL_DET || val == KLT_OOB)
1875 						break;
1876 				}
1877 
1878 				/* Record feature */
1879 				if (val == KLT_OOB) {
1880 					featurelist.features[indx].x = -1.0f;
1881 					featurelist.features[indx].y = -1.0f;
1882 					featurelist.features[indx].val = KLT_OOB;
1883 
1884 					// featurelist.features[indx].aff_img = null;
1885 					// featurelist.features[indx].aff_img_gradx = null;
1886 					// featurelist.features[indx].aff_img_grady = null;
1887 
1888 				} else if (_outOfBounds(xlocout, ylocout, ncols, nrows, tc.borderx, tc.bordery)) {
1889 					featurelist.features[indx].x = -1.0f;
1890 					featurelist.features[indx].y = -1.0f;
1891 					featurelist.features[indx].val = KLT_OOB;
1892 
1893 					// featurelist.features[indx].aff_img = null;
1894 					// featurelist.features[indx].aff_img_gradx = null;
1895 					// featurelist.features[indx].aff_img_grady = null;
1896 				} else if (val == KLT_SMALL_DET) {
1897 					featurelist.features[indx].x = -1.0f;
1898 					featurelist.features[indx].y = -1.0f;
1899 					featurelist.features[indx].val = KLT_SMALL_DET;
1900 
1901 					// featurelist.features[indx].aff_img = null;
1902 					// featurelist.features[indx].aff_img_gradx = null;
1903 					// featurelist.features[indx].aff_img_grady = null;
1904 				} else if (val == KLT_LARGE_RESIDUE) {
1905 					featurelist.features[indx].x = -1.0f;
1906 					featurelist.features[indx].y = -1.0f;
1907 					featurelist.features[indx].val = KLT_LARGE_RESIDUE;
1908 
1909 					// featurelist.features[indx].aff_img = null;
1910 					// featurelist.features[indx].aff_img_gradx = null;
1911 					// featurelist.features[indx].aff_img_grady = null;
1912 				} else if (val == KLT_MAX_ITERATIONS) {
1913 					featurelist.features[indx].x = -1.0f;
1914 					featurelist.features[indx].y = -1.0f;
1915 					featurelist.features[indx].val = KLT_MAX_ITERATIONS;
1916 
1917 					// featurelist.features[indx].aff_img = null;
1918 					// featurelist.features[indx].aff_img_gradx = null;
1919 					// featurelist.features[indx].aff_img_grady = null;
1920 				} else {
1921 					featurelist.features[indx].x = xlocout;
1922 					featurelist.features[indx].y = ylocout;
1923 					featurelist.features[indx].val = KLT_TRACKED;
1924 					if (tc.affineConsistencyCheck >= 0 && val == KLT_TRACKED) { /*
1925 																				 * for
1926 																				 * affine
1927 																				 * mapping
1928 																				 */
1929 						throw new UnsupportedOperationException("Affine mapping not yet implemented");
1930 						// int border = 2; /* add border for interpolation */
1931 						//
1932 						// if(featurelist.features[indx].aff_img == null){
1933 						// /* save image and gradient for each feature at finest
1934 						// resolution after first successful track */
1935 						// featurelist.features[indx].aff_img = new
1936 						// FImage((tc.affine_window_height+border),
1937 						// (tc.affine_window_width+border));
1938 						// featurelist.features[indx].aff_img_gradx = new
1939 						// FImage((tc.affine_window_height+border),
1940 						// (tc.affine_window_width+border));
1941 						// featurelist.features[indx].aff_img_grady = new
1942 						// FImage((tc.affine_window_height+border),
1943 						// (tc.affine_window_width+border));
1944 						// _am_getSubFloatImage(pyramid1.img[0],xloc,yloc,featurelist.features[indx].aff_img);
1945 						// _am_getSubFloatImage(pyramid1_gradx.img[0],xloc,yloc,featurelist.features[indx].aff_img_gradx);
1946 						// _am_getSubFloatImage(pyramid1_grady.img[0],xloc,yloc,featurelist.features[indx].aff_img_grady);
1947 						// featurelist.features[indx].aff_x = xloc - (int) xloc
1948 						// + (tc.affine_window_width+border)/2;
1949 						// featurelist.features[indx].aff_y = yloc - (int) yloc
1950 						// + (tc.affine_window_height+border)/2;;
1951 						// }else{
1952 						// /* affine tracking */
1953 						// val =
1954 						// _am_trackFeatureAffine(featurelist.features[indx].aff_x,
1955 						// featurelist.features[indx].aff_y,
1956 						// &xlocout, &ylocout,
1957 						// featurelist.features[indx].aff_img,
1958 						// featurelist.features[indx].aff_img_gradx,
1959 						// featurelist.features[indx].aff_img_grady,
1960 						// pyramid2.img[0],
1961 						// pyramid2_gradx.img[0], pyramid2_grady.img[0],
1962 						// tc.affine_window_width, tc.affine_window_height,
1963 						// tc.step_factor,
1964 						// tc.affine_max_iterations,
1965 						// tc.min_determinant,
1966 						// tc.min_displacement,
1967 						// tc.affine_min_displacement,
1968 						// tc.affine_max_residue,
1969 						// tc.lighting_insensitive,
1970 						// tc.affineConsistencyCheck,
1971 						// tc.affine_max_displacement_differ,
1972 						// &featurelist.features[indx].aff_Axx,
1973 						// &featurelist.features[indx].aff_Ayx,
1974 						// &featurelist.features[indx].aff_Axy,
1975 						// &featurelist.features[indx].aff_Ayy
1976 						// );
1977 						// featurelist.features[indx].val = val;
1978 						// if(val != KLT_TRACKED){
1979 						// featurelist.features[indx].x = -1.0f;
1980 						// featurelist.features[indx].y = -1.0f;
1981 						// featurelist.features[indx].aff_x = -1.0f;
1982 						// featurelist.features[indx].aff_y = -1.0f;
1983 						//
1984 						// featurelist.features[indx].aff_img = null;
1985 						// featurelist.features[indx].aff_img_gradx = null;
1986 						// featurelist.features[indx].aff_img_grady = null;
1987 						// }else{
1988 						// /*featurelist.features[indx].x = xlocout;*/
1989 						// /*featurelist.features[indx].y = ylocout;*/
1990 						// }
1991 						// }
1992 					}
1993 
1994 				}
1995 			}
1996 		}
1997 	}
1998 
1999 	/**
2000 	 * @return the tracking context
2001 	 */
2002 	public TrackingContext getTrackingContext() {
2003 		return tc;
2004 	}
2005 
2006 	/**
2007 	 * Set the tracking context
2008 	 * 
2009 	 * @param tc
2010 	 */
2011 	public void setTrackingContext(TrackingContext tc) {
2012 		this.tc = tc;
2013 	}
2014 
2015 	/**
2016 	 * @return the feature list
2017 	 */
2018 	public FeatureList getFeatureList() {
2019 		return featurelist;
2020 	}
2021 
2022 	/**
2023 	 * Set the tracking context
2024 	 * 
2025 	 * @param featurelist
2026 	 */
2027 	public void setFeatureList(FeatureList featurelist) {
2028 		this.featurelist = featurelist;
2029 	}
2030 
2031 	/**
2032 	 * @return true if input images are normalised in [0,1]; false if in [0,
2033 	 *         255]
2034 	 */
2035 	public boolean isNorm() {
2036 		return isNorm;
2037 	}
2038 
2039 	/**
2040 	 * Set whether input images are in [0,1] (true) or [0,255] (false).
2041 	 * 
2042 	 * @param isNorm
2043 	 */
2044 	public void setNorm(boolean isNorm) {
2045 		this.isNorm = isNorm;
2046 	}
2047 
2048 }