C++ OpenCV C++;-是否查找包含在图像中的图像?
我有在较大的另一幅图像中搜索一幅小图像的代码:C++ OpenCV C++;-是否查找包含在图像中的图像?,c++,opencv,C++,Opencv,我有在较大的另一幅图像中搜索一幅小图像的代码: 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.r
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个图像-一个模板(),一个图像包含模板()中的图像,另一个图像不包含模板()
对于包含模板的第一个图像,maxVal=0.9999994039535522,并且它正确选择了区域:
但对于图像,该不包含模板,maxVal=1.0000000000000000,并且该错误地选定区域,不包含模板图像:
谢谢大家! 无论算法执行匹配的确定性如何,您都在可视化结果。模板匹配将始终为您提供一个输出—您要做的是尝试确定它是否有效 根据
匹配方法,尝试输出minVal
或maxVal
。您应该比较在找到正确匹配的情况下的值和在它给您假阳性的情况下的值。这些实验应该可以让你建立一个阈值,区分真实命中和误报。因此,您将能够说出maxVal的大小,例如,必须确保它是匹配的。伪代码应该是这样的:
if maxVal > threshold:
match_found = true
match_position = maxLoc
这是一种理论方法。因为您没有提供任何图像,所以它可能是您的问题的解决方案,也可能不是
编辑:
如果您找不到明确的阈值(我认为在大多数情况下,如果您保持质量、尺寸等,这应该是可能的),请尝试做以下两件事之一:
尝试查看所有获得的结果,在minMaxLoc
之前,计算平均值,并查看找到的maxVal
是否比真阳性情况下的平均值大得多。也许您可以将阈值定义为平均值的%,这样说:if maxVal>meanVal+meanVal*n%:match\u found=true
通常情况下,模板匹配对边缘的效果比对真实图像的效果好。同样,您还没有提供示例,因此很难说这种方法有多可靠。但如果你有足够高的频率,用精明的边缘照亮图像,这可能会给你一个更清晰的阈值来区分真阳性和假阳性
EDIT2:
因为您使用的是match_method=0,这意味着CV_TM_SQDIFF
。为了更好地控制流程,请显式使用名称。查找有关方法的信息
另外,将cout放在if语句中,以便打印出正确的值,该值实际上是匹配的ID(在您的示例中,它是minVal)
if(match_method==CV_TM_SQDIFF | match_method==CV_TM_SQDIFF|NORMED)
{
matchLoc=minLoc;
是的,我找到了一些像现在这样的帖子……但是如何计算每个模板图像的阈值呢?我希望OpenCV能够自动在图像中找到图像,而无需用户对阈值进行任何操作。编辑我的答案以适应更多的方向。祝你好运!@Arthur,检查matchTemplate do文档,以获取有关您正在使用的match_template方法应该查看的值的信息。在您的情况下,它应该是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;
}