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 #include <math.h>
00026 #include "fast_match_template/FastMatchTemplate.h"
00027 
00028 
00029 
00030 
00031 bool
00032 FastMatchTemplate( const Mat&      source,
00033                    const Mat&      target,
00034                    vector<Point>*  foundPointsList,
00035                    vector<double>* confidencesList,
00036                    int             matchPercentage,
00037                    bool            findMultipleTargets,
00038                    int             numMaxima,
00039                    int             numDownPyrs,
00040                    int             searchExpansion )
00041 {
00042     
00043     if(target.size().width > source.size().width ||
00044         target.size().height > source.size().height)
00045     {
00046         printf( "\nSource image must be larger than target image.\n" );
00047         return false;
00048     }
00049 
00050     if(source.depth() != target.depth())
00051     {
00052         printf( "\nSource image and target image must have same depth.\n" );
00053         return false;
00054     }
00055 
00056     if(source.channels() != target.channels())
00057     {
00058         printf("\nSource image and target image must have same number of channels.\n" );
00059         return false;
00060     }
00061 
00062     Size sourceSize = source.size();
00063     Size targetSize = target.size();
00064 
00065     
00066     Mat copyOfSource = source.clone();
00067     Mat copyOfTarget = target.clone();
00068 
00069     
00070     for(int ii = 0; ii < numDownPyrs; ii++)
00071     {
00072         
00073         sourceSize.width  = (sourceSize.width  + 1) / 2;
00074         sourceSize.height = (sourceSize.height + 1) / 2;
00075 
00076         Mat smallSource(sourceSize, source.type());
00077         pyrDown(copyOfSource, smallSource);
00078 
00079         
00080         copyOfSource = smallSource.clone();
00081 
00082         
00083         targetSize.width  = (targetSize.width  + 1) / 2;
00084         targetSize.height = (targetSize.height + 1) / 2;
00085 
00086         Mat smallTarget(targetSize, target.type());
00087         pyrDown(copyOfTarget, smallTarget);
00088 
00089         
00090         copyOfTarget = smallTarget.clone();
00091     }
00092 
00093     
00094     Size smallTargetSize = copyOfTarget.size();
00095     Size smallSourceSize = copyOfSource.size();
00096 
00097     Size resultSize;
00098     resultSize.width = smallSourceSize.width - smallTargetSize.width + 1;
00099     resultSize.height = smallSourceSize.height - smallTargetSize.height + 1;
00100 
00101     Mat result(resultSize, CV_32FC1);
00102     matchTemplate(copyOfSource, copyOfTarget, result, CV_TM_CCOEFF_NORMED);
00103 
00104     
00105     Point* locations = NULL;
00106     MultipleMaxLoc(result, &locations, numMaxima);
00107 
00108     
00109     sourceSize = source.size();
00110     targetSize = target.size();
00111 
00112     
00113     for(int currMax = 0; currMax < numMaxima; currMax++)
00114     {
00115         
00116         locations[currMax].x *= (int)pow(2.0f, numDownPyrs);
00117         locations[currMax].y *= (int)pow(2.0f, numDownPyrs);
00118         locations[currMax].x += targetSize.width / 2;
00119         locations[currMax].y += targetSize.height / 2;
00120 
00121         const Point& searchPoint = locations[currMax];
00122 
00123         
00124         
00125         if(findMultipleTargets && !foundPointsList->empty())
00126         {
00127             bool thisTargetFound = false;
00128 
00129             int numPoints = foundPointsList->size();
00130             for(int currPoint = 0; currPoint < numPoints; currPoint++)
00131             {
00132                 const Point& foundPoint = (*foundPointsList)[currPoint];
00133                 if(abs(searchPoint.x - foundPoint.x) <= searchExpansion * 2 &&
00134                     abs(searchPoint.y - foundPoint.y) <= searchExpansion * 2)
00135                 {
00136                     thisTargetFound = true;
00137                     break;
00138                 }
00139             }
00140 
00141             
00142             if(thisTargetFound)
00143             {
00144                 continue;
00145             }
00146         }
00147 
00148         
00149         
00150         Rect searchRoi;
00151         searchRoi.x = searchPoint.x - (target.size().width) / 2 - searchExpansion;
00152         searchRoi.y = searchPoint.y - (target.size().height) / 2 - searchExpansion;
00153         searchRoi.width = target.size().width + searchExpansion * 2;
00154         searchRoi.height = target.size().height + searchExpansion * 2;
00155 
00156         
00157         if(searchRoi.x < 0)
00158         {
00159             searchRoi.x = 0;
00160         }
00161 
00162         if(searchRoi.y < 0)
00163         {
00164             searchRoi.y = 0;
00165         }
00166 
00167         if((searchRoi.x + searchRoi.width) > (sourceSize.width - 1))
00168         {
00169             int numPixelsOver
00170                 = (searchRoi.x + searchRoi.width) - (sourceSize.width - 1);
00171 
00172             searchRoi.width -= numPixelsOver;
00173         }
00174 
00175         if((searchRoi.y + searchRoi.height) > (sourceSize.height - 1))
00176         {
00177             int numPixelsOver
00178                 = (searchRoi.y + searchRoi.height) - (sourceSize.height - 1);
00179 
00180             searchRoi.height -= numPixelsOver;
00181         }
00182 
00183         Mat searchImage = Mat(source, searchRoi);
00184 
00185         
00186         resultSize.width = searchRoi.width - target.size().width + 1;
00187         resultSize.height = searchRoi.height - target.size().height + 1;
00188 
00189         result = Mat(resultSize, CV_32FC1);
00190         matchTemplate(searchImage, target, result, CV_TM_CCOEFF_NORMED);
00191 
00192         
00193         double minValue, maxValue;
00194         Point minLoc, maxLoc;
00195         minMaxLoc(result, &minValue, &maxValue, &minLoc, &maxLoc);
00196         maxValue *= 100;
00197 
00198         
00199         maxLoc.x += searchRoi.x + target.size().width / 2;
00200         maxLoc.y += searchRoi.y + target.size().height / 2;
00201 
00202         if(maxValue >= matchPercentage)
00203         {
00204             
00205             foundPointsList->push_back(maxLoc);
00206             confidencesList->push_back(maxValue);
00207 
00208             
00209             
00210             if(!findMultipleTargets)
00211             {
00212                 break;
00213             }
00214         }
00215     }
00216 
00217     if(foundPointsList->empty())
00218     {
00219         printf( "\nTarget was not found to required confidence of %d.\n",
00220             matchPercentage );
00221     }
00222 
00223     delete [] locations;
00224 
00225     return true;
00226 }
00227 
00228 
00229 
00230 void MultipleMaxLoc(const Mat& image,
00231                     Point**    locations,
00232                     int        numMaxima)
00233 {
00234     
00235     *locations = new Point[numMaxima];
00236 
00237     
00238     float* maxima = new float[numMaxima];
00239     for(int i = 0; i < numMaxima; i++)
00240     {
00241         maxima[i] = 0.0;
00242     }
00243 
00244     Size size = image.size();
00245 
00246     
00247     for(int y = 0; y < size.height; y++)
00248     {
00249         for(int x = 0; x < size.width; x++)
00250         {
00251             float data = image.at<float>(y, x);
00252 
00253             
00254             
00255             for(int j = 0; j < numMaxima; j++)
00256             {
00257                 
00258                 
00259                 if(data > 0.5 && data > maxima[j])
00260                 {
00261                     
00262                     for(int k = numMaxima - 1; k > j; k--)
00263                     {
00264                         maxima[k] = maxima[k-1];
00265                         (*locations)[k] = ( *locations )[k-1];
00266                     }
00267 
00268                     
00269                     maxima[j] = data;
00270                     (*locations)[j].x = x;
00271                     (*locations)[j].y = y;
00272                     break;
00273                 }
00274             }
00275         }
00276     }
00277 
00278     delete [] maxima;
00279 }
00280 
00281 
00282 
00283 void
00284 DrawFoundTargets(Mat*                  image,
00285                  const Size&           size,
00286                  const vector<Point>&  pointsList,
00287                  const vector<double>& confidencesList,
00288                  int                   red,
00289                  int                   green,
00290                  int                   blue)
00291 {
00292     int numPoints = pointsList.size();
00293     for(int currPoint = 0; currPoint < numPoints; currPoint++)
00294     {
00295         const Point& point = pointsList[currPoint];
00296 
00297         
00298         printf("\nTarget found at (%d, %d), with confidence = %3.3f %%.\n",
00299             point.x,
00300             point.y,
00301             confidencesList[currPoint]);
00302 
00303         
00304         circle(*image, point, 2, CV_RGB(red, green, blue));
00305 
00306         
00307         Point topLeft;
00308         topLeft.x = point.x - size.width / 2;
00309         topLeft.y = point.y - size.height / 2;
00310 
00311         Point bottomRight;
00312         bottomRight.x = point.x + size.width / 2;
00313         bottomRight.y = point.y + size.height / 2;
00314 
00315         rectangle(*image, topLeft, bottomRight, CV_RGB(red, green, blue));
00316     }
00317 }