我正在做一个项目,在这个项目中,我必须检查药用泡罩包装中是否缺少药片。
我正在尝试使用opencv的matchTemplate函数。让我显示代码,然后显示一些结果。
int match(string filename, string templatename)
{
Mat ref = cv::imread(filename + ".jpg");
Mat tpl = cv::imread(templatename + ".jpg");
if (ref.empty() || tpl.empty())
{
cout << "Error reading file(s)!" << endl;
return -1;
}
imshow("file", ref);
imshow("template", tpl);
Mat res_32f(ref.rows - tpl.rows + 1, ref.cols - tpl.cols + 1, CV_32FC1);
matchTemplate(ref, tpl, res_32f, CV_TM_CCOEFF_NORMED);
Mat res;
res_32f.convertTo(res, CV_8U, 255.0);
imshow("result", res);
int size = ((tpl.cols + tpl.rows) / 4) * 2 + 1; //force size to be odd
adaptiveThreshold(res, res, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, size, -128);
imshow("result_thresh", res);
while (true)
{
double minval, maxval, threshold = 0.8;
Point minloc, maxloc;
minMaxLoc(res, &minval, &maxval, &minloc, &maxloc);
if (maxval >= threshold)
{
rectangle(ref, maxloc, Point(maxloc.x + tpl.cols, maxloc.y + tpl.rows), CV_RGB(0,255,0), 2);
floodFill(res, maxloc, 0); //mark drawn blob
}
else
break;
}
imshow("final", ref);
waitKey(0);
return 0;
}
这是一些图片。
[一个好的泡罩包装的“样本”图像:
<<从“样本”图像裁剪的模板:
<<带有“样本”图像的结果:
<<检测到此包中缺少平板电脑:
<<但是这里有问题:
<< [我目前不知道为什么会这样。任何建议和/或帮助都将受到赞赏。我遵循和修改的原始代码在这里:http://opencv-code.com/quick-tips/how-to-handle-template-matching-with-multiple-occurences/
我正在做一个项目,在该项目中,我必须检查药用泡罩包装中是否缺少药片。我正在尝试使用opencv的matchTemplate函数。让我显示代码,然后显示一些结果。 int ...
我认为自适应阈值不是一个好的选择。
您在这里需要做的就是非最大抑制。您有一幅具有多个局部最大值的图像,并且想要删除所有不是局部最大值的像素。
cv::dilate(res_32f, res_dilated, null, 5);
cv::compare(res_32f, res_dilated, mask_local_maxima, cv::CMP_GE);
cv::set(res_32f, 0, mask_local_maxima)
double minval, maxval, threshold = 0.8;
现在,我认为您应该能够调整阈值以排除所有误报。
如果还不够,这是另一个建议:我将使用多个模板运行搜索,而不是仅使用一个模板;您当前的模板,以及从包装的右侧和左侧带平板电脑的模板。由于视角的原因,这些平板电脑看起来有些不同。跟踪找到的药片,这样就不会多次检测到smae药片。
使用这些多个模板,您可以将阈值提高得更高。进一步完善:如果检测仍然太不稳定,请尝试使模板模糊并使用高斯模糊搜索图像。这将删除matchTemplate函数可能抛出的细微细节和噪音,同时保留较大的结构不变。
(说,如果对您有用,它就可以使用)
int match(string filename, string templatename)
{
Mat ref = cv::imread(filename + ".jpg");
Mat tpl = cv::imread(templatename + ".jpg");
if(ref.empty() || tpl.empty())
{
cout << "Error reading file(s)!" << endl;
return -1;
}
Mat gref, gtpl;
cvtColor(ref, gref, CV_BGR2GRAY);
cvtColor(tpl, gtpl, CV_BGR2GRAY);
const int low_canny = 110;
Canny(gref, gref, low_canny, low_canny*3);
Canny(gtpl, gtpl, low_canny, low_canny*3);
imshow("file", gref);
imshow("template", gtpl);
Mat res_32f(ref.rows - tpl.rows + 1, ref.cols - tpl.cols + 1, CV_32FC1);
matchTemplate(gref, gtpl, res_32f, CV_TM_CCOEFF_NORMED);
Mat res;
res_32f.convertTo(res, CV_8U, 255.0);
imshow("result", res);
int size = ((tpl.cols + tpl.rows) / 4) * 2 + 1; //force size to be odd
adaptiveThreshold(res, res, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, size, -64);
imshow("result_thresh", res);
while(1)
{
double minval, maxval;
Point minloc, maxloc;
minMaxLoc(res, &minval, &maxval, &minloc, &maxloc);
if(maxval > 0)
{
rectangle(ref, maxloc, Point(maxloc.x + tpl.cols, maxloc.y + tpl.rows), Scalar(0,255,0), 2);
floodFill(res, maxloc, 0); //mark drawn blob
}
else
break;
}
imshow("final", ref);
waitKey(0);
return 0;
}
任何改进建议都值得赞赏。我非常担心代码的性能和健壮性,因此我正在寻找所有想法。
现在有两件事让我感到不安:较低的Canny阈值和adaptiveThreshold函数的负常数。
测试图像,缺少2片:
<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pMjkwLnBob3RvYnVja2V0LmNvbS9hbGJ1bXMvbGwyNTMvcmVkZ3VhcmRzb2xkaWWNZtest1NW”<< [模板和测试图像的Canny结果:
matchTemplate结果(转换为CV_8U):
<< [自适应阈值之后:
<< [最终结果:
<<您是否尝试过Surf算法以获得更详细的描述符?您可以尝试收集完整和空白样本图像的描述符。并对检测到的每个对象执行不同的操作。
您能否在给定的行中告诉我
adaptiveThreshold(res,res,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY,size,-64);
为什么编码器使用-64?它的目的是什么?为什么它是负面的?并且该值的范围是什么??
非常感谢,我有点困惑。