使用opencv matchtemplate进行泡罩包装检查
我正在做一个项目,我必须检查药物泡罩包装是否有丢失的药片 我正在尝试使用opencv的matchTemplate函数。让我先展示代码,然后展示一些结果使用opencv matchtemplate进行泡罩包装检查,opencv,inspection,matchtemplate,Opencv,Inspection,Matchtemplate,我正在做一个项目,我必须检查药物泡罩包装是否有丢失的药片 我正在尝试使用opencv的matchTemplate函数。让我先展示代码,然后展示一些结果 int match(string filename, string templatename) { Mat ref = cv::imread(filename + ".jpg"); Mat tpl = cv::imread(templatename + ".jpg"); if (ref.empty() || tpl.emp
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;
}
int匹配(字符串文件名、字符串模板名)
{
Mat ref=cv::imread(文件名+“.jpg”);
Mat tpl=cv::imread(templatename+“.jpg”);
如果(参考empty()| | tpl.empty())
{
您是否尝试过Surf算法以获得更详细的描述符?您可以尝试收集完整和空样本图像的描述符。并对检测到的每个对象执行不同的操作。我找到了解决我自己问题的方法。我只需要在图像和模板b上应用Canny边缘检测器在将它们发送到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;
}
int匹配(字符串文件名、字符串模板名)
{
Mat ref=cv::imread(文件名+“.jpg”);
Mat tpl=cv::imread(templatename+“.jpg”);
如果(参考empty()| | tpl.empty())
{
cout我认为自适应阈值不是一个好的选择
这里你需要做的就是非最大值抑制。你有一个具有多个局部极大值的图像,你想删除所有非局部极大值的像素
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)
现在,res_32f图像中非局部最大值的所有像素都设置为零。所有最大像素仍保持其原始值,因此您可以稍后在该行中调整阈值
double minval, maxval, threshold = 0.8;
所有局部最大值现在也应被足够的零包围,以使洪水填充不会延伸太远
现在,我认为您应该能够调整阈值以排除所有误报
如果这还不够,还有另一个建议:
我将使用多个模板来运行搜索,而不仅仅是一个模板;您当前的模板,以及一个从包的右侧和左侧带有平板电脑的模板。由于透视角度不同,这些平板电脑看起来有点不同。请跟踪找到的平板电脑,这样您就不会多次检测到smae平板电脑
使用这些多个模板,您可以将阈值提高得更高
进一步的改进:如果检测仍然太不稳定,请尝试模糊模板,并使用高斯模糊搜索图像。这将去除可能导致matchTemplate函数失效的细节和噪声,同时保留较大的结构完整
使用canny滤镜对我来说似乎不可靠:它似乎依赖于这样一个事实,即移除的平板电脑区域在中心会有更多的边缘。但我不确定是否总是这样;而且使用canny滤镜会丢弃很多关于颜色和亮度的信息,因此我预计会有更糟糕的结果
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;
}
(也就是说,如果它对你有效,它就有效)我已经为您编辑了中的图像。+1对于一个优秀的问题,您可以尝试使用不同的阈值?0.8是最高值吗?此外,您可以尝试其他互相关方法,如SQDIFF_NORMED,而不是oft CCOEFF_NORMED?仔细查看代码,将相关结果转换为8位,然后运行自适应thres按住它,这样你传递给MinMaxLoc的图像已经被二值化了,所以更改0.8阈值将没有任何效果。我不确定你从中获得了什么,在原始res_32f中搜索最大值不会得到更好的结果吗?@HugoRune:原始代码在CV_32FC1结果图像上运行MinMaxLoc。但是因为我正在尝试进行近似匹配es,在没有adaptiveThreshold的情况下运行minMaxLoc会首先返回太多的失火。干得好!你能提供你的结果吗!@Constantine:添加了结果图片;)谢谢你的帮助。你能再看看我的答案吗,我添加了结果图片。本地非最大抑制是否有效?我知道目前我的代码只能处理“剪影”平板电脑。但至少它比原始颜色/灰色图像的matchTemplate返回更好的结果。我计划添加另一轮检查匹配轮廓的颜色,以防混入错误颜色的平板电脑。我想测试您的方法,但无法找到cv::set
。其他方法记录在和@handle我可能记错了,或者在我使用的c#包装器中重命名了它;它被称为