FastMatchTemplate.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002  *            FastMatchTemplate.cpp
00003  *
00004  *
00005  *  Copyright  2010  Tristen Georgiou
00006  *  tristen_georgiou@hotmail.com
00007  ****************************************************************************/
00008 
00009 /*
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00023  */
00024 
00025 #include <math.h>
00026 #include "fast_match_template/FastMatchTemplate.h"
00027 
00028 //=============================================================================
00029 // Assumes that source image exists and numDownPyrs > 1, no ROIs for either
00030 //  image, and both images have the same depth and number of channels
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     // make sure that the template image is smaller than the source
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     // create copies of the images to modify
00066     Mat copyOfSource = source.clone();
00067     Mat copyOfTarget = target.clone();
00068 
00069     // down pyramid the images
00070     for(int ii = 0; ii < numDownPyrs; ii++)
00071     {
00072         // start with the source image
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         // prepare for next loop, if any
00080         copyOfSource = smallSource.clone();
00081 
00082         // next, do the target
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         // prepare for next loop, if any
00090         copyOfTarget = smallTarget.clone();
00091     }
00092 
00093     // perform the match on the shrunken images
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     // find the top match locations
00105     Point* locations = NULL;
00106     MultipleMaxLoc(result, &locations, numMaxima);
00107 
00108     // search the large images at the returned locations
00109     sourceSize = source.size();
00110     targetSize = target.size();
00111 
00112     // create a copy of the source in order to adjust its ROI for searching
00113     for(int currMax = 0; currMax < numMaxima; currMax++)
00114     {
00115         // transform the point to its corresponding point in the larger image
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         // if we are searching for multiple targets and we have found a target or
00124         //  multiple targets, we don't want to search in the same location(s) again
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             // if the current target has been found, continue onto the next point
00142             if(thisTargetFound)
00143             {
00144                 continue;
00145             }
00146         }
00147 
00148         // set the source image's ROI to slightly larger than the target image,
00149         //  centred at the current point
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         // make sure ROI doesn't extend outside of image
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         // perform the search on the large images
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         // find the best match location
00193         double minValue, maxValue;
00194         Point minLoc, maxLoc;
00195         minMaxLoc(result, &minValue, &maxValue, &minLoc, &maxLoc);
00196         maxValue *= 100;
00197 
00198         // transform point back to original image
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             // add the point to the list
00205             foundPointsList->push_back(maxLoc);
00206             confidencesList->push_back(maxValue);
00207 
00208             // if we are only looking for a single target, we have found it, so we
00209             //  can return
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     // initialize input variable locations
00235     *locations = new Point[numMaxima];
00236 
00237     // create array for tracking maxima
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     // extract the raw data for analysis
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             // insert the data value into the array if it is greater than any of the
00254             //  other array values, and bump the other values below it, down
00255             for(int j = 0; j < numMaxima; j++)
00256             {
00257                 // require at least 50% confidence on the sub-sampled image
00258                 // in order to make this as fast as possible
00259                 if(data > 0.5 && data > maxima[j])
00260                 {
00261                     // move the maxima down
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                     // insert the value
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         // write the confidences to stdout
00298         printf("\nTarget found at (%d, %d), with confidence = %3.3f %%.\n",
00299             point.x,
00300             point.y,
00301             confidencesList[currPoint]);
00302 
00303         // draw a circle at the center
00304         circle(*image, point, 2, CV_RGB(red, green, blue));
00305 
00306         // draw a rectangle around the found target
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 }


fast_match_template
Author(s): Tristen Georgiou, Dejan Pangercic (for ROS and modifications)
autogenerated on Mon Oct 6 2014 08:23:34