使用opencv matchtemplate进行泡罩包装检查

问题描述 投票:10回答:4

我正在做一个项目,在这个项目中,我必须检查药用泡罩包装中是否缺少药片。

我正在尝试使用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)

现在,将res_32f图像中非局部最大值的所有像素都设置为零。所有最大像素仍保持其原始值,因此您可以稍后在行中调整阈值
double minval, maxval, threshold = 0.8;
现在所有局部最大值也应被足够的零包围,以使洪水填充不会延伸得太远。

现在,我认为您应该能够调整阈值以排除所有误报。

如果还不够,这是另一个建议:

我将使用多个模板运行搜索,而不是仅使用一个模板;您当前的模板,以及从包装的右侧和左侧带平板电脑的模板。由于视角的原因,这些平板电脑看起来有些不同。跟踪找到的药片,这样就不会多次检测到smae药片。

使用这些多个模板,您可以将阈值提高得更高。

进一步完善:如果检测仍然太不稳定,请尝试使模板模糊并使用高斯模糊搜索图像。这将删除matchTemplate函数可能抛出的细微细节和噪音,同时保留较大的结构不变。


相反,对我而言,使用Canny滤镜似乎不可靠:它似乎依赖于这样一个事实,即已移除的数位板区域的中心将有更多的边缘。但是我不确定是否会一直如此。并且您使用Canny滤镜丢弃了很多有关颜色和亮度的信息,因此我希望得到更差的结果。

(说,如果对您有用,它就可以使用)


我为自己的问题找到了解决方案。我只需要在图像和模板上都应用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; }

任何改进建议都值得赞赏。我非常担心代码的性能和健壮性,因此我正在寻找所有想法。

现在有两件事让我感到不安:较低的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?它的目的是什么?为什么它是负面的?并且该值的范围是什么??

非常感谢,我有点困惑。

opencv inspection matchtemplate
4个回答
2
投票
现在所有局部最大值也应被足够的零包围,以使洪水填充不会延伸得太远。

2
投票
© www.soinside.com 2019 - 2024. All rights reserved.