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 }