c++ - 边缘提取建议OpenCV

标签 c++ opencv vision

我正在寻找建议以改善我的算法以搜索下图中的零件

enter image description here

到目前为止,我有以下

GaussianBlur(canny, canny, Size(5, 5), 2, 2);
Canny(canny, canny, 100, 200, 5);
HoughCircles(canny, Part_Centroids, CV_HOUGH_GRADIENT, 2, 30, 100, 50, 50, 60);

我的边缘检测输出看起来像这样

enter image description here

我使用HoughCircle来查找零件。不过,我还没有取得太大的成功,因为HoughCircle看起来很挑剔,并且经常返回一个实际上并不是最匹配的圆圈。

关于改进此搜索算法的任何建议

编辑:

我已经尝试了以下评论中的建议。归一化做了一些改进,但是在霍夫圆改变了所需的设置之前没有移除小节,但是稳定性没有改变。

我认为现在我需要做一些像胡夫圆之类的事情,并且具有非常开放的阈值,然后找到一种对结果进行评分的方法。是否有任何好的方法可以对霍夫圆的结果进行评分或将结果与canny输出进行相关性匹配百分比

最佳答案

我以为我会发布我的解决方案,因为有人会发现我学到的教训很有值(value)。

我首先拍摄了几帧并将其平均。这解决了我在保留强边缘时遇到的一些噪音问题。接下来,我做了一个基本的过滤器和Canny边缘,以提取一个体面的边缘贴图。

    Scalar cannyThreshold = mean(filter);
    // Canny Edge Detection
    Canny(filter, canny, cannyThreshold[0]*(2/3), cannyThreshold[0]*(1+(1/3)), 3);

接下来,我将互相关与直径递增的模板一起使用,并存储得分超过阈值的匹配项
    // Iterate through diameter ranges
    for (int r = 40; r < 70; r++)
    {
        Mat _mask, _template(Size((r * 2) + 4, (r * 2) + 4), CV_8U);
        _template = Scalar(0, 0, 0);
        _mask = _template.clone();
        _mask = Scalar(0, 0, 0);
        circle(_template, Point(r + 4, r + 4), r, Scalar(255, 255, 255), 2, CV_AA);
        circle(_template, Point(r + 4, r + 4), r / 3.592, Scalar(255, 255, 255), 2, CV_AA);
        circle(_mask, Point(r + 4, r + 4), r + 4, Scalar(255, 255, 255), -1);

        Mat res_32f(canny.rows, canny.cols, CV_32FC1);
        matchTemplate(canny, _template, res_32f, CV_TM_CCORR_NORMED, _mask);
        Mat resize(canny.rows, canny.cols, CV_32FC1);
        resize = Scalar(0, 0, 0);
        res_32f.copyTo(resize(Rect((resize.cols - res_32f.cols) / 2, (resize.rows - res_32f.rows) / 2, res_32f.cols, res_32f.rows)));
        // Strore Well Scoring Results
        double minVal, maxVal;
        double threshold = .25;
        do
        {
            Point minLoc, maxLoc;
            minMaxLoc(resize, &minVal, &maxVal, &minLoc, &maxLoc);
            if (maxVal > threshold)
            {
                matches.push_back(CircleScore(maxLoc.x, maxLoc.y, r, maxVal,1));
                circle(resize, maxLoc, 30, Scalar(0, 0, 0), -1);
            }

        } while (maxVal > threshold);
    }

我筛选出各个区域中最匹配的圈子
// Sort Matches For Best Match
    for (size_t i = 0; i < matches.size(); i++)
    {
        size_t j = i + 1;
        while (j < matches.size())
        {
            if (norm(Point2f(matches[i].X, matches[i].Y) - Point2f(matches[j].X, matches[j].Y)) - abs(matches[i].Radius - matches[j].Radius) < 15)
            {
                if (matches[j].Score > matches[i].Score)
                {
                    matches[i] = matches[j];
                }
                matches[j] = matches[matches.size() - 1];
                matches.pop_back();
                j = i + 1;
            }
            else j++;
        }
    }

接下来是棘手的一个。我想看看哪个部分可能最重要。为此,我检查了每组比半径总和更近的部分,然后查看重叠区域中的边缘是否彼此之间更强匹配。任何有盖的圆在重叠区域都应具有很少的坚固边缘。
    // Layer Sort On Intersection
    for (size_t i = 0; i < matches.size(); i++)
    {
        size_t j = i + 1;
        while (j < matches.size())
        {
            double distance = norm(Point2f(matches[i].X, matches[i].Y) - Point2f(matches[j].X, matches[j].Y));
            // Potential Overlapping Part
            if (distance < ((matches[i].Radius+matches[j].Radius) - 10))
            {
                int score_i = 0, score_j = 0;
                Mat intersect_a(canny.rows, canny.cols, CV_8UC1);
                Mat intersect_b(canny.rows, canny.cols, CV_8UC1);
                intersect_a = Scalar(0, 0, 0);
                intersect_b = Scalar(0, 0, 0);
                circle(intersect_a, Point(cvRound(matches[i].X), cvRound(matches[i].Y)), cvRound(matches[i].Radius) +4, Scalar(255, 255, 255), -1);
                circle(intersect_a, Point(cvRound(matches[i].X), cvRound(matches[i].Y)), cvRound(matches[i].Radius / 3.592-4), Scalar(0, 0, 0), -1);
                circle(intersect_b, Point(cvRound(matches[j].X), cvRound(matches[j].Y)), cvRound(matches[j].Radius) + 4, Scalar(255, 255, 255), -1);
                circle(intersect_b, Point(cvRound(matches[j].X), cvRound(matches[j].Y)), cvRound(matches[j].Radius / 3.592-4), Scalar(0, 0, 0), -1);
                bitwise_and(intersect_a, intersect_b, intersect_a);
                double a, h;
                a = (matches[i].Radius*matches[i].Radius - matches[j].Radius*matches[j].Radius + distance*distance) / (2 * distance);
                h = sqrt(matches[i].Radius*matches[i].Radius - a*a);
                Point2f p0((matches[j].X - matches[i].X)*(a / distance) + matches[i].X, (matches[j].Y - matches[i].Y)*(a / distance) + matches[i].Y);
                circle(intersect_a, Point2f(p0.x + h*(matches[j].Y - matches[i].Y) / distance, p0.y - h*(matches[j].X - matches[i].X) / distance), 6, Scalar(0, 0, 0), -1);
                circle(intersect_a, Point2f(p0.x - h*(matches[j].Y - matches[i].Y) / distance, p0.y + h*(matches[j].X - matches[i].X) / distance), 6, Scalar(0, 0, 0), -1);
                bitwise_and(intersect_a, canny, intersect_a);
                intersect_b = Scalar(0, 0, 0);
                circle(intersect_b, Point(cvRound(matches[i].X), cvRound(matches[i].Y)), cvRound(matches[i].Radius), Scalar(255, 255, 255), 6);
                bitwise_and(intersect_a, intersect_b, intersect_b);
                score_i = countNonZero(intersect_b);
                intersect_b = Scalar(0, 0, 0);
                circle(intersect_b, Point(cvRound(matches[j].X), cvRound(matches[j].Y)), cvRound(matches[j].Radius), Scalar(255, 255, 255), 6);
                bitwise_and(intersect_a, intersect_b, intersect_b);
                score_j = countNonZero(intersect_b);
                if (score_i < score_j)matches[i].Layer = matches[j].Layer + 1;
                if (score_j < score_i)matches[j].Layer = matches[i].Layer + 1;
            }
            j++;
        }
    }

之后,很容易提取出最适合的部分(Im也与深度数据相关)

enter image description here

蓝色的圆圈是部分,绿色的圆圈是最高的堆栈,红色的圆圈是在其他部分下面的部分。

我希望这可以帮助其他人解决类似的问题

关于c++ - 边缘提取建议OpenCV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35711804/

相关文章:

c++ - ar : not keeping file modification times

c++ - 通过 msi.dll 一次更改 MSI 表中列中的所有值

opencv - OpenCV 中的层次聚类

c++ - OpenCv:翻译图像,将像素环绕边缘 (C++)

computer-vision - 是否有任何程序可以对计算机视觉管道进行原型(prototype)设计?

c++ - 从 std::true_type 继承 vs static constexpr const bool 成员

c++ - 间隔树 - 主要功能障碍的功能

image-processing - DFT 频率分量 Opencv

iphone - iPhone上的号码识别可以实时进行吗?

c++ - OpenCV 3.0 无法加载神经网络