source: level2/competencies/FacET/src/FastMatchTemplate.cpp @ 234

Revision 74, 11.0 KB checked in by nik, 11 years ago (diff)

FacET import

Line 
1/*! $Id: FastMatchTemplate.cpp 5 2009-03-12 22:30:56Z mw $
2 *  \file FastMatchTemplate.cpp
3 * 
4 *  This program is distributed in the hope that it will be useful,
5 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
6 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7 *  GNU General Public License for more details.
8 *
9 * \author Tristen Georgiou (Copyright \f$\copyright \f$ 2005 Tristen Georgiou)
10 *
11 * minor changes by Marcin Namysl
12 * 2008.06.28
13 */
14
15/***************************************************************************
16 *            FastMatchTemplate.cc
17 *
18 * 
19 *  Copyright  2005  Tristen Georgiou
20 *  tristen_georgiou@hotmail.com
21 ****************************************************************************/
22
23/*
24 *  This program is free software; you can redistribute it and/or modify
25 *  it under the terms of the GNU General Public License as published by
26 *  the Free Software Foundation; either version 2 of the License, or
27 *  (at your option) any later version.
28 *
29 *  This program is distributed in the hope that it will be useful,
30 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
31 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32 *  GNU General Public License for more details.
33 *
34 *  You should have received a copy of the GNU General Public License
35 *  along with this program; if not, write to the Free Software
36 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 */
38
39#include <iostream>
40#include <cmath>
41#include "FastMatchTemplate.h"
42
43using std::cout;
44using std::cerr;
45
46//=============================================================================
47// Assumes that source image exists and numDownPyrs > 1, no ROIs for either
48//  image, and both images have the same depth and number of channels
49bool
50FastMatchTemplate( const IplImage&  source,
51                   const IplImage&  target,
52                   vector<CvPoint>* foundPointsList,
53                   vector<double>*  confidencesList,
54                   int              matchPercentage,
55                   bool             findMultipleTargets,
56                   int              numMaxima,
57                   int              numDownPyrs,
58                   int              searchExpansion )
59{
60  // make sure that the template image is smaller than the source
61  if( target.width > source.width || target.height > source.height )
62  {
63    // Source image must be larger than target image.
64    return false;
65  }
66 
67  if( source.depth != target.depth )
68  {
69    // Source image and target image must have same depth.
70    return false;
71  }
72 
73  if( source.nChannels != target.nChannels )
74  {
75    // Source image and target image must have same number of channels.
76    return false;
77  }
78 
79  CvSize sourceSize = cvGetSize( &source );
80  CvSize targetSize = cvGetSize( &target );
81 
82  int depth = source.depth;
83  int numChannels = source.nChannels;
84 
85  // create copies of the images to modify
86  IplImage* copyOfSource = cvCloneImage( &source );
87  IplImage* copyOfTarget = cvCloneImage( &target );
88 
89  // down pyramid the images
90  for( int ii = 0; ii < numDownPyrs; ii++ )
91  {
92    // start with the source image
93    sourceSize.width /= 2;
94    sourceSize.height /= 2;
95   
96    IplImage* smallSource = NULL;
97    smallSource = cvCreateImage( sourceSize, depth, numChannels );
98    cvPyrDown( copyOfSource, smallSource, CV_GAUSSIAN_5x5 );
99   
100    // prepare for next loop, if any
101    cvReleaseImage( &copyOfSource );
102    copyOfSource = cvCloneImage( smallSource );
103    cvReleaseImage( &smallSource );
104   
105    // next, do the target   
106    targetSize.width /= 2;
107    targetSize.height /= 2;
108   
109    IplImage* smallTarget = NULL;
110    smallTarget = cvCreateImage( targetSize, depth, numChannels );
111    cvPyrDown( copyOfTarget, smallTarget, CV_GAUSSIAN_5x5 );
112   
113    // prepare for next loop, if any
114    cvReleaseImage( &copyOfTarget );
115    copyOfTarget = cvCloneImage( smallTarget );
116    cvReleaseImage( &smallTarget );
117  }
118 
119  // perform the match on the shrunken images
120  CvSize smallTargetSize = cvGetSize( copyOfTarget );
121  CvSize smallSourceSize = cvGetSize( copyOfSource );
122 
123  CvSize resultSize;
124  resultSize.width = smallSourceSize.width - smallTargetSize.width + 1;
125  resultSize.height = smallSourceSize.height - smallTargetSize.height + 1;
126 
127  IplImage* result = cvCreateImage( resultSize, IPL_DEPTH_32F, 1 );
128 
129  cvMatchTemplate( copyOfSource, copyOfTarget, result, CV_TM_CCORR_NORMED );
130
131  // release memory we don't need anymore
132  cvReleaseImage( &copyOfSource );
133  cvReleaseImage( &copyOfTarget );
134 
135  // find the top match locations
136  CvPoint* locations = NULL;
137  MultipleMaxLoc( *result, &locations, numMaxima );
138 
139  cvReleaseImage( &result );
140 
141  // search the large images at the returned locations
142  sourceSize = cvGetSize( &source );
143  targetSize = cvGetSize( &target );
144 
145  // create a copy of the source in order to adjust its ROI for searching
146  IplImage* searchImage = cvCloneImage( &source );
147  for( int currMax = 0; currMax < numMaxima; currMax++ )
148  {
149    // transform the point to its corresponding point in the larger image
150
151    locations[currMax].x *= ( int )pow( (float) 2, (int) numDownPyrs ); // GC(?)
152    locations[currMax].y *= ( int )pow( (float) 2, (int) numDownPyrs );
153    // locations[currMax].x *= ( int )pow( 2, numDownPyrs );
154    // locations[currMax].y *= ( int )pow( 2, numDownPyrs );
155
156    locations[currMax].x += targetSize.width / 2;
157    locations[currMax].y += targetSize.height / 2;
158   
159    const CvPoint& searchPoint = locations[currMax];
160   
161    // if we are searching for multiple targets and we have found a target or
162    //  multiple targets, we don't want to search in the same location(s) again
163    if( findMultipleTargets && !foundPointsList->empty() )
164    {
165      bool thisTargetFound = false;
166     
167      int numPoints = foundPointsList->size();
168      for( int currPoint = 0; currPoint < numPoints; currPoint++ )
169      {
170        const CvPoint& foundPoint = ( *foundPointsList )[currPoint];
171        if( abs( searchPoint.x - foundPoint.x ) <= searchExpansion * 2 &&
172            abs( searchPoint.y - foundPoint.y ) <= searchExpansion * 2 )
173        {
174          thisTargetFound = true;
175          break;
176        }
177      }
178     
179      // if the current target has been found, continue onto the next point
180      if( thisTargetFound )
181      {
182        continue;
183      }
184    }
185   
186    // set the source image's ROI to slightly larger than the target image,
187    //  centred at the current point
188    CvRect searchRoi;
189    searchRoi.x = searchPoint.x - ( target.width ) / 2 - searchExpansion;
190    searchRoi.y = searchPoint.y - ( target.height ) / 2 - searchExpansion;
191    searchRoi.width = target.width + searchExpansion * 2;
192    searchRoi.height = target.height + searchExpansion * 2;
193   
194    // make sure ROI doesn't extend outside of image
195    if( searchRoi.x < 0 )
196    {
197      searchRoi.x = 0;
198    }
199    if( searchRoi.y < 0 )
200    {
201      searchRoi.y = 0;
202    }
203    if( ( searchRoi.x + searchRoi.width ) > ( sourceSize.width - 1 ) )
204    {
205      int numPixelsOver
206        = ( searchRoi.x + searchRoi.width ) - ( sourceSize.width - 1 );
207     
208      searchRoi.width -= numPixelsOver;
209    }
210    if( ( searchRoi.y + searchRoi.height ) > ( sourceSize.height - 1 ) )
211    {
212      int numPixelsOver
213        = ( searchRoi.y + searchRoi.height ) - ( sourceSize.height - 1 );
214     
215      searchRoi.height -= numPixelsOver;
216    }
217   
218    cvSetImageROI( searchImage, searchRoi );
219   
220    // perform the search on the large images
221    resultSize.width = searchRoi.width - target.width + 1;
222    resultSize.height = searchRoi.height - target.height + 1;
223   
224    result = cvCreateImage( resultSize, IPL_DEPTH_32F, 1 );
225   
226    cvMatchTemplate( searchImage, &target, result, CV_TM_CCORR_NORMED );
227    cvResetImageROI( searchImage );
228   
229    // find the best match location
230    double minValue, maxValue;
231    CvPoint minLoc, maxLoc;
232    cvMinMaxLoc( result, &minValue, &maxValue, &minLoc, &maxLoc );
233    maxValue *= 100;
234   
235    // transform point back to original image
236    maxLoc.x += searchRoi.x + target.width / 2;
237    maxLoc.y += searchRoi.y + target.height / 2;
238   
239    cvReleaseImage( &result );
240   
241    if( maxValue >= matchPercentage )
242    {
243      // add the point to the list
244      foundPointsList->push_back( maxLoc );
245      confidencesList->push_back( maxValue );
246     
247      // if we are only looking for a single target, we have found it, so we
248      //  can return
249      if( !findMultipleTargets )
250      {
251        break;
252      }
253    }
254  }
255 
256  if( foundPointsList->empty() )
257  {
258    // Target was not found to required confidence of "matchPercentage".
259  }
260
261  delete [] locations;
262  cvReleaseImage( &searchImage );
263 
264  return true;
265}
266
267//=============================================================================
268
269void MultipleMaxLoc( const IplImage& image,
270                     CvPoint**       locations,
271                     int             numMaxima )
272{
273  // initialize input variable locations
274  *locations = new CvPoint[numMaxima];
275 
276  // create array for tracking maxima
277
278  double *maxima = new double[numMaxima]; // GC
279  // double maxima[numMaxima];
280
281  for( int i = 0; i < numMaxima; i++ )
282  {
283    maxima[i] = 0.0;
284  }
285 
286  // extract the raw data for analysis
287  float* data;
288  int step;
289  CvSize size;
290 
291  cvGetRawData( &image, ( uchar** )&data, &step, &size );
292 
293  step /= sizeof( data[0] );
294 
295  for( int y = 0; y < size.height; y++, data += step )
296  {
297    for( int x = 0; x < size.width; x++ )
298    {
299      // insert the data value into the arry if it is greater than any of the
300      //  other array values, and bump the other values below it, down
301      for( int j = 0; j < numMaxima; j++ )
302      {
303        if( data[x] > maxima[j] )
304        {
305          // move the maxima down
306          for( int k = numMaxima - 1; k > j; k-- )
307          {
308            maxima[k] = maxima[k-1];
309            ( *locations )[k] = ( *locations )[k-1];
310          }
311         
312          // insert the value
313          maxima[j] = ( double )data[x];
314          ( *locations )[j].x = x;
315          ( *locations )[j].y = y;
316          break;
317        }
318      }
319    }
320  }
321  delete [] maxima;  // GC
322}
323
324//=============================================================================
325
326void
327DrawFoundTargets( IplImage*              image,
328                  const CvSize&          size,
329                  const vector<CvPoint>& pointsList,
330                  const vector<double>&  confidencesList,
331                  int                    red,
332                  int                    green,
333                  int                    blue )
334{
335  int numPoints = pointsList.size();
336  for( int currPoint = 0; currPoint < numPoints; currPoint++ )
337  {
338    const CvPoint& point = pointsList[currPoint];
339   
340    // draw a circle at the center
341    cvCircle( image, point, 2, CV_RGB( red, green, blue ) );
342   
343    // draw a rectangle around the found target
344    CvPoint topLeft;
345    topLeft.x = point.x - size.width / 2;
346    topLeft.y = point.y - size.height / 2;
347   
348    CvPoint bottomRight;
349    bottomRight.x = point.x + size.width / 2;
350    bottomRight.y = point.y + size.height / 2;
351   
352    cvRectangle( image, topLeft, bottomRight, CV_RGB( red, green, blue ) );
353  }
354}
Note: See TracBrowser for help on using the repository browser.