边缘提取建议 OpenCV

Edge Extraction Suggections OpenCV

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

到目前为止我有以下内容

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);

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

我正在使用 HoughCircle 来尝试找到零件。不过,我并没有取得很大的成功,因为 HoughCircle 看起来非常挑剔,而且经常 returns 一个并不是真正最适合零件的圆圈。

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

编辑:

我已经尝试了下面评论中的建议。规范化做了一些改进,但在霍夫圆改变所需设置而不是稳定性之前删除了精明。

我认为现在我需要做一些类似具有非常开放阈值的霍夫圆的事情,然后找到一种方法来对结果进行评分。有什么好的方法可以对霍夫圆的结果进行评分,或者将结果与匹配百分比的精明输出相关联

我想我会 post 我的解决方案,因为有人可能会发现我的经验教训很有价值。

我开始拍摄几帧并将它们取平均。这解决了我在保留强边缘的同时遇到的一些噪音问题。接下来我做了一个基本的过滤器和精明的边缘来提取一个像样的边缘图。

    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++;
        }
    }

之后很容易提取最好的部分来挑选(我也与深度数据相关

蓝色圆圈是零件,绿色圆圈是最高堆叠,红色圆圈是其他零件下面的零件。

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