rawTherapee/rtengine/klt/trackFeatures.cc

1541 lines
47 KiB
C++

/*********************************************************************
* trackFeatures.c
*
*********************************************************************/
/* Standard includes */
#include <cassert>
#include <cmath> /* fabs() */
#include <cstdlib> /* malloc() */
#include <cstdio> /* fflush() */
/* Our includes */
#include "base.h"
#include "error.h"
#include "convolve.h" /* for computing pyramid */
#include "klt.h"
#include "klt_util.h" /* _KLT_FloatImage */
#include "pyramid.h" /* _KLT_Pyramid */
extern int KLT_verbose;
typedef float *_FloatWindow;
/*********************************************************************
* _interpolate
*
* Given a point (x,y) in an image, computes the bilinear interpolated
* gray-level value of the point in the image.
*/
static float _interpolate(
float x,
float y,
_KLT_FloatImage img)
{
int xt = (int) x; /* coordinates of top-left corner */
int yt = (int) y;
float ax = x - xt;
float ay = y - yt;
float *ptr = img->data + (img->ncols*yt) + xt;
#ifndef _DNDEBUG
if (xt<0 || yt<0 || xt>=img->ncols-1 || yt>=img->nrows-1) {
fprintf(stderr, "(xt,yt)=(%d,%d) imgsize=(%d,%d)\n"
"(x,y)=(%f,%f) (ax,ay)=(%f,%f)\n",
xt, yt, img->ncols, img->nrows, x, y, ax, ay);
fflush(stderr);
}
#endif
assert (xt >= 0 && yt >= 0 && xt <= img->ncols - 2 && yt <= img->nrows - 2);
return ( (1-ax) * (1-ay) * *ptr +
ax * (1-ay) * *(ptr+1) +
(1-ax) * ay * *(ptr+(img->ncols)) +
ax * ay * *(ptr+(img->ncols)+1) );
}
/*********************************************************************
* _computeIntensityDifference
*
* Given two images and the window center in both images,
* aligns the images wrt the window and computes the difference
* between the two overlaid images.
*/
static void _computeIntensityDifference(
_KLT_FloatImage img1, /* images */
_KLT_FloatImage img2,
float x1, float y1, /* center of window in 1st img */
float x2, float y2, /* center of window in 2nd img */
int width, int height, /* size of window */
_FloatWindow imgdiff) /* output */
{
int hw = width/2, hh = height/2;
float g1, g2;
int i, j;
/* Compute values */
for (j = -hh ; j <= hh ; j++)
for (i = -hw ; i <= hw ; i++) {
g1 = _interpolate(x1+i, y1+j, img1);
g2 = _interpolate(x2+i, y2+j, img2);
*imgdiff++ = g1 - g2;
}
}
/*********************************************************************
* _computeGradientSum
*
* Given two gradients and the window center in both images,
* aligns the gradients wrt the window and computes the sum of the two
* overlaid gradients.
*/
static void _computeGradientSum(
_KLT_FloatImage gradx1, /* gradient images */
_KLT_FloatImage grady1,
_KLT_FloatImage gradx2,
_KLT_FloatImage grady2,
float x1, float y1, /* center of window in 1st img */
float x2, float y2, /* center of window in 2nd img */
int width, int height, /* size of window */
_FloatWindow gradx, /* output */
_FloatWindow grady) /* " */
{
int hw = width/2, hh = height/2;
float g1, g2;
int i, j;
/* Compute values */
for (j = -hh ; j <= hh ; j++)
for (i = -hw ; i <= hw ; i++) {
g1 = _interpolate(x1+i, y1+j, gradx1);
g2 = _interpolate(x2+i, y2+j, gradx2);
*gradx++ = g1 + g2;
g1 = _interpolate(x1+i, y1+j, grady1);
g2 = _interpolate(x2+i, y2+j, grady2);
*grady++ = g1 + g2;
}
}
/*********************************************************************
* _computeIntensityDifferenceLightingInsensitive
*
* Given two images and the window center in both images,
* aligns the images wrt the window and computes the difference
* between the two overlaid images; normalizes for overall gain and bias.
*/
static void _computeIntensityDifferenceLightingInsensitive(
_KLT_FloatImage img1, /* images */
_KLT_FloatImage img2,
float x1, float y1, /* center of window in 1st img */
float x2, float y2, /* center of window in 2nd img */
int width, int height, /* size of window */
_FloatWindow imgdiff) /* output */
{
int hw = width/2, hh = height/2;
float g1, g2, sum1_squared = 0, sum2_squared = 0;
int i, j;
float sum1 = 0, sum2 = 0;
float mean1, mean2,alpha,belta;
/* Compute values */
for (j = -hh ; j <= hh ; j++)
for (i = -hw ; i <= hw ; i++) {
g1 = _interpolate(x1+i, y1+j, img1);
g2 = _interpolate(x2+i, y2+j, img2);
sum1 += g1; sum2 += g2;
sum1_squared += g1*g1;
sum2_squared += g2*g2;
}
mean1=sum1_squared/(width*height);
mean2=sum2_squared/(width*height);
alpha = (float) sqrt(mean1/mean2);
mean1=sum1/(width*height);
mean2=sum2/(width*height);
belta = mean1-alpha*mean2;
for (j = -hh ; j <= hh ; j++)
for (i = -hw ; i <= hw ; i++) {
g1 = _interpolate(x1+i, y1+j, img1);
g2 = _interpolate(x2+i, y2+j, img2);
*imgdiff++ = g1- g2*alpha-belta;
}
}
/*********************************************************************
* _computeGradientSumLightingInsensitive
*
* Given two gradients and the window center in both images,
* aligns the gradients wrt the window and computes the sum of the two
* overlaid gradients; normalizes for overall gain and bias.
*/
static void _computeGradientSumLightingInsensitive(
_KLT_FloatImage gradx1, /* gradient images */
_KLT_FloatImage grady1,
_KLT_FloatImage gradx2,
_KLT_FloatImage grady2,
_KLT_FloatImage img1, /* images */
_KLT_FloatImage img2,
float x1, float y1, /* center of window in 1st img */
float x2, float y2, /* center of window in 2nd img */
int width, int height, /* size of window */
_FloatWindow gradx, /* output */
_FloatWindow grady) /* " */
{
int hw = width/2, hh = height/2;
float g1, g2, sum1_squared = 0, sum2_squared = 0;
int i, j;
float mean1, mean2, alpha;
for (j = -hh ; j <= hh ; j++)
for (i = -hw ; i <= hw ; i++) {
g1 = _interpolate(x1+i, y1+j, img1);
g2 = _interpolate(x2+i, y2+j, img2);
sum1_squared += g1; sum2_squared += g2;
}
mean1 = sum1_squared/(width*height);
mean2 = sum2_squared/(width*height);
alpha = (float) sqrt(mean1/mean2);
/* Compute values */
for (j = -hh ; j <= hh ; j++)
for (i = -hw ; i <= hw ; i++) {
g1 = _interpolate(x1+i, y1+j, gradx1);
g2 = _interpolate(x2+i, y2+j, gradx2);
*gradx++ = g1 + g2*alpha;
g1 = _interpolate(x1+i, y1+j, grady1);
g2 = _interpolate(x2+i, y2+j, grady2);
*grady++ = g1+ g2*alpha;
}
}
/*********************************************************************
* _compute2by2GradientMatrix
*
*/
static void _compute2by2GradientMatrix(
_FloatWindow gradx,
_FloatWindow grady,
int width, /* size of window */
int height,
float *gxx, /* return values */
float *gxy,
float *gyy)
{
float gx, gy;
int i;
/* Compute values */
*gxx = 0.0; *gxy = 0.0; *gyy = 0.0;
for (i = 0 ; i < width * height ; i++) {
gx = *gradx++;
gy = *grady++;
*gxx += gx*gx;
*gxy += gx*gy;
*gyy += gy*gy;
}
}
/*********************************************************************
* _compute2by1ErrorVector
*
*/
static void _compute2by1ErrorVector(
_FloatWindow imgdiff,
_FloatWindow gradx,
_FloatWindow grady,
int width, /* size of window */
int height,
float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid overshooting */
float *ex, /* return values */
float *ey)
{
float diff;
int i;
/* Compute values */
*ex = 0; *ey = 0;
for (i = 0 ; i < width * height ; i++) {
diff = *imgdiff++;
*ex += diff * (*gradx++);
*ey += diff * (*grady++);
}
*ex *= step_factor;
*ey *= step_factor;
}
/*********************************************************************
* _solveEquation
*
* Solves the 2x2 matrix equation
* [gxx gxy] [dx] = [ex]
* [gxy gyy] [dy] = [ey]
* for dx and dy.
*
* Returns KLT_TRACKED on success and KLT_SMALL_DET on failure
*/
static int _solveEquation(
float gxx, float gxy, float gyy,
float ex, float ey,
float small,
float *dx, float *dy)
{
float det = gxx*gyy - gxy*gxy;
if (det < small) return KLT_SMALL_DET;
*dx = (gyy*ex - gxy*ey)/det;
*dy = (gxx*ey - gxy*ex)/det;
return KLT_TRACKED;
}
/*********************************************************************
* _allocateFloatWindow
*/
static _FloatWindow _allocateFloatWindow(
int width,
int height)
{
_FloatWindow fw;
fw = (_FloatWindow) malloc(width*height*sizeof(float));
if (fw == nullptr) {
KLTError("(_allocateFloatWindow) Out of memory.");
exit(1);
}
return fw;
}
/*********************************************************************
* _printFloatWindow
* (for debugging purposes)
*/
/*
static void _printFloatWindow(
_FloatWindow fw,
int width,
int height)
{
int i, j;
fprintf(stderr, "\n");
for (i = 0 ; i < width ; i++) {
for (j = 0 ; j < height ; j++) {
fprintf(stderr, "%6.1f ", *fw++);
}
fprintf(stderr, "\n");
}
}
*/
/*********************************************************************
* _sumAbsFloatWindow
*/
static float _sumAbsFloatWindow(
_FloatWindow fw,
int width,
int height)
{
float sum = 0.0;
int w;
for ( ; height > 0 ; height--)
for (w=0 ; w < width ; w++)
sum += (float) fabs(*fw++);
return sum;
}
/*********************************************************************
* _trackFeature
*
* Tracks a feature point from one image to the next.
*
* RETURNS
* KLT_SMALL_DET if feature is lost,
* KLT_MAX_ITERATIONS if tracking stopped because iterations timed out,
* KLT_TRACKED otherwise.
*/
static int _trackFeature(
float x1, /* location of window in first image */
float y1,
float *x2, /* starting location of search in second image */
float *y2,
_KLT_FloatImage img1,
_KLT_FloatImage gradx1,
_KLT_FloatImage grady1,
_KLT_FloatImage img2,
_KLT_FloatImage gradx2,
_KLT_FloatImage grady2,
int width, /* size of window */
int height,
float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid overshooting */
int max_iterations,
float small, /* determinant threshold for declaring KLT_SMALL_DET */
float th, /* displacement threshold for stopping */
float max_residue, /* residue threshold for declaring KLT_LARGE_RESIDUE */
int lighting_insensitive) /* whether to normalize for gain and bias */
{
_FloatWindow imgdiff, gradx, grady;
float gxx, gxy, gyy, ex, ey, dx, dy;
int iteration = 0;
int status;
int hw = width/2;
int hh = height/2;
int nc = img1->ncols;
int nr = img1->nrows;
float one_plus_eps = 1.001f; /* To prevent rounding errors */
/* Allocate memory for windows */
imgdiff = _allocateFloatWindow(width, height);
gradx = _allocateFloatWindow(width, height);
grady = _allocateFloatWindow(width, height);
/* Iteratively update the window position */
do {
/* If out of bounds, exit loop */
if ( x1-hw < 0.0f || nc-( x1+hw) < one_plus_eps ||
*x2-hw < 0.0f || nc-(*x2+hw) < one_plus_eps ||
y1-hh < 0.0f || nr-( y1+hh) < one_plus_eps ||
*y2-hh < 0.0f || nr-(*y2+hh) < one_plus_eps) {
status = KLT_OOB;
break;
}
/* Compute gradient and difference windows */
if (lighting_insensitive) {
_computeIntensityDifferenceLightingInsensitive(img1, img2, x1, y1, *x2, *y2,
width, height, imgdiff);
_computeGradientSumLightingInsensitive(gradx1, grady1, gradx2, grady2,
img1, img2, x1, y1, *x2, *y2, width, height, gradx, grady);
} else {
_computeIntensityDifference(img1, img2, x1, y1, *x2, *y2,
width, height, imgdiff);
_computeGradientSum(gradx1, grady1, gradx2, grady2,
x1, y1, *x2, *y2, width, height, gradx, grady);
}
/* Use these windows to construct matrices */
_compute2by2GradientMatrix(gradx, grady, width, height,
&gxx, &gxy, &gyy);
_compute2by1ErrorVector(imgdiff, gradx, grady, width, height, step_factor,
&ex, &ey);
/* Using matrices, solve equation for new displacement */
status = _solveEquation(gxx, gxy, gyy, ex, ey, small, &dx, &dy);
if (status == KLT_SMALL_DET) break;
*x2 += dx;
*y2 += dy;
iteration++;
} while ((fabs(dx)>=th || fabs(dy)>=th) && iteration < max_iterations);
/* Check whether window is out of bounds */
if (*x2-hw < 0.0f || nc-(*x2+hw) < one_plus_eps ||
*y2-hh < 0.0f || nr-(*y2+hh) < one_plus_eps || std::isnan(*x2) || std::isnan(*y2))
status = KLT_OOB;
/* Check whether residue is too large */
if (status == KLT_TRACKED) {
if (lighting_insensitive)
_computeIntensityDifferenceLightingInsensitive(img1, img2, x1, y1, *x2, *y2,
width, height, imgdiff);
else
_computeIntensityDifference(img1, img2, x1, y1, *x2, *y2,
width, height, imgdiff);
if (_sumAbsFloatWindow(imgdiff, width, height)/(width*height) > max_residue)
status = KLT_LARGE_RESIDUE;
}
/* Free memory */
free(imgdiff); free(gradx); free(grady);
/* Return appropriate value */
if (status == KLT_SMALL_DET) return KLT_SMALL_DET;
else if (status == KLT_OOB) return KLT_OOB;
else if (status == KLT_LARGE_RESIDUE) return KLT_LARGE_RESIDUE;
else if (iteration >= max_iterations) return KLT_MAX_ITERATIONS;
else return KLT_TRACKED;
}
/*********************************************************************/
static KLT_BOOL _outOfBounds(
float x,
float y,
int ncols,
int nrows,
int borderx,
int bordery)
{
return (x < borderx || x > ncols-1-borderx ||
y < bordery || y > nrows-1-bordery );
}
/**********************************************************************
* CONSISTENCY CHECK OF FEATURES BY AFFINE MAPPING (BEGIN)
*
* Created by: Thorsten Thormaehlen (University of Hannover) June 2004
* thormae@tnt.uni-hannover.de
*
* Permission is granted to any individual or institution to use, copy, modify,
* and distribute this part of the software, provided that this complete authorship
* and permission notice is maintained, intact, in all copies.
*
* This software is provided "as is" without express or implied warranty.
*
*
* The following static functions are helpers for the affine mapping.
* They all start with "_am".
* There are also small changes in other files for the
* affine mapping these are all marked by "for affine mapping"
*
* Thanks to Kevin Koeser (koeser@mip.informatik.uni-kiel.de) for fixing a bug
*/
#define SWAP_ME(X,Y) {temp=(X);(X)=(Y);(Y)=temp;}
static float **_am_matrix(long nr, long nc)
{
float **m;
int a;
m = (float **) malloc((size_t)(nr*sizeof(float*)));
m[0] = (float *) malloc((size_t)((nr*nc)*sizeof(float)));
for(a = 1; a < nr; a++) m[a] = m[a-1]+nc;
return m;
}
static void _am_free_matrix(float **m)
{
free(m[0]);
free(m);
}
static int _am_gauss_jordan_elimination(float **a, int n, float **b, int m)
{
/* re-implemented from Numerical Recipes in C */
int *indxc,*indxr,*ipiv;
int i,j,k,l,ll;
float big,dum,pivinv,temp;
int col = 0;
int row = 0;
indxc=(int *)malloc((size_t) (n*sizeof(int)));
indxr=(int *)malloc((size_t) (n*sizeof(int)));
ipiv=(int *)malloc((size_t) (n*sizeof(int)));
for (j=0;j<n;j++) ipiv[j]=0;
for (i=0;i<n;i++) {
big=0.0;
for (j=0;j<n;j++)
if (ipiv[j] != 1)
for (k=0;k<n;k++) {
if (ipiv[k] == 0) {
if (fabs(a[j][k]) >= big) {
big= (float) fabs(a[j][k]);
row=j;
col=k;
}
} else if (ipiv[k] > 1) {
free(ipiv); free(indxr); free(indxc); return KLT_SMALL_DET;
}
}
++(ipiv[col]);
if (row != col) {
for (l=0;l<n;l++) SWAP_ME(a[row][l],a[col][l])
for (l=0;l<m;l++) SWAP_ME(b[row][l],b[col][l])
}
indxr[i]=row;
indxc[i]=col;
if (a[col][col] == 0.0) {
free(ipiv);
free(indxr);
free(indxc);
return KLT_SMALL_DET;
}
pivinv=1.0f/a[col][col];
a[col][col]=1.0;
for (l=0;l<n;l++) a[col][l] *= pivinv;
for (l=0;l<m;l++) b[col][l] *= pivinv;
for (ll=0;ll<n;ll++)
if (ll != col) {
dum=a[ll][col];
a[ll][col]=0.0;
for (l=0;l<n;l++) a[ll][l] -= a[col][l]*dum;
for (l=0;l<m;l++) b[ll][l] -= b[col][l]*dum;
}
}
for (l=n-1;l>=0;l--) {
if (indxr[l] != indxc[l])
for (k=0;k<n;k++)
SWAP_ME(a[k][indxr[l]],a[k][indxc[l]]);
}
free(ipiv);
free(indxr);
free(indxc);
return KLT_TRACKED;
}
/*********************************************************************
* _am_getGradientWinAffine
*
* aligns the gradients with the affine transformed window
*/
static void _am_getGradientWinAffine(
_KLT_FloatImage in_gradx,
_KLT_FloatImage in_grady,
float x, float y, /* center of window*/
float Axx, float Ayx , float Axy, float Ayy, /* affine mapping */
int width, int height, /* size of window */
_FloatWindow out_gradx, /* output */
_FloatWindow out_grady) /* output */
{
int hw = width/2, hh = height/2;
int i, j;
float mi, mj;
/* Compute values */
for (j = -hh ; j <= hh ; j++)
for (i = -hw ; i <= hw ; i++) {
mi = Axx * i + Axy * j;
mj = Ayx * i + Ayy * j;
*out_gradx++ = _interpolate(x+mi, y+mj, in_gradx);
*out_grady++ = _interpolate(x+mi, y+mj, in_grady);
}
}
///*********************************************************************
// * _computeAffineMappedImage
// * used only for DEBUG output
// *
//*/
//
//static void _am_computeAffineMappedImage(
// _KLT_FloatImage img, /* images */
// float x, float y, /* center of window */
// float Axx, float Ayx , float Axy, float Ayy, /* affine mapping */
// int width, int height, /* size of window */
// _FloatWindow imgdiff) /* output */
//{
// int hw = width/2, hh = height/2;
// int i, j;
// float mi, mj;
//
// /* Compute values */
// for (j = -hh ; j <= hh ; j++)
// for (i = -hw ; i <= hw ; i++) {
// mi = Axx * i + Axy * j;
// mj = Ayx * i + Ayy * j;
// *imgdiff++ = _interpolate(x+mi, y+mj, img);
// }
//}
/*********************************************************************
* _getSubFloatImage
*/
static void _am_getSubFloatImage(
_KLT_FloatImage img, /* image */
float x, float y, /* center of window */
_KLT_FloatImage window) /* output */
{
int hw = window->ncols/2, hh = window->nrows/2;
int x0 = (int) x;
int y0 = (int) y;
float * windata = window->data;
int offset;
int i, j;
assert(x0 - hw >= 0);
assert(y0 - hh >= 0);
assert(x0 + hw <= img->ncols);
assert(y0 + hh <= img->nrows);
/* copy values */
for (j = -hh ; j <= hh ; j++)
for (i = -hw ; i <= hw ; i++) {
offset = (j+y0)*img->ncols + (i+x0);
*windata++ = *(img->data+offset);
}
}
/*********************************************************************
* _am_computeIntensityDifferenceAffine
*
* Given two images and the window center in both images,
* aligns the images with the window and computes the difference
* between the two overlaid images using the affine mapping.
* A = [ Axx Axy]
* [ Ayx Ayy]
*/
static void _am_computeIntensityDifferenceAffine(
_KLT_FloatImage img1, /* images */
_KLT_FloatImage img2,
float x1, float y1, /* center of window in 1st img */
float x2, float y2, /* center of window in 2nd img */
float Axx, float Ayx , float Axy, float Ayy, /* affine mapping */
int width, int height, /* size of window */
_FloatWindow imgdiff) /* output */
{
int hw = width/2, hh = height/2;
float g1, g2;
int i, j;
float mi, mj;
/* Compute values */
for (j = -hh ; j <= hh ; j++)
for (i = -hw ; i <= hw ; i++) {
g1 = _interpolate(x1+i, y1+j, img1);
mi = Axx * i + Axy * j;
mj = Ayx * i + Ayy * j;
g2 = _interpolate(x2+mi, y2+mj, img2);
*imgdiff++ = g1 - g2;
}
}
/*********************************************************************
* _am_compute6by6GradientMatrix
*
*/
static void _am_compute6by6GradientMatrix(
_FloatWindow gradx,
_FloatWindow grady,
int width, /* size of window */
int height,
float **T) /* return values */
{
int hw = width/2, hh = height/2;
int i, j;
float gx, gy, gxx, gxy, gyy, x, y, xx, xy, yy;
/* Set values to zero */
for (j = 0 ; j < 6 ; j++) {
for (i = j ; i < 6 ; i++) {
T[j][i] = 0.0;
}
}
for (j = -hh ; j <= hh ; j++) {
for (i = -hw ; i <= hw ; i++) {
gx = *gradx++;
gy = *grady++;
gxx = gx * gx;
gxy = gx * gy;
gyy = gy * gy;
x = (float) i;
y = (float) j;
xx = x * x;
xy = x * y;
yy = y * y;
T[0][0] += xx * gxx;
T[0][1] += xx * gxy;
T[0][2] += xy * gxx;
T[0][3] += xy * gxy;
T[0][4] += x * gxx;
T[0][5] += x * gxy;
T[1][1] += xx * gyy;
T[1][2] += xy * gxy;
T[1][3] += xy * gyy;
T[1][4] += x * gxy;
T[1][5] += x * gyy;
T[2][2] += yy * gxx;
T[2][3] += yy * gxy;
T[2][4] += y * gxx;
T[2][5] += y * gxy;
T[3][3] += yy * gyy;
T[3][4] += y * gxy;
T[3][5] += y * gyy;
T[4][4] += gxx;
T[4][5] += gxy;
T[5][5] += gyy;
}
}
for (j = 0 ; j < 5 ; j++) {
for (i = j+1 ; i < 6 ; i++) {
T[i][j] = T[j][i];
}
}
}
/*********************************************************************
* _am_compute6by1ErrorVector
*
*/
static void _am_compute6by1ErrorVector(
_FloatWindow imgdiff,
_FloatWindow gradx,
_FloatWindow grady,
int width, /* size of window */
int height,
float **e) /* return values */
{
int hw = width/2, hh = height/2;
int i, j;
float diff, diffgradx, diffgrady;
/* Set values to zero */
for(i = 0; i < 6; i++) e[i][0] = 0.0;
/* Compute values */
for (j = -hh ; j <= hh ; j++) {
for (i = -hw ; i <= hw ; i++) {
diff = *imgdiff++;
diffgradx = diff * (*gradx++);
diffgrady = diff * (*grady++);
e[0][0] += diffgradx * i;
e[1][0] += diffgrady * i;
e[2][0] += diffgradx * j;
e[3][0] += diffgrady * j;
e[4][0] += diffgradx;
e[5][0] += diffgrady;
}
}
for(i = 0; i < 6; i++) e[i][0] *= 0.5;
}
/*********************************************************************
* _am_compute4by4GradientMatrix
*
*/
static void _am_compute4by4GradientMatrix(
_FloatWindow gradx,
_FloatWindow grady,
int width, /* size of window */
int height,
float **T) /* return values */
{
int hw = width/2, hh = height/2;
int i, j;
float gx, gy, x, y;
/* Set values to zero */
for (j = 0 ; j < 4 ; j++) {
for (i = 0 ; i < 4 ; i++) {
T[j][i] = 0.0;
}
}
for (j = -hh ; j <= hh ; j++) {
for (i = -hw ; i <= hw ; i++) {
gx = *gradx++;
gy = *grady++;
x = (float) i;
y = (float) j;
T[0][0] += (x*gx+y*gy) * (x*gx+y*gy);
T[0][1] += (x*gx+y*gy)*(x*gy-y*gx);
T[0][2] += (x*gx+y*gy)*gx;
T[0][3] += (x*gx+y*gy)*gy;
T[1][1] += (x*gy-y*gx) * (x*gy-y*gx);
T[1][2] += (x*gy-y*gx)*gx;
T[1][3] += (x*gy-y*gx)*gy;
T[2][2] += gx*gx;
T[2][3] += gx*gy;
T[3][3] += gy*gy;
}
}
for (j = 0 ; j < 3 ; j++) {
for (i = j+1 ; i < 4 ; i++) {
T[i][j] = T[j][i];
}
}
}
/*********************************************************************
* _am_compute4by1ErrorVector
*
*/
static void _am_compute4by1ErrorVector(
_FloatWindow imgdiff,
_FloatWindow gradx,
_FloatWindow grady,
int width, /* size of window */
int height,
float **e) /* return values */
{
int hw = width/2, hh = height/2;
int i, j;
float diff, diffgradx, diffgrady;
/* Set values to zero */
for(i = 0; i < 4; i++) e[i][0] = 0.0;
/* Compute values */
for (j = -hh ; j <= hh ; j++) {
for (i = -hw ; i <= hw ; i++) {
diff = *imgdiff++;
diffgradx = diff * (*gradx++);
diffgrady = diff * (*grady++);
e[0][0] += diffgradx * i + diffgrady * j;
e[1][0] += diffgrady * i - diffgradx * j;
e[2][0] += diffgradx;
e[3][0] += diffgrady;
}
}
for(i = 0; i < 4; i++) e[i][0] *= 0.5;
}
/*********************************************************************
* _am_trackFeatureAffine
*
* Tracks a feature point from the image of first occurrence to the actual image.
*
* RETURNS
* KLT_SMALL_DET or KLT_LARGE_RESIDUE or KLT_OOB if feature is lost,
* KLT_TRACKED otherwise.
*/
/* if you enable the DEBUG_AFFINE_MAPPING make sure you have created a directory "./debug" */
/* #define DEBUG_AFFINE_MAPPING */
#ifdef DEBUG_AFFINE_MAPPING
static int counter = 0;
static int glob_index = 0;
#endif
static int _am_trackFeatureAffine(
float x1, /* location of window in first image */
float y1,
float *x2, /* starting location of search in second image */
float *y2,
_KLT_FloatImage img1,
_KLT_FloatImage gradx1,
_KLT_FloatImage grady1,
_KLT_FloatImage img2,
_KLT_FloatImage gradx2,
_KLT_FloatImage grady2,
int width, /* size of window */
int height,
float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid overshooting */
int max_iterations,
float small, /* determinant threshold for declaring KLT_SMALL_DET */
float th, /* displacement threshold for stopping */
float th_aff,
float max_residue, /* residue threshold for declaring KLT_LARGE_RESIDUE */
int lighting_insensitive, /* whether to normalize for gain and bias */
int affine_map, /* whether to evaluates the consistency of features with affine mapping */
float mdd, /* difference between the displacements */
float *Axx, float *Ayx,
float *Axy, float *Ayy) /* used affine mapping */
{
_FloatWindow imgdiff, gradx, grady;
float gxx, gxy, gyy, ex, ey, dx = 0.f, dy = 0.f;
int iteration = 0;
int status = 0;
int hw = width/2;
int hh = height/2;
int nc1 = img1->ncols;
int nr1 = img1->nrows;
int nc2 = img2->ncols;
int nr2 = img2->nrows;
float **a;
float **T;
float one_plus_eps = 1.001f; /* To prevent rounding errors */
float old_x2 = *x2;
float old_y2 = *y2;
KLT_BOOL convergence = FALSE;
#ifdef DEBUG_AFFINE_MAPPING
char fname[80];
_KLT_FloatImage aff_diff_win = _KLTCreateFloatImage(width,height);
printf("starting location x2=%f y2=%f\n", *x2, *y2);
#endif
/* Allocate memory for windows */
imgdiff = _allocateFloatWindow(width, height);
gradx = _allocateFloatWindow(width, height);
grady = _allocateFloatWindow(width, height);
T = _am_matrix(6,6);
a = _am_matrix(6,1);
/* Iteratively update the window position */
do {
if(!affine_map) {
/* pure translation tracker */
/* If out of bounds, exit loop */
if ( x1-hw < 0.0f || nc1-( x1+hw) < one_plus_eps ||
*x2-hw < 0.0f || nc2-(*x2+hw) < one_plus_eps ||
y1-hh < 0.0f || nr1-( y1+hh) < one_plus_eps ||
*y2-hh < 0.0f || nr2-(*y2+hh) < one_plus_eps) {
status = KLT_OOB;
break;
}
/* Compute gradient and difference windows */
if (lighting_insensitive) {
_computeIntensityDifferenceLightingInsensitive(img1, img2, x1, y1, *x2, *y2,
width, height, imgdiff);
_computeGradientSumLightingInsensitive(gradx1, grady1, gradx2, grady2,
img1, img2, x1, y1, *x2, *y2, width, height, gradx, grady);
} else {
_computeIntensityDifference(img1, img2, x1, y1, *x2, *y2,
width, height, imgdiff);
_computeGradientSum(gradx1, grady1, gradx2, grady2,
x1, y1, *x2, *y2, width, height, gradx, grady);
}
#ifdef DEBUG_AFFINE_MAPPING
aff_diff_win->data = imgdiff;
snprintf(fname, sizeof(fname), "./debug/kltimg_trans_diff_win%03d.%03d.pgm", glob_index, counter);
printf("%s\n", fname);
_KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0);
printf("iter = %d translation tracker res: %f\n", iteration, _sumAbsFloatWindow(imgdiff, width, height)/(width*height));
#endif
/* Use these windows to construct matrices */
_compute2by2GradientMatrix(gradx, grady, width, height,
&gxx, &gxy, &gyy);
_compute2by1ErrorVector(imgdiff, gradx, grady, width, height, step_factor,
&ex, &ey);
/* Using matrices, solve equation for new displacement */
status = _solveEquation(gxx, gxy, gyy, ex, ey, small, &dx, &dy);
convergence = (fabs(dx) < th && fabs(dy) < th);
*x2 += dx;
*y2 += dy;
}else{
/* affine tracker */
float ul_x = *Axx * (-hw) + *Axy * hh + *x2; /* upper left corner */
float ul_y = *Ayx * (-hw) + *Ayy * hh + *y2;
float ll_x = *Axx * (-hw) + *Axy * (-hh) + *x2; /* lower left corner */
float ll_y = *Ayx * (-hw) + *Ayy * (-hh) + *y2;
float ur_x = *Axx * hw + *Axy * hh + *x2; /* upper right corner */
float ur_y = *Ayx * hw + *Ayy * hh + *y2;
float lr_x = *Axx * hw + *Axy * (-hh) + *x2; /* lower right corner */
float lr_y = *Ayx * hw + *Ayy * (-hh) + *y2;
/* If out of bounds, exit loop */
if ( x1-hw < 0.0f || nc1-(x1+hw) < one_plus_eps ||
y1-hh < 0.0f || nr1-(y1+hh) < one_plus_eps ||
ul_x < 0.0f || nc2-(ul_x ) < one_plus_eps ||
ll_x < 0.0f || nc2-(ll_x ) < one_plus_eps ||
ur_x < 0.0f || nc2-(ur_x ) < one_plus_eps ||
lr_x < 0.0f || nc2-(lr_x ) < one_plus_eps ||
ul_y < 0.0f || nr2-(ul_y ) < one_plus_eps ||
ll_y < 0.0f || nr2-(ll_y ) < one_plus_eps ||
ur_y < 0.0f || nr2-(ur_y ) < one_plus_eps ||
lr_y < 0.0f || nr2-(lr_y ) < one_plus_eps) {
status = KLT_OOB;
break;
}
#ifdef DEBUG_AFFINE_MAPPING
counter++;
_am_computeAffineMappedImage(img1, x1, y1, 1.0, 0.0 , 0.0, 1.0, width, height, imgdiff);
aff_diff_win->data = imgdiff;
snprintf(fname, sizeof(fname), "./debug/kltimg_aff_diff_win%03d.%03d_1.pgm", glob_index, counter);
printf("%s\n", fname);
_KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0);
_am_computeAffineMappedImage(img2, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy, width, height, imgdiff);
aff_diff_win->data = imgdiff;
snprintf(fname, sizeof(fname), "./debug/kltimg_aff_diff_win%03d.%03d_2.pgm", glob_index, counter);
printf("%s\n", fname);
_KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0);
#endif
_am_computeIntensityDifferenceAffine(img1, img2, x1, y1, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy,
width, height, imgdiff);
#ifdef DEBUG_AFFINE_MAPPING
aff_diff_win->data = imgdiff;
snprintf(fname, sizeof(fname), "./debug/kltimg_aff_diff_win%03d.%03d_3.pgm", glob_index,counter);
printf("%s\n", fname);
_KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0);
printf("iter = %d affine tracker res: %f\n", iteration, _sumAbsFloatWindow(imgdiff, width, height)/(width*height));
#endif
_am_getGradientWinAffine(gradx2, grady2, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy,
width, height, gradx, grady);
switch(affine_map){
case 1:
_am_compute4by1ErrorVector(imgdiff, gradx, grady, width, height, a);
_am_compute4by4GradientMatrix(gradx, grady, width, height, T);
status = _am_gauss_jordan_elimination(T,4,a,1);
*Axx += a[0][0];
*Ayx += a[1][0];
*Ayy = *Axx;
*Axy = -(*Ayx);
dx = a[2][0];
dy = a[3][0];
break;
case 2:
_am_compute6by1ErrorVector(imgdiff, gradx, grady, width, height, a);
_am_compute6by6GradientMatrix(gradx, grady, width, height, T);
status = _am_gauss_jordan_elimination(T,6,a,1);
*Axx += a[0][0];
*Ayx += a[1][0];
*Axy += a[2][0];
*Ayy += a[3][0];
dx = a[4][0];
dy = a[5][0];
break;
}
*x2 += dx;
*y2 += dy;
/* old upper left corner - new upper left corner */
ul_x -= *Axx * (-hw) + *Axy * hh + *x2;
ul_y -= *Ayx * (-hw) + *Ayy * hh + *y2;
/* old lower left corner - new lower left corner */
ll_x -= *Axx * (-hw) + *Axy * (-hh) + *x2;
ll_y -= *Ayx * (-hw) + *Ayy * (-hh) + *y2;
/* old upper right corner - new upper right corner */
ur_x -= *Axx * hw + *Axy * hh + *x2;
ur_y -= *Ayx * hw + *Ayy * hh + *y2;
/* old lower right corner - new lower right corner */
lr_x -= *Axx * hw + *Axy * (-hh) + *x2;
lr_y -= *Ayx * hw + *Ayy * (-hh) + *y2;
#ifdef DEBUG_AFFINE_MAPPING
printf ("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",
iteration, ul_x, ul_y, ll_x, ll_y, ur_x, ur_y, lr_x, lr_y);
#endif
convergence = (fabs(dx) < th && fabs(dy) < th &&
fabs(ul_x) < th_aff && fabs(ul_y) < th_aff &&
fabs(ll_x) < th_aff && fabs(ll_y) < th_aff &&
fabs(ur_x) < th_aff && fabs(ur_y) < th_aff &&
fabs(lr_x) < th_aff && fabs(lr_y) < th_aff);
}
if (status == KLT_SMALL_DET) break;
iteration++;
#ifdef DEBUG_AFFINE_MAPPING
printf ("iter = %d, x1=%f, y1=%f, x2=%f, y2=%f, Axx=%f, Ayx=%f , Axy=%f, Ayy=%f \n",iteration, x1, y1, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy);
#endif
} while ( !convergence && iteration < max_iterations);
/*} while ( (fabs(dx)>=th || fabs(dy)>=th || (affine_map && iteration < 8) ) && iteration < max_iterations); */
_am_free_matrix(T);
_am_free_matrix(a);
/* Check whether window is out of bounds */
if (*x2-hw < 0.0f || nc2-(*x2+hw) < one_plus_eps ||
*y2-hh < 0.0f || nr2-(*y2+hh) < one_plus_eps)
status = KLT_OOB;
/* Check whether feature point has moved to much during iteration*/
if ( (*x2-old_x2) > mdd || (*y2-old_y2) > mdd )
status = KLT_OOB;
/* Check whether residue is too large */
if (status == KLT_TRACKED) {
if(!affine_map){
_computeIntensityDifference(img1, img2, x1, y1, *x2, *y2,
width, height, imgdiff);
}else{
_am_computeIntensityDifferenceAffine(img1, img2, x1, y1, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy,
width, height, imgdiff);
}
#ifdef DEBUG_AFFINE_MAPPING
printf("iter = %d final_res = %f\n", iteration, _sumAbsFloatWindow(imgdiff, width, height)/(width*height));
#endif
if (_sumAbsFloatWindow(imgdiff, width, height)/(width*height) > max_residue)
status = KLT_LARGE_RESIDUE;
}
/* Free memory */
free(imgdiff); free(gradx); free(grady);
#ifdef DEBUG_AFFINE_MAPPING
printf("iter = %d status=%d\n", iteration, status);
_KLTFreeFloatImage( aff_diff_win );
#endif
/* Return appropriate value */
return status;
}
/*
* CONSISTENCY CHECK OF FEATURES BY AFFINE MAPPING (END)
**********************************************************************/
/*********************************************************************
* KLTTrackFeatures
*
* Tracks feature points from one image to the next.
*/
void KLTTrackFeatures(
KLT_TrackingContext tc,
KLT_PixelType *img1,
KLT_PixelType *img2,
int ncols,
int nrows,
KLT_FeatureList featurelist)
{
_KLT_FloatImage tmpimg, floatimg1, floatimg2;
_KLT_Pyramid pyramid1, pyramid1_gradx, pyramid1_grady,
pyramid2, pyramid2_gradx, pyramid2_grady;
float subsampling = (float) tc->subsampling;
float xloc, yloc, xlocout, ylocout;
int val = 0;
int indx, r;
KLT_BOOL floatimg1_created = FALSE;
int i;
if (KLT_verbose >= 1) {
fprintf(stderr, "(KLT) Tracking %d features in a %d by %d image... ",
KLTCountRemainingFeatures(featurelist), ncols, nrows);
fflush(stderr);
}
/* Check window size (and correct if necessary) */
if (tc->window_width % 2 != 1) {
tc->window_width = tc->window_width+1;
KLTWarning("Tracking context's window width must be odd. "
"Changing to %d.\n", tc->window_width);
}
if (tc->window_height % 2 != 1) {
tc->window_height = tc->window_height+1;
KLTWarning("Tracking context's window height must be odd. "
"Changing to %d.\n", tc->window_height);
}
if (tc->window_width < 3) {
tc->window_width = 3;
KLTWarning("Tracking context's window width must be at least three. \n"
"Changing to %d.\n", tc->window_width);
}
if (tc->window_height < 3) {
tc->window_height = 3;
KLTWarning("Tracking context's window height must be at least three. \n"
"Changing to %d.\n", tc->window_height);
}
/* Create temporary image */
tmpimg = _KLTCreateFloatImage(ncols, nrows);
/* Process first image by converting to float, smoothing, computing */
/* pyramid, and computing gradient pyramids */
if (tc->sequentialMode && tc->pyramid_last != nullptr) {
pyramid1 = (_KLT_Pyramid) tc->pyramid_last;
pyramid1_gradx = (_KLT_Pyramid) tc->pyramid_last_gradx;
pyramid1_grady = (_KLT_Pyramid) tc->pyramid_last_grady;
if (pyramid1->ncols[0] != ncols || pyramid1->nrows[0] != nrows) {
KLTError("(KLTTrackFeatures) Size of incoming image (%d by %d) "
"is different from size of previous image (%d by %d)\n",
ncols, nrows, pyramid1->ncols[0], pyramid1->nrows[0]);
exit(1);
}
assert(pyramid1_gradx != nullptr);
assert(pyramid1_grady != nullptr);
} else {
floatimg1_created = TRUE;
floatimg1 = _KLTCreateFloatImage(ncols, nrows);
_KLTToFloatImage(img1, ncols, nrows, tmpimg);
_KLTComputeSmoothedImage(tmpimg, _KLTComputeSmoothSigma(tc), floatimg1);
pyramid1 = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels);
_KLTComputePyramid(floatimg1, pyramid1, tc->pyramid_sigma_fact);
pyramid1_gradx = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels);
pyramid1_grady = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels);
for (i = 0 ; i < tc->nPyramidLevels ; i++)
_KLTComputeGradients(pyramid1->img[i], tc->grad_sigma,
pyramid1_gradx->img[i],
pyramid1_grady->img[i]);
}
/* Do the same thing with second image */
floatimg2 = _KLTCreateFloatImage(ncols, nrows);
_KLTToFloatImage(img2, ncols, nrows, tmpimg);
_KLTComputeSmoothedImage(tmpimg, _KLTComputeSmoothSigma(tc), floatimg2);
pyramid2 = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels);
_KLTComputePyramid(floatimg2, pyramid2, tc->pyramid_sigma_fact);
pyramid2_gradx = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels);
pyramid2_grady = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels);
for (i = 0 ; i < tc->nPyramidLevels ; i++)
_KLTComputeGradients(pyramid2->img[i], tc->grad_sigma,
pyramid2_gradx->img[i],
pyramid2_grady->img[i]);
/* Write internal images */
if (tc->writeInternalImages) {
char fname[80];
for (i = 0 ; i < tc->nPyramidLevels ; i++) {
snprintf(fname, sizeof(fname), "kltimg_tf_i%d.pgm", i);
_KLTWriteFloatImageToPGM(pyramid1->img[i], fname);
snprintf(fname, sizeof(fname), "kltimg_tf_i%d_gx.pgm", i);
_KLTWriteFloatImageToPGM(pyramid1_gradx->img[i], fname);
snprintf(fname, sizeof(fname), "kltimg_tf_i%d_gy.pgm", i);
_KLTWriteFloatImageToPGM(pyramid1_grady->img[i], fname);
snprintf(fname, sizeof(fname), "kltimg_tf_j%d.pgm", i);
_KLTWriteFloatImageToPGM(pyramid2->img[i], fname);
snprintf(fname, sizeof(fname), "kltimg_tf_j%d_gx.pgm", i);
_KLTWriteFloatImageToPGM(pyramid2_gradx->img[i], fname);
snprintf(fname, sizeof(fname), "kltimg_tf_j%d_gy.pgm", i);
_KLTWriteFloatImageToPGM(pyramid2_grady->img[i], fname);
}
}
/* For each feature, do ... */
for (indx = 0 ; indx < featurelist->nFeatures ; indx++) {
/* Only track features that are not lost */
if (featurelist->feature[indx]->val >= 0) {
xloc = featurelist->feature[indx]->x;
yloc = featurelist->feature[indx]->y;
/* Transform location to coarsest resolution */
for (r = tc->nPyramidLevels - 1 ; r >= 0 ; r--) {
xloc /= subsampling; yloc /= subsampling;
}
xlocout = xloc; ylocout = yloc;
/* Beginning with coarsest resolution, do ... */
for (r = tc->nPyramidLevels - 1 ; r >= 0 ; r--) {
/* Track feature at current resolution */
xloc *= subsampling; yloc *= subsampling;
xlocout *= subsampling; ylocout *= subsampling;
val = _trackFeature(xloc, yloc,
&xlocout, &ylocout,
pyramid1->img[r],
pyramid1_gradx->img[r], pyramid1_grady->img[r],
pyramid2->img[r],
pyramid2_gradx->img[r], pyramid2_grady->img[r],
tc->window_width, tc->window_height,
tc->step_factor,
tc->max_iterations,
tc->min_determinant,
tc->min_displacement,
tc->max_residue,
tc->lighting_insensitive);
if (val==KLT_SMALL_DET || val==KLT_OOB)
break;
}
/* Record feature */
if (val == KLT_OOB) {
featurelist->feature[indx]->x = -1.0;
featurelist->feature[indx]->y = -1.0;
featurelist->feature[indx]->val = KLT_OOB;
if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img);
if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx);
if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady);
featurelist->feature[indx]->aff_img = nullptr;
featurelist->feature[indx]->aff_img_gradx = nullptr;
featurelist->feature[indx]->aff_img_grady = nullptr;
} else if (_outOfBounds(xlocout, ylocout, ncols, nrows, tc->borderx, tc->bordery)) {
featurelist->feature[indx]->x = -1.0;
featurelist->feature[indx]->y = -1.0;
featurelist->feature[indx]->val = KLT_OOB;
if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img);
if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx);
if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady);
featurelist->feature[indx]->aff_img = nullptr;
featurelist->feature[indx]->aff_img_gradx = nullptr;
featurelist->feature[indx]->aff_img_grady = nullptr;
} else if (val == KLT_SMALL_DET) {
featurelist->feature[indx]->x = -1.0;
featurelist->feature[indx]->y = -1.0;
featurelist->feature[indx]->val = KLT_SMALL_DET;
if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img);
if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx);
if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady);
featurelist->feature[indx]->aff_img = nullptr;
featurelist->feature[indx]->aff_img_gradx = nullptr;
featurelist->feature[indx]->aff_img_grady = nullptr;
} else if (val == KLT_LARGE_RESIDUE) {
featurelist->feature[indx]->x = -1.0;
featurelist->feature[indx]->y = -1.0;
featurelist->feature[indx]->val = KLT_LARGE_RESIDUE;
if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img);
if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx);
if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady);
featurelist->feature[indx]->aff_img = nullptr;
featurelist->feature[indx]->aff_img_gradx = nullptr;
featurelist->feature[indx]->aff_img_grady = nullptr;
} else if (val == KLT_MAX_ITERATIONS) {
featurelist->feature[indx]->x = -1.0;
featurelist->feature[indx]->y = -1.0;
featurelist->feature[indx]->val = KLT_MAX_ITERATIONS;
if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img);
if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx);
if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady);
featurelist->feature[indx]->aff_img = nullptr;
featurelist->feature[indx]->aff_img_gradx = nullptr;
featurelist->feature[indx]->aff_img_grady = nullptr;
} else {
featurelist->feature[indx]->x = xlocout;
featurelist->feature[indx]->y = ylocout;
featurelist->feature[indx]->val = KLT_TRACKED;
if (tc->affineConsistencyCheck >= 0 && val == KLT_TRACKED) { /*for affine mapping*/
int border = 2; /* add border for interpolation */
#ifdef DEBUG_AFFINE_MAPPING
glob_index = indx;
#endif
if(!featurelist->feature[indx]->aff_img){
/* save image and gradient for each feature at finest resolution after first successful track */
featurelist->feature[indx]->aff_img = _KLTCreateFloatImage((tc->affine_window_width+border), (tc->affine_window_height+border));
featurelist->feature[indx]->aff_img_gradx = _KLTCreateFloatImage((tc->affine_window_width+border), (tc->affine_window_height+border));
featurelist->feature[indx]->aff_img_grady = _KLTCreateFloatImage((tc->affine_window_width+border), (tc->affine_window_height+border));
_am_getSubFloatImage(pyramid1->img[0],xloc,yloc,featurelist->feature[indx]->aff_img);
_am_getSubFloatImage(pyramid1_gradx->img[0],xloc,yloc,featurelist->feature[indx]->aff_img_gradx);
_am_getSubFloatImage(pyramid1_grady->img[0],xloc,yloc,featurelist->feature[indx]->aff_img_grady);
featurelist->feature[indx]->aff_x = xloc - (int) xloc + (tc->affine_window_width+border)/2;
featurelist->feature[indx]->aff_y = yloc - (int) yloc + (tc->affine_window_height+border)/2;;
}else{
/* affine tracking */
val = _am_trackFeatureAffine(featurelist->feature[indx]->aff_x, featurelist->feature[indx]->aff_y,
&xlocout, &ylocout,
featurelist->feature[indx]->aff_img,
featurelist->feature[indx]->aff_img_gradx,
featurelist->feature[indx]->aff_img_grady,
pyramid2->img[0],
pyramid2_gradx->img[0], pyramid2_grady->img[0],
tc->affine_window_width, tc->affine_window_height,
tc->step_factor,
tc->affine_max_iterations,
tc->min_determinant,
tc->min_displacement,
tc->affine_min_displacement,
tc->affine_max_residue,
tc->lighting_insensitive,
tc->affineConsistencyCheck,
tc->affine_max_displacement_differ,
&featurelist->feature[indx]->aff_Axx,
&featurelist->feature[indx]->aff_Ayx,
&featurelist->feature[indx]->aff_Axy,
&featurelist->feature[indx]->aff_Ayy
);
featurelist->feature[indx]->val = val;
if(val != KLT_TRACKED){
featurelist->feature[indx]->x = -1.0;
featurelist->feature[indx]->y = -1.0;
featurelist->feature[indx]->aff_x = -1.0;
featurelist->feature[indx]->aff_y = -1.0;
/* free image and gradient for lost feature */
_KLTFreeFloatImage(featurelist->feature[indx]->aff_img);
_KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx);
_KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady);
featurelist->feature[indx]->aff_img = nullptr;
featurelist->feature[indx]->aff_img_gradx = nullptr;
featurelist->feature[indx]->aff_img_grady = nullptr;
}else{
/*featurelist->feature[indx]->x = xlocout;*/
/*featurelist->feature[indx]->y = ylocout;*/
}
}
}
}
}
}
if (tc->sequentialMode) {
tc->pyramid_last = pyramid2;
tc->pyramid_last_gradx = pyramid2_gradx;
tc->pyramid_last_grady = pyramid2_grady;
} else {
_KLTFreePyramid(pyramid2);
_KLTFreePyramid(pyramid2_gradx);
_KLTFreePyramid(pyramid2_grady);
}
/* Free memory */
_KLTFreeFloatImage(tmpimg);
if (floatimg1_created) _KLTFreeFloatImage(floatimg1);
_KLTFreeFloatImage(floatimg2);
_KLTFreePyramid(pyramid1);
_KLTFreePyramid(pyramid1_gradx);
_KLTFreePyramid(pyramid1_grady);
if (KLT_verbose >= 1) {
fprintf(stderr, "\n\t%d features successfully tracked.\n",
KLTCountRemainingFeatures(featurelist));
if (tc->writeInternalImages)
fprintf(stderr, "\tWrote images to 'kltimg_tf*.pgm'.\n");
fflush(stderr);
}
}