opencv - 使用 OpenCV 查找重叠/复杂的圆

标签 opencv image-processing

我想计算红色圆圈的半径(图 2)。我无法使用 OpenCV 中的 HoughCircles 找到这些圈子。如图所示。 2 我只能使用 HoughCircles 找到中心显示为黑色的小圆圈。

原创pic1图 2。red

因为我知道红色圆圈的中心(与红色圆圈相同),有没有办法简单地计算红色圆圈的半径?

是否也可以有一种通用的方法来计算更复杂的图像(例如这幅图像)上的圆半径:

example 2

编辑:这里是获得图 2 后我的代码中有趣的部分:

threshold(maskedImage, maskedImage, thresh, 255, THRESH_BINARY_INV | THRESH_OTSU);
    std::vector<Vec3f> circles;
// Canny(maskedImage, maskedImage, thresh, thresh * 2, 3);

HoughCircles(maskedImage, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows / 4, cannyThreshold, accumulatorThreshold, 0, 0);

Mat display = src_display.clone();
for (size_t i = 0; i < circles.size(); i++)
{
    Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
    int radius = cvRound(circles[i][2]);
    // circle center
    circle(display, center, 3, Scalar(0, 255, 0), -1, 8, 0);
    // circle outline
    circle(display, center, radius, Scalar(0, 0, 255), 3, 8, 0);
}

我尝试使用 cannyThreshold 和 accumulator 玩游戏,但没有结果。真实图像大 5 倍。这里a link例如阈值后的 1。

谢谢

最佳答案

你已经知道图像中的小圆圈(你用黑色画的)。

  • 使用这些圆圈准备蒙版图像,这样圆圈较小的区域将具有非零像素。我们称之为面具:

enter image description here

  • 在原始图像中,用深色(比如黑色)填充这些圆圈区域。这将生成类似于图 2 的图像。我们将其称为填充
  • 填充图像进行阈值处理以获得暗区。我们称之为二进制。您可以为此使用 Otsu 阈值。结果将如下所示:

enter image description here

  • 对这张二进制 图像进行距离变换。为此使用准确的距离估计方法。我们称之为 dist。它看起来像这样。为了更清楚起见,彩色的只是一张热图:

enter image description here enter image description here

  • 使用ma​​skdist 获取峰区域。每个这样的区域的最大值应该给你更大的圆的半径。您还可以对这些区域进行一些处理,以获得更合理的半径值,而不仅仅是选择最大值。
  • 要选择区域,您可以找到ma​​sk 的轮廓,然后从dist 图像中提取该区域,或者,因为您已经知道来自应用 hough-circle 变换,从每个圆圈中准备一个蒙版,并从 dist 图像中提取该区域。我不确定你是否可以通过给面具来计算最大值或其他统计数据。 Max 肯定会起作用,因为其余像素为 0。如果将这些像素提取到另一个数组,您可能能够计算该区域的统计数据。

下图显示了这样的蒙版和从 dist 中提取的区域。为此,我得到的最大值约为 29,这与该圆的半径一致。请注意,图片未按比例缩放。

圆圈的 mask ,从 dist 中提取的区域

enter image description here enter image description here

这是代码(我没有使用霍夫圆变换):

    Mat im = imread(INPUT_FOLDER_PATH + string("ex1.jpg"));

    Mat gray;
    cvtColor(im, gray, CV_BGR2GRAY);

    Mat bw;
    threshold(gray, bw, 0, 255, CV_THRESH_BINARY|CV_THRESH_OTSU);
    // filtering smaller circles: not using hough-circles transform here. 
    // you can replace this part with you hough-circles code.
    vector<int> circles;
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
    for(int idx = 0; idx >= 0; idx = hierarchy[idx][0])
    {
        Rect rect = boundingRect(contours[idx]);
        if (abs(1.0 - ((double)rect.width/rect.height) < .1))
        {
            Mat mask = Mat::zeros(im.rows, im.cols, CV_8U);
            drawContours(mask, contours, idx, Scalar(255, 255, 255), -1);
            double area = sum(mask).val[0]/255;
            double rad = (rect.width + rect.height)/4.0;
            double circArea = CV_PI*rad*rad;
            double dif = abs(1.0 - area/circArea);
            if (dif < .5 && rad < 50 && rad > 30)   // restrict the radius
            {
                circles.push_back(idx); // store smaller circle contours
                drawContours(gray, contours, idx, Scalar(0, 0, 0), -1); // fill circles
            }
        }
    }

    threshold(gray, bw, 0, 255, CV_THRESH_BINARY_INV|CV_THRESH_OTSU);

    Mat dist, distColor, color;
    distanceTransform(bw, dist, CV_DIST_L2, 5);
    double max;
    Point maxLoc;
    minMaxLoc(dist, NULL, &max);
    dist.convertTo(distColor, CV_8U, 255.0/max);
    applyColorMap(distColor, color, COLORMAP_JET);
    imshow("", color);
    waitKey();

    // extract dist region corresponding to each smaller circle and find max
    for(int idx = 0; idx < (int)circles.size(); idx++)
    {
        Mat masked;
        Mat mask = Mat::zeros(im.rows, im.cols, CV_8U);
        drawContours(mask, contours, circles[idx], Scalar(255, 255, 255), -1);
        dist.copyTo(masked, mask);
        minMaxLoc(masked, NULL, &max, NULL, &maxLoc);
        circle(im, maxLoc, 4, Scalar(0, 255, 0), -1);
        circle(im, maxLoc, (int)max, Scalar(0, 0, 255), 2);
        cout << "rad: " << max << endl;
    }
    imshow("", im);
    waitKey();

结果(缩放):

enter image description here enter image description here

希望这对您有所帮助。

关于opencv - 使用 OpenCV 查找重叠/复杂的圆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25667053/

相关文章:

opencv - conda install opencv ImportError : the specified module could not be found

c++ - OpenCV inRange 改变 Mat 类型

matlab - 在低分辨率灰度图像中查找重叠圆的中心

java - Swing PixelGrabber - 数据排序

image-processing - 在序列matlab中提取字符

image-processing - 物体检测/物体识别?

python - cv2.fitEllipse 如何处理旋转的宽度/高度?

python - cv2 videowriter,写得很好,但在应用程序关闭时抛出错误

c++ - 在 OpenCV Mat 中高效查找元素

python - 调整图像大小时如何最大程度地减少模糊度?