我有用于在另一张图片中搜索一张小图片的代码:
int* MyLib::MatchingMethod(int, void*)
{
/// Source image to display
img.copyTo(img_display);
/// Create the result matrix
int result_cols = img.cols - templ.cols + 1;
int result_rows = img.rows - templ.rows + 1;
result.create(result_rows, result_cols, CV_32FC1);
match_method = 0;
/// Do the Matching and Normalize
matchTemplate(img, templ, result, match_method);
normalize(result, result, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());
/// Localizing the best match with minMaxLoc
double minVal;
double maxVal;
cv::Point minLoc;
cv::Point maxLoc;
cv::Point matchLoc;
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat());
/// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better
if (match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED)
{
matchLoc = minLoc;
}
else
{
matchLoc = maxLoc;
}
if (showOpenCVWindow) {
/// Show me what you got
rectangle(img_display, matchLoc, cv::Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), cv::Scalar(255, 0, 0, 255), 2, 8, 0);
rectangle(result, matchLoc, cv::Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), cv::Scalar(255, 0, 0, 255), 2, 8, 0);
imshow(image_window, img_display);
imshow(result_window, result);
}
double myX = (matchLoc.x + (templ.cols) / 2);
double myY = (matchLoc.y + (templ.rows) / 2);
static int o[2];
o[0] = myX;
o[1] = myY;
return o;
}
但是这段代码可能会错误地“找到”任何区域,即使较大的图像不包含小图像。
如何更改此代码,强制它“完全”搜索小图像。例如,如果较小的图像不在较大的图像上,则此代码必须显示任何信息消息“未找到图像”。
更新1。看起来,matchTemplate
效果不佳。例如,我有3张图片 - 一张模板(http://s6.postimg.org/nj2ts3lf5/image.png),一张图片,其中包含来自模板的图片(http://s6.postimg.org/fp6tkg301/image.png),以及一张图片,其中不包含模板(http://s6.postimg.org/9x23zk3sh/image.png )。
对于包含模板的第一张图片,maxVal = 0.99999994039535522并正确选择了区域:http://s6.postimg.org/65x4qzfht/image.png
但是对于图片,不包含模板,maxVal = 1.0000000000000000 且错误选定区域,不包含t包含模板图片:http://s6.postimg.org/5132llt0x/screenshot_544.png
谢谢!
答案 0 :(得分:3)
无论算法执行匹配的确定性如何,您都可以将结果可视化。模板匹配总是会给你一个输出 - 你想要做的是试着弄清楚它是否有效。
根据minVal
尝试输出maxVal
或match_method
。您应该在找到正确匹配的情况下以及在它给出误报的情况下比较值。那些实验应该允许你建立一个阈值,区分真正的命中和误报。因此,你可以说多大 - 例如 - maxVal必须确保它是一个匹配。伪代码会是这样的:
if maxVal > threshold:
match_found = true
match_position = maxLoc
现在这是一种理论方法。由于您没有提供任何图像,因此可能会或可能不会解决您的问题。
修改强> 如果您找不到明确的阈值(在我看来,在大多数情况下,如果您保持质量,尺寸等,我认为应该可以),请尝试执行以下两项操作之一:
minMaxLoc
之前尝试查看所有获得的结果,计算平均值,看看发现的maxVal
是否比真阳性情况下的平均值大得多。也许您可以将阈值定义为平均值的百分比,从而说:if maxVal > meanVal + meanVal * n%: match_found = true
<强> EDIT2:强>
由于您使用match_method = 0,这意味着CV_TM_SQDIFF
。要更好地控制该过程,请明确使用该名称。查找有关方法source的信息。
另外,将cout放在if语句中,这样就可以打印正确的值,实际上就是匹配匹配(在你的情况下,它是minVal)。
if (match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED)
{
matchLoc = minLoc;
std::cout << minVal << std::endl;
}
else
{
matchLoc = maxLoc;
std::cout << maxVal << std::endl;
}
再次说明:如果没有达到预期效果,相当合理的轮廓检测几乎肯定会有所帮助。