使用OpenCV查找重叠/复杂圆圈

时间:2014-09-04 13:41:50

标签: 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。

由于

1 个答案:

答案 0 :(得分:5)

您已经知道图像中较小的圆圈(以黑色绘制)。

  • 使用这些圆圈准备遮罩图像,以使具有较小圆圈的区域具有非零像素。我们称之为面具

enter image description here

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

enter image description here

  • 获取此二进制图像的距离变换。为此使用精确的距离估计方法。我们称之为 dist 。它看起来像这样。有色的只是一张热图,更清晰:

enter image description here enter image description here

  • 使用掩码 dist 获取峰值区域。每个此类区域的最大值应该为您提供较大圆的半径。您还可以对这些区域进行一些处理,以获得更合理的半径值,而不是仅仅拿起最大值。
  • 要选择区域,您可以找到面具的轮廓,然后从 dist 图像中提取该区域,或者,因为您已经知道来自 dist 图像的较小圆圈应用霍夫圆变换,从每个圆圈中准备一个遮罩,并从 dist 图像中提取该区域。我不确定你是否可以通过给出一个面具来计算最大或其他数据。 Max肯定会工作,因为其余像素为0.如果将这些像素提取到另一个数组,您可以计算区域的统计数据。

下图显示了此类面具和 dist 中提取的区域。为此,我获得了大约29的最大值,这与该圆的半径一致。请注意,图像不是按比例缩放的。

一个圆圈的掩码,从 dist

中提取的区域

enter image description here enter image description here

这是代码(我不使用hough-circles变换):

    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

希望这有帮助。