Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of gr-peach-opencv-project-sd-card by
templmatch.cpp
00001 /*M/////////////////////////////////////////////////////////////////////////////////////// 00002 // 00003 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 00004 // 00005 // By downloading, copying, installing or using the software you agree to this license. 00006 // If you do not agree to this license, do not download, install, 00007 // copy or use the software. 00008 // 00009 // 00010 // Intel License Agreement 00011 // For Open Source Computer Vision Library 00012 // 00013 // Copyright (C) 2000, Intel Corporation, all rights reserved. 00014 // Third party copyrights are property of their respective owners. 00015 // 00016 // Redistribution and use in source and binary forms, with or without modification, 00017 // are permitted provided that the following conditions are met: 00018 // 00019 // * Redistribution's of source code must retain the above copyright notice, 00020 // this list of conditions and the following disclaimer. 00021 // 00022 // * Redistribution's in binary form must reproduce the above copyright notice, 00023 // this list of conditions and the following disclaimer in the documentation 00024 // and/or other materials provided with the distribution. 00025 // 00026 // * The name of Intel Corporation may not be used to endorse or promote products 00027 // derived from this software without specific prior written permission. 00028 // 00029 // This software is provided by the copyright holders and contributors "as is" and 00030 // any express or implied warranties, including, but not limited to, the implied 00031 // warranties of merchantability and fitness for a particular purpose are disclaimed. 00032 // In no event shall the Intel Corporation or contributors be liable for any direct, 00033 // indirect, incidental, special, exemplary, or consequential damages 00034 // (including, but not limited to, procurement of substitute goods or services; 00035 // loss of use, data, or profits; or business interruption) however caused 00036 // and on any theory of liability, whether in contract, strict liability, 00037 // or tort (including negligence or otherwise) arising in any way out of 00038 // the use of this software, even if advised of the possibility of such damage. 00039 // 00040 //M*/ 00041 00042 #include "precomp.hpp" 00043 #include "opencl_kernels_imgproc.hpp" 00044 00045 ////////////////////////////////////////////////// matchTemplate ////////////////////////////////////////////////////////// 00046 00047 namespace cv 00048 { 00049 00050 #ifdef HAVE_OPENCL 00051 00052 /////////////////////////////////////////////////// CCORR ////////////////////////////////////////////////////////////// 00053 00054 enum 00055 { 00056 SUM_1 = 0, SUM_2 = 1 00057 }; 00058 00059 static bool extractFirstChannel_32F(InputArray _image, OutputArray _result, int cn) 00060 { 00061 int depth = _image.depth(); 00062 00063 ocl::Device dev = ocl::Device::getDefault(); 00064 int pxPerWIy = (dev.isIntel() && (dev.type() & ocl::Device::TYPE_GPU)) ? 4 : 1; 00065 00066 ocl::Kernel k("extractFirstChannel", ocl::imgproc::match_template_oclsrc, format("-D FIRST_CHANNEL -D T1=%s -D cn=%d -D PIX_PER_WI_Y=%d", 00067 ocl::typeToStr(depth), cn, pxPerWIy)); 00068 if (k.empty()) 00069 return false; 00070 00071 UMat image = _image.getUMat(); 00072 UMat result = _result.getUMat(); 00073 00074 00075 size_t globalsize[2] = {(size_t)result.cols, ((size_t)result.rows+pxPerWIy-1)/pxPerWIy}; 00076 return k.args(ocl::KernelArg::ReadOnlyNoSize(image), ocl::KernelArg::WriteOnly(result)).run( 2, globalsize, NULL, false); 00077 } 00078 00079 static bool sumTemplate(InputArray _src, UMat & result) 00080 { 00081 int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); 00082 int wdepth = CV_32F, wtype = CV_MAKE_TYPE(wdepth, cn); 00083 size_t wgs = ocl::Device::getDefault().maxWorkGroupSize(); 00084 00085 int wgs2_aligned = 1; 00086 while (wgs2_aligned < (int)wgs) 00087 wgs2_aligned <<= 1; 00088 wgs2_aligned >>= 1; 00089 00090 char cvt[40]; 00091 ocl::Kernel k("calcSum", ocl::imgproc::match_template_oclsrc, 00092 format("-D CALC_SUM -D T=%s -D T1=%s -D WT=%s -D cn=%d -D convertToWT=%s -D WGS=%d -D WGS2_ALIGNED=%d", 00093 ocl::typeToStr(type), ocl::typeToStr(depth), ocl::typeToStr(wtype), cn, 00094 ocl::convertTypeStr(depth, wdepth, cn, cvt), 00095 (int)wgs, wgs2_aligned)); 00096 if (k.empty()) 00097 return false; 00098 00099 UMat src = _src.getUMat(); 00100 result.create(1, 1, CV_32FC1); 00101 00102 ocl::KernelArg srcarg = ocl::KernelArg::ReadOnlyNoSize(src), 00103 resarg = ocl::KernelArg::PtrWriteOnly(result); 00104 00105 k.args(srcarg, src.cols, (int)src.total(), resarg); 00106 00107 size_t globalsize = wgs; 00108 return k.run(1, &globalsize, &wgs, false); 00109 } 00110 00111 static bool useNaive(Size size) 00112 { 00113 int dft_size = 18; 00114 return size.height < dft_size && size.width < dft_size; 00115 } 00116 00117 struct ConvolveBuf 00118 { 00119 Size result_size; 00120 Size block_size; 00121 Size user_block_size; 00122 Size dft_size; 00123 00124 UMat image_spect, templ_spect, result_spect; 00125 UMat image_block, templ_block, result_data; 00126 00127 void create(Size image_size, Size templ_size); 00128 }; 00129 00130 void ConvolveBuf::create(Size image_size, Size templ_size) 00131 { 00132 result_size = Size(image_size.width - templ_size.width + 1, 00133 image_size.height - templ_size.height + 1); 00134 00135 const double blockScale = 4.5; 00136 const int minBlockSize = 256; 00137 00138 block_size.width = cvRound(result_size.width*blockScale); 00139 block_size.width = std::max( block_size.width, minBlockSize - templ_size.width + 1 ); 00140 block_size.width = std::min( block_size.width, result_size.width ); 00141 block_size.height = cvRound(templ_size.height*blockScale); 00142 block_size.height = std::max( block_size.height, minBlockSize - templ_size.height + 1 ); 00143 block_size.height = std::min( block_size.height, result_size.height ); 00144 00145 dft_size.width = std::max(getOptimalDFTSize(block_size.width + templ_size.width - 1), 2); 00146 dft_size.height = getOptimalDFTSize(block_size.height + templ_size.height - 1); 00147 if( dft_size.width <= 0 || dft_size.height <= 0 ) 00148 CV_Error( CV_StsOutOfRange, "the input arrays are too big" ); 00149 00150 // recompute block size 00151 block_size.width = dft_size.width - templ_size.width + 1; 00152 block_size.width = std::min( block_size.width, result_size.width); 00153 block_size.height = dft_size.height - templ_size.height + 1; 00154 block_size.height = std::min( block_size.height, result_size.height ); 00155 00156 image_block.create(dft_size, CV_32F); 00157 templ_block.create(dft_size, CV_32F); 00158 result_data.create(dft_size, CV_32F); 00159 00160 image_spect.create(dft_size.height, dft_size.width / 2 + 1, CV_32FC2); 00161 templ_spect.create(dft_size.height, dft_size.width / 2 + 1, CV_32FC2); 00162 result_spect.create(dft_size.height, dft_size.width / 2 + 1, CV_32FC2); 00163 00164 // Use maximum result matrix block size for the estimated DFT block size 00165 block_size.width = std::min(dft_size.width - templ_size.width + 1, result_size.width); 00166 block_size.height = std::min(dft_size.height - templ_size.height + 1, result_size.height); 00167 } 00168 00169 static bool convolve_dft(InputArray _image, InputArray _templ, OutputArray _result) 00170 { 00171 ConvolveBuf buf; 00172 CV_Assert(_image.type() == CV_32F); 00173 CV_Assert(_templ.type() == CV_32F); 00174 00175 buf.create(_image.size(), _templ.size()); 00176 _result.create(buf.result_size, CV_32F); 00177 00178 UMat image = _image.getUMat(); 00179 UMat templ = _templ.getUMat(); 00180 00181 UMat result = _result.getUMat(); 00182 00183 Size& block_size = buf.block_size; 00184 Size& dft_size = buf.dft_size; 00185 00186 UMat& image_block = buf.image_block; 00187 UMat& templ_block = buf.templ_block; 00188 UMat& result_data = buf.result_data; 00189 00190 UMat& image_spect = buf.image_spect; 00191 UMat& templ_spect = buf.templ_spect; 00192 UMat& result_spect = buf.result_spect; 00193 00194 UMat templ_roi = templ; 00195 copyMakeBorder(templ_roi, templ_block, 0, templ_block.rows - templ_roi.rows, 0, 00196 templ_block.cols - templ_roi.cols, BORDER_ISOLATED); 00197 00198 dft(templ_block, templ_spect, 0, templ.rows); 00199 00200 // Process all blocks of the result matrix 00201 for (int y = 0; y < result.rows; y += block_size.height) 00202 { 00203 for (int x = 0; x < result.cols; x += block_size.width) 00204 { 00205 Size image_roi_size(std::min(x + dft_size.width, image.cols) - x, 00206 std::min(y + dft_size.height, image.rows) - y); 00207 Rect roi0(x, y, image_roi_size.width, image_roi_size.height); 00208 00209 UMat image_roi(image, roi0); 00210 00211 copyMakeBorder(image_roi, image_block, 0, image_block.rows - image_roi.rows, 00212 0, image_block.cols - image_roi.cols, BORDER_ISOLATED); 00213 00214 dft(image_block, image_spect, 0); 00215 00216 mulSpectrums(image_spect, templ_spect, result_spect, 0, true); 00217 00218 dft(result_spect, result_data, cv::DFT_INVERSE | cv::DFT_REAL_OUTPUT | cv::DFT_SCALE); 00219 00220 Size result_roi_size(std::min(x + block_size.width, result.cols) - x, 00221 std::min(y + block_size.height, result.rows) - y); 00222 00223 Rect roi1(x, y, result_roi_size.width, result_roi_size.height); 00224 Rect roi2(0, 0, result_roi_size.width, result_roi_size.height); 00225 00226 UMat result_roi(result, roi1); 00227 UMat result_block(result_data, roi2); 00228 00229 result_block.copyTo(result_roi); 00230 } 00231 } 00232 return true; 00233 } 00234 00235 static bool convolve_32F(InputArray _image, InputArray _templ, OutputArray _result) 00236 { 00237 _result.create(_image.rows() - _templ.rows() + 1, _image.cols() - _templ.cols() + 1, CV_32F); 00238 00239 if (_image.channels() == 1) 00240 return(convolve_dft(_image, _templ, _result)); 00241 else 00242 { 00243 UMat image = _image.getUMat(); 00244 UMat templ = _templ.getUMat(); 00245 UMat result_(image.rows-templ.rows+1,(image.cols-templ.cols+1)*image.channels(), CV_32F); 00246 bool ok = convolve_dft(image.reshape(1), templ.reshape(1), result_); 00247 if (ok==false) 00248 return false; 00249 UMat result = _result.getUMat(); 00250 return (extractFirstChannel_32F(result_, _result, _image.channels())); 00251 } 00252 } 00253 00254 static bool matchTemplateNaive_CCORR(InputArray _image, InputArray _templ, OutputArray _result) 00255 { 00256 int type = _image.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); 00257 int wdepth = CV_32F, wtype = CV_MAKE_TYPE(wdepth, cn); 00258 00259 ocl::Device dev = ocl::Device::getDefault(); 00260 int pxPerWIx = (cn==1 && dev.isIntel() && (dev.type() & ocl::Device::TYPE_GPU)) ? 4 : 1; 00261 int rated_cn = cn; 00262 int wtype1 = wtype; 00263 00264 if (pxPerWIx!=1) 00265 { 00266 rated_cn = pxPerWIx; 00267 type = CV_MAKE_TYPE(depth, rated_cn); 00268 wtype1 = CV_MAKE_TYPE(wdepth, rated_cn); 00269 } 00270 00271 char cvt[40]; 00272 char cvt1[40]; 00273 const char* convertToWT1 = ocl::convertTypeStr(depth, wdepth, cn, cvt); 00274 const char* convertToWT = ocl::convertTypeStr(depth, wdepth, rated_cn, cvt1); 00275 00276 ocl::Kernel k("matchTemplate_Naive_CCORR", ocl::imgproc::match_template_oclsrc, 00277 format("-D CCORR -D T=%s -D T1=%s -D WT=%s -D WT1=%s -D convertToWT=%s -D convertToWT1=%s -D cn=%d -D PIX_PER_WI_X=%d", ocl::typeToStr(type), ocl::typeToStr(depth), ocl::typeToStr(wtype1), ocl::typeToStr(wtype), 00278 convertToWT, convertToWT1, cn, pxPerWIx)); 00279 if (k.empty()) 00280 return false; 00281 00282 UMat image = _image.getUMat(), templ = _templ.getUMat(); 00283 _result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1); 00284 UMat result = _result.getUMat(); 00285 00286 k.args(ocl::KernelArg::ReadOnlyNoSize(image), ocl::KernelArg::ReadOnly(templ), 00287 ocl::KernelArg::WriteOnly(result)); 00288 00289 size_t globalsize[2] = { ((size_t)result.cols+pxPerWIx-1)/pxPerWIx, (size_t)result.rows}; 00290 return k.run(2, globalsize, NULL, false); 00291 } 00292 00293 00294 static bool matchTemplate_CCORR(InputArray _image, InputArray _templ, OutputArray _result) 00295 { 00296 if (useNaive(_templ.size())) 00297 return( matchTemplateNaive_CCORR(_image, _templ, _result)); 00298 else 00299 { 00300 if(_image.depth() == CV_8U) 00301 { 00302 UMat imagef, templf; 00303 UMat image = _image.getUMat(); 00304 UMat templ = _templ.getUMat(); 00305 image.convertTo(imagef, CV_32F); 00306 templ.convertTo(templf, CV_32F); 00307 return(convolve_32F(imagef, templf, _result)); 00308 } 00309 else 00310 { 00311 return(convolve_32F(_image, _templ, _result)); 00312 } 00313 } 00314 } 00315 00316 static bool matchTemplate_CCORR_NORMED(InputArray _image, InputArray _templ, OutputArray _result) 00317 { 00318 matchTemplate(_image, _templ, _result, CV_TM_CCORR); 00319 00320 int type = _image.type(), cn = CV_MAT_CN(type); 00321 00322 ocl::Kernel k("matchTemplate_CCORR_NORMED", ocl::imgproc::match_template_oclsrc, 00323 format("-D CCORR_NORMED -D T=%s -D cn=%d", ocl::typeToStr(type), cn)); 00324 if (k.empty()) 00325 return false; 00326 00327 UMat image = _image.getUMat(), templ = _templ.getUMat(); 00328 _result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1); 00329 UMat result = _result.getUMat(); 00330 00331 UMat image_sums, image_sqsums; 00332 integral (image.reshape(1), image_sums, image_sqsums, CV_32F, CV_32F); 00333 00334 UMat templ_sqsum; 00335 if (!sumTemplate(templ, templ_sqsum)) 00336 return false; 00337 00338 k.args(ocl::KernelArg::ReadOnlyNoSize(image_sqsums), ocl::KernelArg::ReadWrite(result), 00339 templ.rows, templ.cols, ocl::KernelArg::PtrReadOnly(templ_sqsum)); 00340 00341 size_t globalsize[2] = { (size_t)result.cols, (size_t)result.rows }; 00342 return k.run(2, globalsize, NULL, false); 00343 } 00344 00345 ////////////////////////////////////// SQDIFF ////////////////////////////////////////////////////////////// 00346 00347 static bool matchTemplateNaive_SQDIFF(InputArray _image, InputArray _templ, OutputArray _result) 00348 { 00349 int type = _image.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); 00350 int wdepth = CV_32F, wtype = CV_MAKE_TYPE(wdepth, cn); 00351 00352 char cvt[40]; 00353 ocl::Kernel k("matchTemplate_Naive_SQDIFF", ocl::imgproc::match_template_oclsrc, 00354 format("-D SQDIFF -D T=%s -D T1=%s -D WT=%s -D convertToWT=%s -D cn=%d", ocl::typeToStr(type), ocl::typeToStr(depth), 00355 ocl::typeToStr(wtype), ocl::convertTypeStr(depth, wdepth, cn, cvt), cn)); 00356 if (k.empty()) 00357 return false; 00358 00359 UMat image = _image.getUMat(), templ = _templ.getUMat(); 00360 _result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32F); 00361 UMat result = _result.getUMat(); 00362 00363 k.args(ocl::KernelArg::ReadOnlyNoSize(image), ocl::KernelArg::ReadOnly(templ), 00364 ocl::KernelArg::WriteOnly(result)); 00365 00366 size_t globalsize[2] = { (size_t)result.cols, (size_t)result.rows }; 00367 return k.run(2, globalsize, NULL, false); 00368 } 00369 00370 static bool matchTemplate_SQDIFF(InputArray _image, InputArray _templ, OutputArray _result) 00371 { 00372 if (useNaive(_templ.size())) 00373 return( matchTemplateNaive_SQDIFF(_image, _templ, _result)); 00374 else 00375 { 00376 matchTemplate(_image, _templ, _result, CV_TM_CCORR); 00377 00378 int type = _image.type(), cn = CV_MAT_CN(type); 00379 00380 ocl::Kernel k("matchTemplate_Prepared_SQDIFF", ocl::imgproc::match_template_oclsrc, 00381 format("-D SQDIFF_PREPARED -D T=%s -D cn=%d", ocl::typeToStr(type), cn)); 00382 if (k.empty()) 00383 return false; 00384 00385 UMat image = _image.getUMat(), templ = _templ.getUMat(); 00386 _result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32F); 00387 UMat result = _result.getUMat(); 00388 00389 UMat image_sums, image_sqsums; 00390 integral (image.reshape(1), image_sums, image_sqsums, CV_32F, CV_32F); 00391 00392 UMat templ_sqsum; 00393 if (!sumTemplate(_templ, templ_sqsum)) 00394 return false; 00395 00396 k.args(ocl::KernelArg::ReadOnlyNoSize(image_sqsums), ocl::KernelArg::ReadWrite(result), 00397 templ.rows, templ.cols, ocl::KernelArg::PtrReadOnly(templ_sqsum)); 00398 00399 size_t globalsize[2] = { (size_t)result.cols, (size_t)result.rows }; 00400 00401 return k.run(2, globalsize, NULL, false); 00402 } 00403 } 00404 00405 static bool matchTemplate_SQDIFF_NORMED(InputArray _image, InputArray _templ, OutputArray _result) 00406 { 00407 matchTemplate(_image, _templ, _result, CV_TM_CCORR); 00408 00409 int type = _image.type(), cn = CV_MAT_CN(type); 00410 00411 ocl::Kernel k("matchTemplate_SQDIFF_NORMED", ocl::imgproc::match_template_oclsrc, 00412 format("-D SQDIFF_NORMED -D T=%s -D cn=%d", ocl::typeToStr(type), cn)); 00413 if (k.empty()) 00414 return false; 00415 00416 UMat image = _image.getUMat(), templ = _templ.getUMat(); 00417 _result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32F); 00418 UMat result = _result.getUMat(); 00419 00420 UMat image_sums, image_sqsums; 00421 integral (image.reshape(1), image_sums, image_sqsums, CV_32F, CV_32F); 00422 00423 UMat templ_sqsum; 00424 if (!sumTemplate(_templ, templ_sqsum)) 00425 return false; 00426 00427 k.args(ocl::KernelArg::ReadOnlyNoSize(image_sqsums), ocl::KernelArg::ReadWrite(result), 00428 templ.rows, templ.cols, ocl::KernelArg::PtrReadOnly(templ_sqsum)); 00429 00430 size_t globalsize[2] = { (size_t)result.cols, (size_t)result.rows }; 00431 00432 return k.run(2, globalsize, NULL, false); 00433 } 00434 00435 ///////////////////////////////////// CCOEFF ///////////////////////////////////////////////////////////////// 00436 00437 static bool matchTemplate_CCOEFF(InputArray _image, InputArray _templ, OutputArray _result) 00438 { 00439 matchTemplate(_image, _templ, _result, CV_TM_CCORR); 00440 00441 UMat image_sums, temp; 00442 integral (_image, image_sums, CV_32F); 00443 00444 int type = image_sums.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); 00445 00446 ocl::Kernel k("matchTemplate_Prepared_CCOEFF", ocl::imgproc::match_template_oclsrc, 00447 format("-D CCOEFF -D T=%s -D T1=%s -D cn=%d", ocl::typeToStr(type), ocl::typeToStr(depth), cn)); 00448 if (k.empty()) 00449 return false; 00450 00451 UMat templ = _templ.getUMat(); 00452 UMat result = _result.getUMat(); 00453 00454 if (cn==1) 00455 { 00456 Scalar templMean = mean(templ); 00457 float templ_sum = (float)templMean[0]; 00458 00459 k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols, templ_sum); 00460 } 00461 else 00462 { 00463 Vec4f templ_sum = Vec4f::all(0); 00464 templ_sum = (Vec4f)mean(templ); 00465 00466 k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols, templ_sum); } 00467 00468 size_t globalsize[2] = { (size_t)result.cols, (size_t)result.rows }; 00469 return k.run(2, globalsize, NULL, false); 00470 } 00471 00472 static bool matchTemplate_CCOEFF_NORMED(InputArray _image, InputArray _templ, OutputArray _result) 00473 { 00474 matchTemplate(_image, _templ, _result, CV_TM_CCORR); 00475 00476 UMat temp, image_sums, image_sqsums; 00477 integral (_image, image_sums, image_sqsums, CV_32F, CV_32F); 00478 00479 int type = image_sums.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); 00480 00481 ocl::Kernel k("matchTemplate_CCOEFF_NORMED", ocl::imgproc::match_template_oclsrc, 00482 format("-D CCOEFF_NORMED -D T=%s -D T1=%s -D cn=%d", ocl::typeToStr(type), ocl::typeToStr(depth), cn)); 00483 if (k.empty()) 00484 return false; 00485 00486 UMat templ = _templ.getUMat(); 00487 Size size = _image.size(), tsize = templ.size(); 00488 _result.create(size.height - templ.rows + 1, size.width - templ.cols + 1, CV_32F); 00489 UMat result = _result.getUMat(); 00490 00491 float scale = 1.f / tsize.area(); 00492 00493 if (cn == 1) 00494 { 00495 float templ_sum = (float)sum(templ)[0]; 00496 00497 multiply(templ, templ, temp, 1, CV_32F); 00498 float templ_sqsum = (float)sum(temp)[0]; 00499 00500 templ_sqsum -= scale * templ_sum * templ_sum; 00501 templ_sum *= scale; 00502 00503 if (templ_sqsum < DBL_EPSILON) 00504 { 00505 result = Scalar::all(1); 00506 return true; 00507 } 00508 00509 k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadOnlyNoSize(image_sqsums), 00510 ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols, scale, templ_sum, templ_sqsum); 00511 } 00512 else 00513 { 00514 Vec4f templ_sum = Vec4f::all(0), templ_sqsum = Vec4f::all(0); 00515 templ_sum = sum(templ); 00516 00517 multiply(templ, templ, temp, 1, CV_32F); 00518 templ_sqsum = sum(temp); 00519 00520 float templ_sqsum_sum = 0; 00521 for (int i = 0; i < cn; i ++) 00522 templ_sqsum_sum += templ_sqsum[i] - scale * templ_sum[i] * templ_sum[i]; 00523 00524 templ_sum *= scale; 00525 00526 if (templ_sqsum_sum < DBL_EPSILON) 00527 { 00528 result = Scalar::all(1); 00529 return true; 00530 } 00531 00532 k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadOnlyNoSize(image_sqsums), 00533 ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols, scale, 00534 templ_sum, templ_sqsum_sum); } 00535 00536 size_t globalsize[2] = { (size_t)result.cols, (size_t)result.rows }; 00537 return k.run(2, globalsize, NULL, false); 00538 } 00539 00540 /////////////////////////////////////////////////////////////////////////////////////////////////////////// 00541 00542 static bool ocl_matchTemplate( InputArray _img, InputArray _templ, OutputArray _result, int method) 00543 { 00544 int cn = _img.channels(); 00545 00546 if (cn > 4) 00547 return false; 00548 00549 typedef bool (*Caller)(InputArray _img, InputArray _templ, OutputArray _result); 00550 00551 static const Caller callers[] = 00552 { 00553 matchTemplate_SQDIFF, matchTemplate_SQDIFF_NORMED, matchTemplate_CCORR, 00554 matchTemplate_CCORR_NORMED, matchTemplate_CCOEFF, matchTemplate_CCOEFF_NORMED 00555 }; 00556 const Caller caller = callers[method]; 00557 00558 return caller(_img, _templ, _result); 00559 } 00560 00561 #endif 00562 00563 #if defined HAVE_IPP 00564 00565 typedef IppStatus (CV_STDCALL * ippimatchTemplate)(const void*, int, IppiSize, const void*, int, IppiSize, Ipp32f* , int , IppEnum , Ipp8u*); 00566 00567 static bool ipp_crossCorr(const Mat& src, const Mat& tpl, Mat& dst) 00568 { 00569 IppStatus status; 00570 00571 IppiSize srcRoiSize = {src.cols,src.rows}; 00572 IppiSize tplRoiSize = {tpl.cols,tpl.rows}; 00573 00574 Ipp8u *pBuffer; 00575 int bufSize=0; 00576 00577 int depth = src.depth(); 00578 00579 ippimatchTemplate ippFunc = 00580 depth==CV_8U ? (ippimatchTemplate)ippiCrossCorrNorm_8u32f_C1R: 00581 depth==CV_32F? (ippimatchTemplate)ippiCrossCorrNorm_32f_C1R: 0; 00582 00583 if (ippFunc==0) 00584 return false; 00585 00586 IppEnum funCfg = (IppEnum)(ippAlgAuto | ippiNormNone | ippiROIValid); 00587 00588 status = ippiCrossCorrNormGetBufferSize(srcRoiSize, tplRoiSize, funCfg, &bufSize); 00589 if ( status < 0 ) 00590 return false; 00591 00592 pBuffer = ippsMalloc_8u( bufSize ); 00593 00594 status = ippFunc(src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr<Ipp32f>(), (int)dst.step, funCfg, pBuffer); 00595 00596 ippsFree( pBuffer ); 00597 return status >= 0; 00598 } 00599 00600 static bool ipp_sqrDistance(const Mat& src, const Mat& tpl, Mat& dst) 00601 { 00602 IppStatus status; 00603 00604 IppiSize srcRoiSize = {src.cols,src.rows}; 00605 IppiSize tplRoiSize = {tpl.cols,tpl.rows}; 00606 00607 Ipp8u *pBuffer; 00608 int bufSize=0; 00609 00610 int depth = src.depth(); 00611 00612 ippimatchTemplate ippFunc = 00613 depth==CV_8U ? (ippimatchTemplate)ippiSqrDistanceNorm_8u32f_C1R: 00614 depth==CV_32F? (ippimatchTemplate)ippiSqrDistanceNorm_32f_C1R: 0; 00615 00616 if (ippFunc==0) 00617 return false; 00618 00619 IppEnum funCfg = (IppEnum)(ippAlgAuto | ippiNormNone | ippiROIValid); 00620 00621 status = ippiSqrDistanceNormGetBufferSize(srcRoiSize, tplRoiSize, funCfg, &bufSize); 00622 if ( status < 0 ) 00623 return false; 00624 00625 pBuffer = ippsMalloc_8u( bufSize ); 00626 00627 status = ippFunc(src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr<Ipp32f>(), (int)dst.step, funCfg, pBuffer); 00628 00629 ippsFree( pBuffer ); 00630 return status >= 0; 00631 } 00632 00633 #endif 00634 00635 void crossCorr( const Mat& img, const Mat& _templ, Mat& corr, 00636 Size corrsize, int ctype, 00637 Point anchor, double delta, int borderType ) 00638 { 00639 const double blockScale = 4.5; 00640 const int minBlockSize = 256; 00641 std::vector<uchar> buf; 00642 00643 Mat templ = _templ; 00644 int depth = img.depth(), cn = img.channels(); 00645 int tdepth = templ.depth(), tcn = templ.channels(); 00646 int cdepth = CV_MAT_DEPTH(ctype), ccn = CV_MAT_CN(ctype); 00647 00648 CV_Assert( img.dims <= 2 && templ.dims <= 2 && corr.dims <= 2 ); 00649 00650 if( depth != tdepth && tdepth != std::max(CV_32F, depth) ) 00651 { 00652 _templ.convertTo(templ, std::max(CV_32F, depth)); 00653 tdepth = templ.depth(); 00654 } 00655 00656 CV_Assert( depth == tdepth || tdepth == CV_32F); 00657 CV_Assert( corrsize.height <= img.rows + templ.rows - 1 && 00658 corrsize.width <= img.cols + templ.cols - 1 ); 00659 00660 CV_Assert( ccn == 1 || delta == 0 ); 00661 00662 corr.create(corrsize, ctype); 00663 00664 int maxDepth = depth > CV_8S ? CV_64F : std::max(std::max(CV_32F, tdepth), cdepth); 00665 Size blocksize, dftsize; 00666 00667 blocksize.width = cvRound(templ.cols*blockScale); 00668 blocksize.width = std::max( blocksize.width, minBlockSize - templ.cols + 1 ); 00669 blocksize.width = std::min( blocksize.width, corr.cols ); 00670 blocksize.height = cvRound(templ.rows*blockScale); 00671 blocksize.height = std::max( blocksize.height, minBlockSize - templ.rows + 1 ); 00672 blocksize.height = std::min( blocksize.height, corr.rows ); 00673 00674 dftsize.width = std::max(getOptimalDFTSize(blocksize.width + templ.cols - 1), 2); 00675 dftsize.height = getOptimalDFTSize(blocksize.height + templ.rows - 1); 00676 if( dftsize.width <= 0 || dftsize.height <= 0 ) 00677 CV_Error( CV_StsOutOfRange, "the input arrays are too big" ); 00678 00679 // recompute block size 00680 blocksize.width = dftsize.width - templ.cols + 1; 00681 blocksize.width = MIN( blocksize.width, corr.cols ); 00682 blocksize.height = dftsize.height - templ.rows + 1; 00683 blocksize.height = MIN( blocksize.height, corr.rows ); 00684 00685 Mat dftTempl( dftsize.height*tcn, dftsize.width, maxDepth ); 00686 Mat dftImg( dftsize, maxDepth ); 00687 00688 int i, k, bufSize = 0; 00689 if( tcn > 1 && tdepth != maxDepth ) 00690 bufSize = templ.cols*templ.rows*CV_ELEM_SIZE(tdepth); 00691 00692 if( cn > 1 && depth != maxDepth ) 00693 bufSize = std::max( bufSize, (blocksize.width + templ.cols - 1)* 00694 (blocksize.height + templ.rows - 1)*CV_ELEM_SIZE(depth)); 00695 00696 if( (ccn > 1 || cn > 1) && cdepth != maxDepth ) 00697 bufSize = std::max( bufSize, blocksize.width*blocksize.height*CV_ELEM_SIZE(cdepth)); 00698 00699 buf.resize(bufSize); 00700 00701 // compute DFT of each template plane 00702 for( k = 0; k < tcn; k++ ) 00703 { 00704 int yofs = k*dftsize.height; 00705 Mat src = templ; 00706 Mat dst(dftTempl, Rect(0, yofs, dftsize.width, dftsize.height)); 00707 Mat dst1(dftTempl, Rect(0, yofs, templ.cols, templ.rows)); 00708 00709 if( tcn > 1 ) 00710 { 00711 src = tdepth == maxDepth ? dst1 : Mat(templ.size(), tdepth, &buf[0]); 00712 int pairs[] = {k, 0}; 00713 mixChannels(&templ, 1, &src, 1, pairs, 1); 00714 } 00715 00716 if( dst1.data != src.data ) 00717 src.convertTo(dst1, dst1.depth()); 00718 00719 if( dst.cols > templ.cols ) 00720 { 00721 Mat part(dst, Range(0, templ.rows), Range(templ.cols, dst.cols)); 00722 part = Scalar::all(0); 00723 } 00724 dft(dst, dst, 0, templ.rows); 00725 } 00726 00727 int tileCountX = (corr.cols + blocksize.width - 1)/blocksize.width; 00728 int tileCountY = (corr.rows + blocksize.height - 1)/blocksize.height; 00729 int tileCount = tileCountX * tileCountY; 00730 00731 Size wholeSize = img.size(); 00732 Point roiofs(0,0); 00733 Mat img0 = img; 00734 00735 if( !(borderType & BORDER_ISOLATED) ) 00736 { 00737 img.locateROI(wholeSize, roiofs); 00738 img0.adjustROI(roiofs.y, wholeSize.height-img.rows-roiofs.y, 00739 roiofs.x, wholeSize.width-img.cols-roiofs.x); 00740 } 00741 borderType |= BORDER_ISOLATED; 00742 00743 // calculate correlation by blocks 00744 for( i = 0; i < tileCount; i++ ) 00745 { 00746 int x = (i%tileCountX)*blocksize.width; 00747 int y = (i/tileCountX)*blocksize.height; 00748 00749 Size bsz(std::min(blocksize.width, corr.cols - x), 00750 std::min(blocksize.height, corr.rows - y)); 00751 Size dsz(bsz.width + templ.cols - 1, bsz.height + templ.rows - 1); 00752 int x0 = x - anchor.x + roiofs.x, y0 = y - anchor.y + roiofs.y; 00753 int x1 = std::max(0, x0), y1 = std::max(0, y0); 00754 int x2 = std::min(img0.cols, x0 + dsz.width); 00755 int y2 = std::min(img0.rows, y0 + dsz.height); 00756 Mat src0(img0, Range(y1, y2), Range(x1, x2)); 00757 Mat dst(dftImg, Rect(0, 0, dsz.width, dsz.height)); 00758 Mat dst1(dftImg, Rect(x1-x0, y1-y0, x2-x1, y2-y1)); 00759 Mat cdst(corr, Rect(x, y, bsz.width, bsz.height)); 00760 00761 for( k = 0; k < cn; k++ ) 00762 { 00763 Mat src = src0; 00764 dftImg = Scalar::all(0); 00765 00766 if( cn > 1 ) 00767 { 00768 src = depth == maxDepth ? dst1 : Mat(y2-y1, x2-x1, depth, &buf[0]); 00769 int pairs[] = {k, 0}; 00770 mixChannels(&src0, 1, &src, 1, pairs, 1); 00771 } 00772 00773 if( dst1.data != src.data ) 00774 src.convertTo(dst1, dst1.depth()); 00775 00776 if( x2 - x1 < dsz.width || y2 - y1 < dsz.height ) 00777 copyMakeBorder(dst1, dst, y1-y0, dst.rows-dst1.rows-(y1-y0), 00778 x1-x0, dst.cols-dst1.cols-(x1-x0), borderType); 00779 00780 dft( dftImg, dftImg, 0, dsz.height ); 00781 Mat dftTempl1(dftTempl, Rect(0, tcn > 1 ? k*dftsize.height : 0, 00782 dftsize.width, dftsize.height)); 00783 mulSpectrums(dftImg, dftTempl1, dftImg, 0, true); 00784 dft( dftImg, dftImg, DFT_INVERSE + DFT_SCALE, bsz.height ); 00785 00786 src = dftImg(Rect(0, 0, bsz.width, bsz.height)); 00787 00788 if( ccn > 1 ) 00789 { 00790 if( cdepth != maxDepth ) 00791 { 00792 Mat plane(bsz, cdepth, &buf[0]); 00793 src.convertTo(plane, cdepth, 1, delta); 00794 src = plane; 00795 } 00796 int pairs[] = {0, k}; 00797 mixChannels(&src, 1, &cdst, 1, pairs, 1); 00798 } 00799 else 00800 { 00801 if( k == 0 ) 00802 src.convertTo(cdst, cdepth, 1, delta); 00803 else 00804 { 00805 if( maxDepth != cdepth ) 00806 { 00807 Mat plane(bsz, cdepth, &buf[0]); 00808 src.convertTo(plane, cdepth); 00809 src = plane; 00810 } 00811 add(src, cdst, cdst); 00812 } 00813 } 00814 } 00815 } 00816 } 00817 00818 static void matchTemplateMask( InputArray _img, InputArray _templ, OutputArray _result, int method, InputArray _mask ) 00819 { 00820 int type = _img.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); 00821 CV_Assert( CV_TM_SQDIFF <= method && method <= CV_TM_CCOEFF_NORMED ); 00822 CV_Assert( (depth == CV_8U || depth == CV_32F) && type == _templ.type() && _img.dims() <= 2 ); 00823 00824 Mat img = _img.getMat(), templ = _templ.getMat(), mask = _mask.getMat(); 00825 int ttype = templ.type(), tdepth = CV_MAT_DEPTH(ttype), tcn = CV_MAT_CN(ttype); 00826 int mtype = img.type(), mdepth = CV_MAT_DEPTH(type), mcn = CV_MAT_CN(mtype); 00827 00828 if (depth == CV_8U) 00829 { 00830 depth = CV_32F; 00831 type = CV_MAKETYPE(CV_32F, cn); 00832 img.convertTo(img, type, 1.0 / 255); 00833 } 00834 00835 if (tdepth == CV_8U) 00836 { 00837 tdepth = CV_32F; 00838 ttype = CV_MAKETYPE(CV_32F, tcn); 00839 templ.convertTo(templ, ttype, 1.0 / 255); 00840 } 00841 00842 if (mdepth == CV_8U) 00843 { 00844 mdepth = CV_32F; 00845 mtype = CV_MAKETYPE(CV_32F, mcn); 00846 compare(mask, Scalar::all(0), mask, CMP_NE); 00847 mask.convertTo(mask, mtype, 1.0 / 255); 00848 } 00849 00850 Size corrSize(img.cols - templ.cols + 1, img.rows - templ.rows + 1); 00851 _result.create(corrSize, CV_32F); 00852 Mat result = _result.getMat(); 00853 00854 Mat img2 = img.mul(img); 00855 Mat mask2 = mask.mul(mask); 00856 Mat mask_templ = templ.mul(mask); 00857 Scalar templMean, templSdv; 00858 00859 double templSum2 = 0; 00860 meanStdDev( mask_templ, templMean, templSdv ); 00861 00862 templSum2 = templSdv[0]*templSdv[0] + templSdv[1]*templSdv[1] + templSdv[2]*templSdv[2] + templSdv[3]*templSdv[3]; 00863 templSum2 += templMean[0]*templMean[0] + templMean[1]*templMean[1] + templMean[2]*templMean[2] + templMean[3]*templMean[3]; 00864 templSum2 *= ((double)templ.rows * templ.cols); 00865 00866 if (method == CV_TM_SQDIFF) 00867 { 00868 Mat mask2_templ = templ.mul(mask2); 00869 00870 Mat corr(corrSize, CV_32F); 00871 crossCorr( img, mask2_templ, corr, corr.size(), corr.type(), Point(0,0), 0, 0 ); 00872 crossCorr( img2, mask, result, result.size(), result.type(), Point(0,0), 0, 0 ); 00873 00874 result -= corr * 2; 00875 result += templSum2; 00876 } 00877 else if (method == CV_TM_CCORR_NORMED) 00878 { 00879 if (templSum2 < DBL_EPSILON) 00880 { 00881 result = Scalar::all(1); 00882 return; 00883 } 00884 00885 Mat corr(corrSize, CV_32F); 00886 crossCorr( img2, mask2, corr, corr.size(), corr.type(), Point(0,0), 0, 0 ); 00887 crossCorr( img, mask_templ, result, result.size(), result.type(), Point(0,0), 0, 0 ); 00888 00889 sqrt(corr, corr); 00890 result = result.mul(1/corr); 00891 result /= std::sqrt(templSum2); 00892 } 00893 else 00894 CV_Error(Error::StsNotImplemented, ""); 00895 } 00896 } 00897 00898 00899 namespace cv 00900 { 00901 static void common_matchTemplate( Mat& img, Mat& templ, Mat& result, int method, int cn ) 00902 { 00903 if( method == CV_TM_CCORR ) 00904 return; 00905 00906 int numType = method == CV_TM_CCORR || method == CV_TM_CCORR_NORMED ? 0 : 00907 method == CV_TM_CCOEFF || method == CV_TM_CCOEFF_NORMED ? 1 : 2; 00908 bool isNormed = method == CV_TM_CCORR_NORMED || 00909 method == CV_TM_SQDIFF_NORMED || 00910 method == CV_TM_CCOEFF_NORMED; 00911 00912 double invArea = 1./((double)templ.rows * templ.cols); 00913 00914 Mat sum, sqsum; 00915 Scalar templMean, templSdv; 00916 double *q0 = 0, *q1 = 0, *q2 = 0, *q3 = 0; 00917 double templNorm = 0, templSum2 = 0; 00918 00919 if( method == CV_TM_CCOEFF ) 00920 { 00921 integral (img, sum, CV_64F); 00922 templMean = mean(templ); 00923 } 00924 else 00925 { 00926 integral (img, sum, sqsum, CV_64F); 00927 meanStdDev( templ, templMean, templSdv ); 00928 00929 templNorm = templSdv[0]*templSdv[0] + templSdv[1]*templSdv[1] + templSdv[2]*templSdv[2] + templSdv[3]*templSdv[3]; 00930 00931 if( templNorm < DBL_EPSILON && method == CV_TM_CCOEFF_NORMED ) 00932 { 00933 result = Scalar::all(1); 00934 return; 00935 } 00936 00937 templSum2 = templNorm + templMean[0]*templMean[0] + templMean[1]*templMean[1] + templMean[2]*templMean[2] + templMean[3]*templMean[3]; 00938 00939 if( numType != 1 ) 00940 { 00941 templMean = Scalar::all(0); 00942 templNorm = templSum2; 00943 } 00944 00945 templSum2 /= invArea; 00946 templNorm = std::sqrt(templNorm); 00947 templNorm /= std::sqrt(invArea); // care of accuracy here 00948 00949 q0 = (double*)sqsum.data; 00950 q1 = q0 + templ.cols*cn; 00951 q2 = (double*)(sqsum.data + templ.rows*sqsum.step); 00952 q3 = q2 + templ.cols*cn; 00953 } 00954 00955 double* p0 = (double*)sum.data; 00956 double* p1 = p0 + templ.cols*cn; 00957 double* p2 = (double*)(sum.data + templ.rows*sum.step); 00958 double* p3 = p2 + templ.cols*cn; 00959 00960 int sumstep = sum.data ? (int)(sum.step / sizeof(double)) : 0; 00961 int sqstep = sqsum.data ? (int)(sqsum.step / sizeof(double)) : 0; 00962 00963 int i, j, k; 00964 00965 for( i = 0; i < result.rows; i++ ) 00966 { 00967 float* rrow = result.ptr<float>(i); 00968 int idx = i * sumstep; 00969 int idx2 = i * sqstep; 00970 00971 for( j = 0; j < result.cols; j++, idx += cn, idx2 += cn ) 00972 { 00973 double num = rrow[j], t; 00974 double wndMean2 = 0, wndSum2 = 0; 00975 00976 if( numType == 1 ) 00977 { 00978 for( k = 0; k < cn; k++ ) 00979 { 00980 t = p0[idx+k] - p1[idx+k] - p2[idx+k] + p3[idx+k]; 00981 wndMean2 += t*t; 00982 num -= t*templMean[k]; 00983 } 00984 00985 wndMean2 *= invArea; 00986 } 00987 00988 if( isNormed || numType == 2 ) 00989 { 00990 for( k = 0; k < cn; k++ ) 00991 { 00992 t = q0[idx2+k] - q1[idx2+k] - q2[idx2+k] + q3[idx2+k]; 00993 wndSum2 += t; 00994 } 00995 00996 if( numType == 2 ) 00997 { 00998 num = wndSum2 - 2*num + templSum2; 00999 num = MAX(num, 0.); 01000 } 01001 } 01002 01003 if( isNormed ) 01004 { 01005 t = std::sqrt(MAX(wndSum2 - wndMean2,0))*templNorm; 01006 if( fabs(num) < t ) 01007 num /= t; 01008 else if( fabs(num) < t*1.125 ) 01009 num = num > 0 ? 1 : -1; 01010 else 01011 num = method != CV_TM_SQDIFF_NORMED ? 0 : 1; 01012 } 01013 01014 rrow[j] = (float)num; 01015 } 01016 } 01017 } 01018 } 01019 01020 01021 #if defined HAVE_IPP 01022 namespace cv 01023 { 01024 static bool ipp_matchTemplate( Mat& img, Mat& templ, Mat& result, int method, int cn ) 01025 { 01026 bool useIppMT = (templ.rows < img.rows/2 && templ.cols < img.cols/2); 01027 01028 if(cn == 1 && useIppMT) 01029 { 01030 if(method == CV_TM_SQDIFF) 01031 { 01032 if (ipp_sqrDistance(img, templ, result)) 01033 return true; 01034 } 01035 else 01036 { 01037 if(ipp_crossCorr(img, templ, result)) 01038 { 01039 common_matchTemplate(img, templ, result, method, cn); 01040 return true; 01041 } 01042 } 01043 } 01044 01045 return false; 01046 } 01047 } 01048 #endif 01049 01050 //////////////////////////////////////////////////////////////////////////////////////////////////////// 01051 01052 void cv::matchTemplate( InputArray _img, InputArray _templ, OutputArray _result, int method, InputArray _mask ) 01053 { 01054 if (!_mask.empty()) 01055 { 01056 cv::matchTemplateMask(_img, _templ, _result, method, _mask); 01057 return; 01058 } 01059 01060 int type = _img.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); 01061 CV_Assert( CV_TM_SQDIFF <= method && method <= CV_TM_CCOEFF_NORMED ); 01062 CV_Assert( (depth == CV_8U || depth == CV_32F) && type == _templ.type() && _img.dims() <= 2 ); 01063 01064 bool needswap = _img.size().height < _templ.size().height || _img.size().width < _templ.size().width; 01065 if (needswap) 01066 { 01067 CV_Assert(_img.size().height <= _templ.size().height && _img.size().width <= _templ.size().width); 01068 } 01069 01070 #ifdef HAVE_OPENCL 01071 CV_OCL_RUN(_img.dims() <= 2 && _result.isUMat(), 01072 (!needswap ? ocl_matchTemplate(_img, _templ, _result, method) : ocl_matchTemplate(_templ, _img, _result, method))) 01073 #endif 01074 01075 Mat img = _img.getMat(), templ = _templ.getMat(); 01076 if (needswap) 01077 std::swap(img, templ); 01078 01079 Size corrSize(img.cols - templ.cols + 1, img.rows - templ.rows + 1); 01080 _result.create(corrSize, CV_32F); 01081 Mat result = _result.getMat(); 01082 01083 #ifdef HAVE_TEGRA_OPTIMIZATION 01084 if (tegra::useTegra() && tegra::matchTemplate(img, templ, result, method)) 01085 return; 01086 #endif 01087 01088 CV_IPP_RUN(true, ipp_matchTemplate(img, templ, result, method, cn)) 01089 01090 crossCorr( img, templ, result, result.size(), result.type(), Point(0,0), 0, 0); 01091 01092 common_matchTemplate(img, templ, result, method, cn); 01093 } 01094 01095 CV_IMPL void 01096 cvMatchTemplate( const CvArr* _img, const CvArr* _templ, CvArr* _result, int method ) 01097 { 01098 cv::Mat img = cv::cvarrToMat(_img), templ = cv::cvarrToMat(_templ), 01099 result = cv::cvarrToMat(_result); 01100 CV_Assert( result.size() == cv::Size(std::abs(img.cols - templ.cols) + 1, 01101 std::abs(img.rows - templ.rows) + 1) && 01102 result.type() == CV_32F ); 01103 matchTemplate(img, templ, result, method); 01104 } 01105 01106 /* End of file. */ 01107
Generated on Tue Jul 12 2022 14:47:39 by
1.7.2
