2014-09-04 104 views
5

我想计算红色圆圈半径(图2)。我遇到了使用OpenCV中的HoughCircles找到这些圈子的麻烦。正如你在图1中看到的那样。 2我只能找到使用HoughCircles以黑色显示的中心小圆圈。使用OpenCV查找重叠/复杂圆圈

原始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和累加器玩没有结果。真实的图像是5倍大。例如,a link例如在阈值之后。

谢谢

+0

你能显示你的HoughCircles代码吗?重叠/半圈等通常不是HoughCircles afaik的问题。 – Micka 2014-09-04 13:44:08

+0

谢谢Micka我只是加了一些代码 – coincoin 2014-09-04 13:56:49

+1

你可以把maskedImage保存到一个文件('imwrite(“maskedImage.jpg”,maskedImage)')并发布一个链接吗? – 2014-09-04 14:01:21

回答

5

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

  • 使用这些圆来准备掩模图像,使具有较小圆的区域将具有非零像素。我们叫它掩盖

enter image description here

  • 在原始图像中,深色填补这些领域圈(说黑)。这将导致像你的图2的图像。我们将其称为填充
  • 阈值的填充图像以获得黑暗的地区。我们将其称为二进制。你可以使用Otsu为此设定阈值。结果会是这个样子:

enter image description here

  • 乘坐距离变换这二进制形象。为此使用精确的距离估计方法。我们将这个称为dist。它看起来像这样。彩色一个仅仅是为了更清楚的热图:

enter image description hereenter image description here

  • 使用面具DIST获得峰值区域。每个这样的区域的最大值应该给你更大的圆的半径。您也可以对这些区域进行一些处理,以获得更为合理的半径值,而不仅仅是拾取最大值。
  • 对于选择区域,您可以找到面具的轮廓,然后从DIST图像提取区域,或者,因为你已经知道,从应用霍夫圆变换的小圆圈,准备从面具每个圈子从dist图像中提取该区域。我不确定你是否可以通过掩码来计算最大或其他属性。 Max肯定会工作,因为其余像素都是0.如果将这些像素提取到另一个阵列,则可能可以计算该区域的统计信息。

下图显示了这样的面罩和从dist提取的区域。为此,我得到最大值约为29,与该圆的半径一致。请注意,图像不是按比例绘制的。

掩模圆形,提取出的区域从DIST

enter image description hereenter 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 hereenter image description here

希望这会有所帮助。

+0

谢谢你这是个好主意。我已经使用distanceTransform获得了相同的结果。 (顺便说一句,你如何着色距离贴图applyColorMap似乎不适合我)。但是,我不明白我如何区分圆半径并有效计算这些最大值? – coincoin 2014-09-05 10:04:51

+1

在OpenCV中,距离转换结果的类型为float。尝试将其缩放到0-255范围并转换为键入uint8。然后applyColorMap将起作用。至于获得最大值,请参阅我编辑的帖子,看看我是否在那里回答了您的问题。 – dhanushka 2014-09-05 11:25:34

+0

谢谢你宝贵的答案。我得到了地图颜色,但我很难理解如何使用蒙板图像和小圆圈的中心来提取区域。你能详细说明这个部分吗? – coincoin 2014-09-05 14:36:37