00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #include <new>
00047
00048 #include "KLTTracker.h"
00049
00050 #include "Image/ByteImage.h"
00051 #include "Image/ImageProcessor.h"
00052 #include "Math/Math2d.h"
00053
00054 #include <stdio.h>
00055 #include <float.h>
00056 #include <math.h>
00057
00058
00059
00060
00061
00062
00063 #define KLT_ITERATIONS 20
00064
00065
00066
00067
00068
00069
00070
00071 CKLTTracker::CKLTTracker(int width_, int height_, int nLevels, int nHalfWindowSize) : width(width_), height(height_), m_nLevels(nLevels), m_nHalfWindowSize(nHalfWindowSize)
00072 {
00073 m_ppPyramidI = new CByteImage*[nLevels + 1];
00074 m_ppPyramidJ = new CByteImage*[nLevels + 1];
00075
00076 int w = width;
00077 int h = height;
00078
00079 int i;
00080
00081
00082 for (i = 0; i <= nLevels; i++)
00083 {
00084 m_ppPyramidI[i] = new CByteImage(w, h, CByteImage::eGrayScale);
00085 m_ppPyramidJ[i] = new CByteImage(w, h, CByteImage::eGrayScale);
00086
00087 w /= 2;
00088 h /= 2;
00089 }
00090
00091
00092 m_pScaleFactors = new float[m_nLevels + 1];
00093 for (i = m_nLevels; i >= 0; i--)
00094 m_pScaleFactors[i] = 1.0f / powf(2.0f, (float) i);
00095
00096 m_bInitialized = false;
00097 }
00098
00099 CKLTTracker::~CKLTTracker()
00100 {
00101 for (int i = 0; i <= m_nLevels; i++)
00102 {
00103 delete m_ppPyramidI[i];
00104 delete m_ppPyramidJ[i];
00105 }
00106
00107 delete [] m_ppPyramidI;
00108 delete [] m_ppPyramidJ;
00109
00110 delete [] m_pScaleFactors;
00111 }
00112
00113
00114
00115
00116
00117
00118 bool CKLTTracker::Track(const CByteImage *pImage, const Vec2d *pPoints, int nPoints, Vec2d *pResultPoints)
00119 {
00120 if (pImage->type != CByteImage::eGrayScale)
00121 {
00122 printf("error: image must be of type eGrayScale for CKLTTracker::Track\n");
00123 return false;
00124 }
00125
00126 if (!m_bInitialized)
00127 {
00128
00129 ImageProcessor::CopyImage(pImage, m_ppPyramidI[0]);
00130
00131
00132 for (int i = 1; i <= m_nLevels; i++)
00133 ImageProcessor::Resize(m_ppPyramidI[i - 1], m_ppPyramidI[i]);
00134
00135 m_bInitialized = true;
00136 }
00137
00138 int i;
00139
00140
00141 ImageProcessor::CopyImage(pImage, m_ppPyramidJ[0]);
00142
00143
00144 for (i = 1; i <= m_nLevels; i++)
00145 ImageProcessor::Resize(m_ppPyramidJ[i - 1], m_ppPyramidJ[i]);
00146
00147 const int nWindowSize = 2 * m_nHalfWindowSize + 1;
00148 const int nWindowSizePlus2 = nWindowSize + 2;
00149
00150 Vec2d d;
00151
00152 float *IX = new float[nWindowSizePlus2 * nWindowSizePlus2];
00153 float *IY = new float[nWindowSizePlus2 * nWindowSizePlus2];
00154 float *pGrayValues = new float[nWindowSizePlus2 * nWindowSizePlus2];
00155
00156
00157 for (i = 0; i < nPoints; i++)
00158 {
00159 const float ux = pPoints[i].x;
00160 const float uy = pPoints[i].y;
00161
00162 if (ux < 0.0f && uy < 0.0f)
00163 {
00164 Math2d::SetVec(pResultPoints[i], -1.0f, -1.0f);
00165 continue;
00166 }
00167
00168 Vec2d g = { 0.0f, 0.0f };
00169
00170 for (int l = m_nLevels; l >= 0; l--)
00171 {
00172 const int w = m_ppPyramidI[l]->width;
00173 const int h = m_ppPyramidI[l]->height;
00174
00175 const float px_ = m_pScaleFactors[l] * ux;
00176 const float py_ = m_pScaleFactors[l] * uy;
00177
00178 const int px = int(floorf(px_));
00179 const int py = int(floorf(py_));
00180
00181 if (px - m_nHalfWindowSize < 1 || px + m_nHalfWindowSize + 3 > w || py - m_nHalfWindowSize < 1 || py + m_nHalfWindowSize + 3 > h)
00182 {
00183 Math2d::MulVecScalar(g, 2.0f, g);
00184 continue;
00185 }
00186
00187 const unsigned char *pixelsI = m_ppPyramidI[l]->pixels;
00188
00189 {
00190 const int diff = w - nWindowSizePlus2;
00191
00192 const float dx = px_ - floorf(px_);
00193 const float dy = py_ - floorf(py_);
00194
00195 const float f00 = (1.0f - dx) * (1.0f - dy);
00196 const float f10 = dx * (1.0f - dy);
00197 const float f01 = (1.0f - dx) * dy;
00198 const float f11 = dx * dy;
00199
00200 for (int j = nWindowSizePlus2, offset = (py - m_nHalfWindowSize - 1) * w + px - m_nHalfWindowSize - 1, offset2 = 0; j; j--, offset += diff)
00201 for (int jj = nWindowSizePlus2; jj; jj--, offset++, offset2++)
00202 pGrayValues[offset2] = f00 * pixelsI[offset] + f10 * pixelsI[offset + 1] + f01 * pixelsI[offset + w] + f11 * pixelsI[offset + w + 1];
00203 }
00204
00205 float gxx = 0.0f, gxy = 0.0f, gyy = 0.0f;
00206
00207 for (int j = nWindowSize, offset = nWindowSizePlus2 + 1; j; j--, offset += 2)
00208 for (int jj = nWindowSize; jj; jj--, offset++)
00209 {
00210 const float ix = pGrayValues[offset + 1] - pGrayValues[offset - 1];
00211 const float iy = pGrayValues[offset + nWindowSizePlus2] - pGrayValues[offset - nWindowSizePlus2];
00212
00213 IX[offset] = ix;
00214 IY[offset] = iy;
00215
00216 gxx += ix * ix;
00217 gyy += iy * iy;
00218 gxy += ix * iy;
00219 }
00220
00221 Vec2d v = { 0.0f, 0.0f };
00222
00223 if (fabsf(gxx * gyy - gxy * gxy) > FLT_EPSILON)
00224 {
00225 const Mat2d G = { gxx, gxy, gxy, gyy };
00226 Mat2d G_;
00227 Math2d::Invert(G, G_);
00228
00229 const unsigned char *pixelsJ = m_ppPyramidJ[l]->pixels;
00230
00231 for (int k = 0; k < KLT_ITERATIONS; k++)
00232 {
00233 const float dxJ = g.x + v.x;
00234 const float dyJ = g.y + v.y;
00235
00236 const int xb = int(floorf(px_ + dxJ));
00237 const int yb = int(floorf(py_ + dyJ));
00238
00239 if (xb - m_nHalfWindowSize < 1 || xb + m_nHalfWindowSize + 3 >= w || yb - m_nHalfWindowSize < 1 || yb + m_nHalfWindowSize + 3 >= h)
00240 break;
00241
00242 float bx = 0.0f, by = 0.0f;
00243
00244 {
00245 const int diff = w - nWindowSize;
00246
00247 const float dx = px_ + dxJ - floorf(px_ + dxJ);
00248 const float dy = py_ + dyJ - floorf(py_ + dyJ);
00249
00250 const float f00 = (1.0f - dx) * (1.0f - dy);
00251 const float f10 = dx * (1.0f - dy);
00252 const float f01 = (1.0f - dx) * dy;
00253 const float f11 = dx * dy;
00254
00255 for (int j = nWindowSize, offset = (yb - m_nHalfWindowSize) * w + xb - m_nHalfWindowSize, offset2 = nWindowSizePlus2 + 1; j; j--, offset += diff, offset2 += 2)
00256 for (int jj = nWindowSize; jj; jj--, offset++, offset2++)
00257 {
00258 const float dI = pGrayValues[offset2] - (f00 * pixelsJ[offset] + f10 * pixelsJ[offset + 1] + f01 * pixelsJ[offset + w] + f11 * pixelsJ[offset + w + 1]);
00259
00260 bx += IX[offset2] * dI;
00261 by += IY[offset2] * dI;
00262 }
00263 }
00264
00265 const Vec2d b = { bx, by };
00266
00267 Vec2d n;
00268 Math2d::MulMatVec(G_, b, n);
00269
00270 Math2d::MulVecScalar(n, 2.0f, n);
00271
00272 Math2d::AddToVec(v, n);
00273
00274 if (Math2d::SquaredLength(n) < 0.03f)
00275 break;
00276 }
00277 }
00278
00279 Math2d::SetVec(d, v);
00280
00281 if (l != 0)
00282 {
00283 g.x = 2.0f * (g.x + d.x);
00284 g.y = 2.0f * (g.y + d.y);
00285 }
00286 }
00287
00288 Math2d::AddToVec(d, g);
00289
00290 const float x = ux + d.x;
00291 const float y = uy + d.y;
00292
00293 const int x_ = int(floorf(x));
00294 const int y_ = int(floorf(y));
00295
00296 if (x_ > m_nHalfWindowSize && x_ < width - m_nHalfWindowSize - 3 && y_ > m_nHalfWindowSize && y_ < height - m_nHalfWindowSize - 3)
00297 Math2d::SetVec(pResultPoints[i], x, y);
00298 else
00299 Math2d::SetVec(pResultPoints[i], -1.0f, -1.0f);
00300 }
00301
00302
00303 CByteImage **ppTemp = m_ppPyramidI;
00304 m_ppPyramidI = m_ppPyramidJ;
00305 m_ppPyramidJ = ppTemp;
00306
00307
00308 delete [] IX;
00309 delete [] IY;
00310 delete [] pGrayValues;
00311
00312 return true;
00313 }
00314