LKTracker.h
Go to the documentation of this file.
00001 /* Copyright (C) 2012 Christian Lutz, Thorsten Engesser
00002  * 
00003  * This file is part of motld
00004  * 
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation, either version 3 of the License, or
00008  * (at your option) any later version.
00009  * 
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #ifndef LKTracker_H
00020 #define LKTracker_H
00021   
00022 #include "Matrix.h"
00023 #include <vector>
00024 #include <algorithm>
00025 #include <math.h>
00026 
00027 #define KERNEL_WIDTH 2
00028 #define MAX_PYRAMID_LEVEL 5
00029 
00030 #define LK_ITERATIONS 30
00031 
00032 #define GRID_SIZE_X 10
00033 #define GRID_SIZE_Y 10
00034 
00035 
00036 #define GRID_PADDING 0.15
00037 
00038 #define N_CORNERNESS_POINTS 0
00039 
00040 #define GRID_MARGIN 3
00041 #define KERNEL_SIZE ((KERNEL_WIDTH*2+1)*(KERNEL_WIDTH*2+1))
00042 
00043 namespace motld {
00044   
00047   class LKTracker
00048   {
00049   public:
00051   LKTracker(int width, int height) : ivWidth(width), ivHeight(height), 
00052       ivPrevPyramid(NULL), ivIndex(1) {};
00054     ~LKTracker() {delete ivPrevPyramid;};
00056     void initFirstFrame(unsigned char * img);
00058     void initFirstFrame(const Matrix& img);
00064     void processFrame(const Matrix& curImage, std::vector<ObjectBox>& bbox, std::vector<bool>& isDefined); 
00066     bool processFrame(const Matrix& curImage, ObjectBox& bbox, bool dotracking = true); 
00068     const std::vector<int> * getDebugPoints() const { return &ivDebugPoints; };
00069   
00070   private:
00072     struct LKPyramid
00073     {
00074       std::vector<Matrix> I,Ix,Iy;
00075       LKPyramid(){};
00076       LKPyramid(int nLevels){
00077         I = std::vector<Matrix>(nLevels);
00078         Ix = std::vector<Matrix>(nLevels);
00079         Iy = std::vector<Matrix>(nLevels); 
00080       };
00081     };
00083     struct Point2D
00084     {
00085       float x, y;
00086     };
00087     int ivWidth;
00088     int ivHeight;
00089     LKPyramid* ivPrevPyramid;
00090     int ivIndex;
00091     std::vector<int> ivDebugPoints;
00094     inline float median(std::vector<float> * vec, bool compSqrt = false) const;
00099     inline double NCC(const Matrix& aMatrix, const Matrix& bMatrix) const;
00103     inline void pyramidLK(const LKPyramid *prevPyramid, const LKPyramid *curPyramid, 
00104                           const Point2D *prevPts, Point2D *nextPts, 
00105                           char *status, int count) const;
00106   };
00107 
00108 
00109 
00110 /**************************************************************************************************
00111  * IMPLEMENTATION                                                                                 *
00112  **************************************************************************************************/ 
00113   void LKTracker::initFirstFrame(unsigned char * img)
00114   {
00115     Matrix curImage(ivWidth, ivHeight);
00116     curImage.copyFromCharArray(img);
00117     initFirstFrame(curImage);
00118   }
00119   void LKTracker::initFirstFrame(const Matrix& img)
00120   {
00121     ivPrevPyramid = new LKPyramid(MAX_PYRAMID_LEVEL+1);
00122     ivPrevPyramid->I[0] = img;
00123     for (int i = 0; i <= MAX_PYRAMID_LEVEL; ++i)
00124     {
00125       ivPrevPyramid->I[i].scharrDerivativeX(ivPrevPyramid->Ix[i]);
00126       ivPrevPyramid->I[i].scharrDerivativeY(ivPrevPyramid->Iy[i]);
00127       if (i < MAX_PYRAMID_LEVEL)
00128         ivPrevPyramid->I[i].halfSizeImage(ivPrevPyramid->I[i+1]);
00129 #if DEBUG > 1
00130       char filename[255];
00131       sprintf(filename, "output/img%05d-%d.ppm", 0, i);
00132       ivPrevPyramid->I[i].writeToPGM(filename);
00133 #endif    
00134     }
00135 #if DEBUG
00136     std::cout << "#1 LKTracker: initialized, image size = (" << img.xSize() << "," << img.ySize() << ")" << std::endl;
00137 #endif
00138   }
00139 
00140   bool LKTracker::processFrame(const Matrix& curImage, ObjectBox& bbox, bool dotracking)
00141   {
00142     std::vector<ObjectBox> boxes;
00143     std::vector<bool> isDefined;
00144     boxes.push_back(bbox);
00145     isDefined.push_back(dotracking);
00146     processFrame(curImage, boxes, isDefined);
00147     bbox = boxes[0];
00148     return isDefined[0];
00149   }
00150 
00151   void LKTracker::processFrame(const Matrix& curImage, std::vector<ObjectBox>& bbox, std::vector<bool>& isDefined)
00152   {
00153     int nobs = bbox.size();
00154     if (nobs > 0 && !ivPrevPyramid)
00155       initFirstFrame(curImage);
00156 #if DEBUG
00157     std::cout << "#" << (ivIndex+1) << " LKTracker: ";
00158 #endif
00159     ivDebugPoints.clear();
00160     LKPyramid* curPyramid = new LKPyramid(MAX_PYRAMID_LEVEL+1);
00161     curPyramid->I[0] = curImage;
00162     for (int i = 0; i < MAX_PYRAMID_LEVEL; ++i)
00163     {
00164       curPyramid->I[i].halfSizeImage(curPyramid->I[i+1]);
00165 #if DEBUG > 1
00166       char filename[255];
00167       sprintf(filename, "output/img%05d-%d.ppm", ivIndex, i);
00168       curPyramid->I[i].writeToPGM(filename);
00169 #endif  
00170     }
00171   
00172 #pragma omp parallel sections
00173     {
00174 #pragma omp section
00175       {
00176         //#pragma omp parallel for
00177         for (int i = 0; i <= MAX_PYRAMID_LEVEL; ++i)
00178           curPyramid->I[i].scharrDerivativeX(curPyramid->Ix[i]);
00179       }
00180 #pragma omp section
00181       {
00182         //#pragma omp parallel for
00183         for (int i = 0; i <= MAX_PYRAMID_LEVEL; ++i)
00184           curPyramid->I[i].scharrDerivativeY(curPyramid->Iy[i]);
00185       }
00186     }
00187   
00188 #if DEBUG > 1
00189     Matrix debugFlow(ivWidth, ivHeight, 0);
00190 #endif
00191       
00192     // loop over all object boxes
00193     for (int obj = 0; obj < nobs; obj++)
00194     {
00195 #if DEBUG
00196       std::cout << "\tObj" << obj << ": ";
00197 #endif
00198       if (isDefined[obj])
00199       {
00200         float oldwidth = bbox[obj].width, 
00201           oldheight = bbox[obj].height,
00202           oldcenterx = bbox[obj].x + oldwidth*0.5, 
00203           oldcentery = bbox[obj].y + oldheight*0.5;
00204 
00205         Point2D points0[N_CORNERNESS_POINTS + GRID_SIZE_X*GRID_SIZE_Y]; // points to be tracked
00206         Point2D points1[N_CORNERNESS_POINTS + GRID_SIZE_X*GRID_SIZE_Y]; // result of forward step
00207         Point2D points2[N_CORNERNESS_POINTS + GRID_SIZE_X*GRID_SIZE_Y]; // result of backward step
00208         char status[N_CORNERNESS_POINTS + GRID_SIZE_X*GRID_SIZE_Y];
00209         float fb[N_CORNERNESS_POINTS + GRID_SIZE_X*GRID_SIZE_Y];
00210         float ncc[N_CORNERNESS_POINTS + GRID_SIZE_X*GRID_SIZE_Y];
00211         int count = 0;
00212   
00213         // take points on a regular grid
00214         float stepX = oldwidth * (1 - 2*GRID_PADDING) / (GRID_SIZE_X-1), 
00215           stepY = oldheight * (1 - 2*GRID_PADDING) / (GRID_SIZE_Y-1);
00216         for (int y = 0; y < GRID_SIZE_Y; ++y)
00217           for (int x = 0; x < GRID_SIZE_X; ++x)
00218           {
00219             points0[count].x = bbox[obj].x + GRID_PADDING * oldwidth  + x*stepX;
00220             points0[count].y = bbox[obj].y + GRID_PADDING * oldheight + y*stepY;
00221             status[count] = 1;
00222             count++;
00223           }
00224     
00225         // ALTERNATIVE (or supplementary): compute interesting points (with high minimum eigen values) within bounding box
00226 #if N_CORNERNESS_POINTS > 0
00227         int xstart = std::max(0, (int)(bbox[obj].x)), 
00228           xend = std::min(ivWidth, (int)(bbox[obj].x + oldwidth + 1)),
00229           ystart = std::max(0, (int)(bbox[obj].y)),
00230           yend = std::min(ivHeight, (int)(bbox[obj].y + oldheight + 1)),
00231           xsize = xend - xstart,
00232           ysize = yend - ystart;      
00233         Matrix Ix2 (xsize, ysize);
00234         Matrix IxIy(xsize, ysize);
00235         Matrix Iy2 (xsize, ysize);
00236         Matrix cornerness(xsize, ysize, 0);
00237         for (int y = ystart; y < yend; y++)
00238           for (int x = xstart; x < xend; x++)
00239           {
00240             Ix2(x-xstart,y-ystart)  = ivPrevPyramid->Ix[0](x,y) * ivPrevPyramid->Ix[0](x,y);
00241             IxIy(x-xstart,y-ystart) = ivPrevPyramid->Ix[0](x,y) * ivPrevPyramid->Iy[0](x,y);
00242             Iy2(x-xstart,y-ystart)  = ivPrevPyramid->Iy[0](x,y) * ivPrevPyramid->Iy[0](x,y);
00243           }      
00244         Ix2.gaussianSmooth(2.0, 3);
00245         IxIy.gaussianSmooth(2.0, 3);
00246         Iy2.gaussianSmooth(2.0, 3);
00247       
00248         std::vector<float> cns;
00249         for (int y = GRID_MARGIN; y < ysize - GRID_MARGIN; y++)
00250           for (int x = GRID_MARGIN; x < xsize - GRID_MARGIN; x++)
00251           {
00252             cornerness(x,y) = (Ix2(x,y) + Iy2(x,y)) / 2.0 
00253               - sqrt(((Ix2(x,y) + Iy2(x,y)) / 2.0) * ((Ix2(x,y) + Iy2(x,y)) / 2.0)
00254                      - Ix2(x,y) * Iy2(x,y) + IxIy(x,y)*IxIy(x,y));
00255             if (cornerness(x,y) > 1.0)
00256               cns.push_back(cornerness(x, y));
00257           }
00258         float threshold = 0;
00259         if (cns.size() > N_CORNERNESS_POINTS)
00260         {
00261           std::nth_element(cns.begin(),cns.end() - N_CORNERNESS_POINTS, cns.end());
00262           threshold = *(cns.end() - N_CORNERNESS_POINTS);
00263         }
00264         for (int y = GRID_MARGIN; y < ysize - GRID_MARGIN; y++)
00265           for (int x = GRID_MARGIN; x < xsize - GRID_MARGIN; x++)
00266           {
00267             if (cornerness(x,y) > threshold && count < N_CORNERNESS_POINTS)
00268             {
00269               points0[count].x = x + xstart;
00270               points0[count].y = y + ystart;
00271               status[count] = 1;
00272               count++;
00273             }
00274           }      
00275 #endif //N_CORNERNESS_POINTS > 0
00276   
00277         // Track points forward
00278         pyramidLK(ivPrevPyramid, curPyramid, points0, points1, status, count);
00279 
00280 #if DEBUG > 1
00281         int nfwd = 0;
00282         for (int i = 0; i<count; ++i)
00283           if (status[i] > 0)
00284             ++nfwd;
00285         std::cout << "\t#fwd=" << nfwd;
00286 #endif
00287   
00288         // Track remaining points backward
00289         pyramidLK(curPyramid, ivPrevPyramid, points1, points2, status, count);
00290   
00291         // Compute FB-error and NCC
00292         std::vector<float> fbs, nccs;
00293         int nbwd = 0;
00294         //#pragma omp parallel for reduction(+:nbwd)
00295         for (int i = 0; i < count; ++i)
00296         {
00297           if (status[i] > 0)
00298           {
00299             fb[i] = sqrt((points2[i].x - points0[i].x) * (points2[i].x - points0[i].x) 
00300                          + (points2[i].y - points0[i].y) * (points2[i].y - points0[i].y));
00301             //#pragma omp critical
00302             fbs.push_back(fb[i]);
00303             Matrix mA = ivPrevPyramid->I[0].getRectSubPix(points0[i].x, points0[i].y, 10, 10);
00304             Matrix mB = curImage.getRectSubPix(points2[i].x, points2[i].y, 10, 10);
00305             ncc[i] = NCC(mA, mB);
00306             //#pragma omp critical
00307             nccs.push_back(ncc[i]);
00308             ++nbwd;
00309           }
00310         }
00311   
00312         float medFB = median(&fbs),
00313           medNCC = median(&nccs);
00314   
00315 #if DEBUG > 1
00316         std::cout << ", #bwd=" << nbwd;
00317         std::cout << "  \tmedFB=" << medFB << "\tmedNCC=" << medNCC;
00318 #endif
00319   
00320         //#pragma omp parallel for
00321         for (int i = 0; i < count; ++i)
00322         {
00323           if (status[i] > 0)
00324           {
00325             if (fb[i] > medFB || fb[i] > 8  || ncc[i] < medNCC)
00326               status[i] = 0;
00327             else 
00328               //#pragma omp critical
00329             {
00330               ivDebugPoints.push_back(round(points1[i].x)); 
00331               ivDebugPoints.push_back(round(points1[i].y)); 
00332             }
00333           }
00334         }
00335           
00336         // Compute median flow
00337         std::vector<float> deltax;
00338         std::vector<float> deltay;
00339         int num = 0;
00340         for (int i = 0; i < count; ++i)
00341         {
00342           if (status[i] > 0)
00343           {
00344             deltax.push_back(points1[i].x - points0[i].x);
00345             deltay.push_back(points1[i].y - points0[i].y);
00346             ++num;
00347 #if DEBUG > 1
00348             debugFlow.drawLine(points0[i].x, points0[i].y, points1[i].x, points1[i].y, 255);
00349             debugFlow.drawCross(points1[i].x, points1[i].y, 255);
00350 #endif
00351           }
00352         }
00353         if (num < 4)
00354         {
00355 #if DEBUG
00356           std::cout << "n=" << num << " => FAILURE: lost object" << std::endl;
00357 #endif
00358           isDefined[obj] = false;
00359           continue;
00360         }
00361         //else
00362 
00363         float dx = median(&deltax),
00364           dy = median(&deltay);  
00365       
00366         // Remove outliers
00367         /*
00368           for (int i = 0; i < count; ++i)
00369           if (status[i] > 0)
00370           if ((points1[i].x - points0[i].x - dx) * (points1[i].x - points0[i].x - dx)
00371           + (points1[i].y - points0[i].y - dy) * (points1[i].y - points0[i].y - dy) > 5*5)
00372           {
00373           status[i] = 0;
00374           num--;
00375           }
00376         */
00377   
00378         // Resize bounding box (compute median elongation factor)
00379         float s = 1;
00380         if (num >= 16){
00381           std::vector<float> d2;
00382           float dpx,dpy,ddx,ddy;
00383           for (int i = 0; i < count; ++i)
00384             if (status[i] > 0)
00385               for (int j = i + 1; j < count; ++j)
00386                 if (status[j] > 0)
00387                 {
00388                   ddx = points0[i].x - points0[j].x;
00389                   ddy = points0[i].y - points0[j].y;
00390                   dpx = points1[i].x - points1[j].x;
00391                   dpy = points1[i].y - points1[j].y;
00392                   d2.push_back((dpx*dpx + dpy*dpy) / (ddx*ddx + ddy*ddy));
00393                 }
00394 
00395           if (!d2.empty())
00396           {
00397             s = median(&d2, true);
00398             //upper bound for enlargement
00399             //s = std::min(1.1, s);
00400           }
00401         }
00402         //delete[] points0; delete[] points1; delete[] points2;
00403         //delete[] status; delete[] fb; delete[] ncc;
00404 
00405         float  centerx = oldcenterx + dx, 
00406           centery = oldcentery + dy;
00407 
00408         bbox[obj].x = (centerx - s * oldwidth * 0.5);
00409         bbox[obj].y = (centery - s * oldheight * 0.5);
00410         bbox[obj].width  = s * oldwidth;
00411         bbox[obj].height = s * oldheight;
00412 #if DEBUG
00413         std::cout << "n = " << num 
00414                   << ", new BB: (" << round(bbox[obj].x) << "," << round(bbox[obj].y) << ", "
00415                   << round(bbox[obj].width) << "," << round(bbox[obj].height) << ")";
00416         //<< ")\ts=" << s << std::endl;
00417 #endif  
00418       }else{
00419 #if DEBUG
00420         std::cout << "not defined";
00421 #endif
00422       }
00423     } // end for(obj)
00424   
00425 #if DEBUG > 1
00426     char filename[255];
00427     sprintf(filename, "output/flow%05d.ppm", ivIndex);
00428     writePPM(filename, ivPrevPyramid->I[0], curImage, debugFlow);
00429 #endif
00430   
00431     delete ivPrevPyramid;
00432     ivPrevPyramid = curPyramid;
00433     ++ivIndex;
00434   }
00435  
00436   inline void LKTracker::pyramidLK(const LKPyramid *prevPyramid, const LKPyramid *curPyramid, 
00437                                    const Point2D *prevPts, Point2D *nextPts, 
00438                                    char *status, int count) const
00439   {
00440     for (int l = MAX_PYRAMID_LEVEL; l >= 0; --l)
00441     {
00442       int xSize = prevPyramid->I[l].xSize(), 
00443         ySize = prevPyramid->I[l].ySize();
00444 #if DEBUG > 2
00445       std::cout << "l=" << l << ", Size=(" << xSize << "," << ySize << ")" << std::endl;
00446 #endif
00447     
00448 #pragma omp parallel for default(shared)
00449       for (int i = 0; i < count; i++)
00450       {
00451         if (status[i] > 0)
00452         {
00453           //initial guess from previous iteration
00454           if (l == MAX_PYRAMID_LEVEL)
00455           {
00456             nextPts[i].x = prevPts[i].x;
00457             nextPts[i].y = prevPts[i].y;
00458           }else{
00459             nextPts[i].x *= 2.0;
00460             nextPts[i].y *= 2.0;
00461           }
00462           float px = prevPts[i].x * 1.0/(1<<l), py = prevPts[i].y * 1.0/(1<<l);
00463           int px0 = (int)px, py0 = (int)py;
00464           float pxa = px - px0, pya = py - py0;
00465 #if DEBUG > 2
00466           std::cout << "  p=(" << px0 << "+" << pxa << ", " << py0 << "+" << pya  << ")" << std::endl;
00467 #endif
00468           if (px < KERNEL_WIDTH || py < KERNEL_WIDTH || px >= xSize-KERNEL_WIDTH-1 
00469               || py >= ySize-KERNEL_WIDTH-1)
00470           {
00471             if (l >= MAX_PYRAMID_LEVEL-1){
00472               // Give it another try one level above
00473               nextPts[i].x = px;
00474               nextPts[i].y = py;
00475             }else{
00476               status[i] = 0;
00477             }
00478             //continue;        
00479           }else{ //omp parallel for does not like continues...
00480             // Compute components of spatial gradient Matrix G = [Gx2 Gxy; Gxy Gy2]
00481             float Gx2 = 0, Gxy = 0, Gy2 = 0;
00482             for (int x = px0-KERNEL_WIDTH; x <= px0+KERNEL_WIDTH+1; ++x)
00483             {
00484               float factor = (x == px0-KERNEL_WIDTH ? (1-pxa) : (x == px0+KERNEL_WIDTH+1 ? pxa : 1));
00485               for (int y = py0-KERNEL_WIDTH; y <= py0+KERNEL_WIDTH+1; ++y)
00486               {
00487                 factor *= (y == py0-KERNEL_WIDTH ? (1-pya) : (y == py0+KERNEL_WIDTH+1 ? pya : 1));
00488                 Gx2 += factor * prevPyramid->Ix[l](x,y)*prevPyramid->Ix[l](x,y); //Ix2(x,y)
00489                 Gxy += factor * prevPyramid->Ix[l](x,y)*prevPyramid->Iy[l](x,y); //IxIy(x,y)
00490                 Gy2 += factor * prevPyramid->Iy[l](x,y)*prevPyramid->Iy[l](x,y); //Iy2(x,y)
00491               }
00492             }    
00493             double denom = Gx2*Gy2 - Gxy*Gxy;
00494 #if DEBUG > 2
00495             std::cout << "\tGx2 = " << Gx2 << "\tGxy = " << Gxy << "\tGy2 = " << Gy2 << "\tdenom = " << denom << std::endl;
00496 #endif
00497             if (denom <= 1e-30)
00498             {
00499               status[i] = 0;
00500               //continue;        
00501             }else{          
00502               //iteratively compute additional flow on this pyramid level
00503               for (int k = 1; k <= LK_ITERATIONS; k++)
00504               {
00505                 //float qx = px + tp->fx, qy = py + tp->fy;
00506                 float qx = nextPts[i].x, qy = nextPts[i].y;
00507                 if (qx < KERNEL_WIDTH || qy < KERNEL_WIDTH || qx >= xSize-KERNEL_WIDTH-1 || qy >= ySize-KERNEL_WIDTH-1)
00508                 {  //lost tracking point
00509                   if (l >= MAX_PYRAMID_LEVEL-1){
00510                     //give it another try one level above
00511                     nextPts[i].x = px;
00512                     nextPts[i].y = py;
00513                   }else{
00514                     status[i] = 0;
00515                   }
00516                   break;
00517                 }
00518                 int vx0 = (int)qx - px0, vy0 = (int)qy - py0;
00519                 float vxa = fmod(qx, 1), vya = fmod(qx, 1);
00520           
00521                 //compute image missmatch vector b = [bx; by]
00522                 float bx = 0, by = 0;
00523                 for (int x = px0 - KERNEL_WIDTH; x <= px0 + KERNEL_WIDTH; ++x)
00524                 {
00525                   for (int y = py0 - KERNEL_WIDTH; y <= py0 + KERNEL_WIDTH; ++y)
00526                   {
00527                     float dIk = (1-pxa) * ((1-pya)*prevPyramid->I[l](x, y) + pya*prevPyramid->I[l](x, y+1))
00528                       + pxa * ((1-pya)*prevPyramid->I[l](x+1, y) + pya*prevPyramid->I[l](x+1, y+1))
00529                       - (1-vxa) * ((1-vya)*curPyramid->I[l](x+vx0, y+vy0) + vya*curPyramid->I[l](x+vx0, y+vy0+1))
00530                       - vxa * ((1-vya)*curPyramid->I[l](x+vx0+1, y+vy0) + vya*curPyramid->I[l](x+vx0+1, y+vy0+1));
00531                     bx += dIk * ((1-pxa) * ((1-pya)*prevPyramid->Ix[l](x, y) + pya*prevPyramid->Ix[l](x, y+1)) 
00532                                  + pxa * ((1-pya)*prevPyramid->Ix[l](x+1, y) + pya*prevPyramid->Ix[l](x+1, y+1))); 
00533                     by += dIk * ((1-pxa) * ((1-pya)*prevPyramid->Iy[l](x, y) + pya*prevPyramid->Iy[l](x, y+1)) 
00534                                  + pxa * ((1-pya)*prevPyramid->Iy[l](x+1, y) + pya*prevPyramid->Iy[l](x+1, y+1))); 
00535                   }
00536                 }    
00537                 float dx = (bx*Gy2 - by*Gxy) / denom,
00538                   dy = (by*Gx2 - bx*Gxy) / denom;
00539                 nextPts[i].x += dx;
00540                 nextPts[i].y += dy;
00541 #if DEBUG > 2
00542                 std::cout << "\tf=(" << (nextPts[i].x - prevPts[i].x) << "," << (nextPts[i].y - prevPts[i].y) << ")" << std::endl;
00543 #endif
00544                         
00545                 if (fabs(dx) > 3.5 || fabs(dy) > 3.5)
00546                 {  //remove point because of unstable drifting..
00547                   if (l >= 1){
00548                     nextPts[i].x = px;
00549                     nextPts[i].y = py;
00550                   }else{
00551                     status[i] = 0;
00552                   }
00553                   break;
00554                 }
00555               } //end for k
00556             }
00557           }
00558         } //end if (status > 0)
00559       } //end for each tp
00560     } //end for l
00561   }
00562 
00563 //compute median of a vector
00564 //side effect: changes order of vector-elements!
00565   inline float LKTracker::median(std::vector<float> * vec, bool compSqrt) const
00566   {
00567     int n = vec->size();
00568     if (n == 0)
00569       return 0;
00570     if (n % 2) //odd: return (sqrt of) middle element
00571     { 
00572       std::nth_element(vec->begin(), vec->begin() + n/2, vec->end());
00573       return compSqrt ? sqrt(*(vec->begin() + n/2)) : *(vec->begin() + n/2);
00574     }else{     //even: return average (sqrt) of the two middle elements
00575       std::nth_element(vec->begin(), vec->begin() + (n/2-1), vec->end());
00576       float tmp = (compSqrt ? sqrt(*(vec->begin() + (n/2-1))) : *(vec->begin() + (n/2-1)));
00577       std::nth_element(vec->begin() + n/2, vec->begin() + n/2, vec->end());
00578       return 0.5 * (tmp + (compSqrt ? sqrt(*(vec->begin() + n/2)) : *(vec->begin() + n/2)));
00579     }
00580     return 0;
00581   }
00582 
00583   inline double LKTracker::NCC(const Matrix& aMatrix, const Matrix& bMatrix) const
00584   {
00585     int size = aMatrix.size();
00586     if (size != bMatrix.size()){
00587       std::cerr << "ncc called for matrices with unequal size!" << std::endl;
00588       return 0;
00589     }    
00590     float aMean = aMatrix.avg(), bMean = bMatrix.avg();
00591     double sumA = 0, sumB = 0, sumDiff = 0;
00592     for (int i = 0; i < size; ++i)
00593     {
00594       sumA += (aMatrix.data()[i] - aMean) * (aMatrix.data()[i] - aMean);
00595       sumB += (bMatrix.data()[i] - bMean) * (bMatrix.data()[i] - bMean);
00596       sumDiff += (aMatrix.data()[i] - aMean) * (bMatrix.data()[i] - bMean);
00597     }
00598     if (sumA == 0 || sumB == 0)
00599       return 0;
00600     return sumDiff / sqrt(sumA*sumB); //+1)/2.0;
00601   }
00602 }
00603 
00604 #endif 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines


motld
Author(s): Jost Tobias Springenberg, Jan Wuelfing
autogenerated on Wed Dec 26 2012 16:24:49