问题描述
我想计算红色圆圈的半径(图2).我在使用OpenCV的HoughCircles查找这些圈子时遇到了麻烦.如您在图中所见. 2我只能使用HoughCircles在中心找到以黑色显示的小圆圈.
I want to compute the red circles radius (fig 2). I have troubles finding these circles using HoughCircles from OpenCV. As you can see in fig. 2 I can only find the little circles in center which are shown in black using HoughCircles.
原始图2.
由于我知道红色圆圈的中心(与红色圆圈相同),有没有办法简单地计算红色圆圈的半径?
Since I know the center of the red circles (which are the same as the red ones), is there a way to compute simply the radius of the red circles ?
是否还有一种通用的方法可以在像这样的更复杂的图像上计算圆的半径:
Is it also possible to have a generic way of computing radius of circles on a more complex image such as this one :
获得图2之后,这是我代码中有趣的部分:
Edit : Here the interesting part of my code after obtaining fig 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和累加器使用play,但没有结果.实际图像大5倍.在此处链接例如阈值后的1.
I have tried to use play with cannyThreshold and accumulator without results. Real images are 5x biggers. Here a link for example 1 after threshold.
谢谢
推荐答案
您已经知道图像中的较小圆圈(用黑色绘制).
You already know the smaller circles in the image(which you have drawn in black).
- 使用这些圆圈准备遮罩图像,因此圆圈较小的区域将具有非零像素.我们将其称为面具:
- 在原始图像中,用深色(例如黑色)填充这些圆圈区域.这将产生类似于您的无花果2的图像.我们将其称为填充
- 阈值填充图像以获取深色区域.我们将其称为 binary .您可以为此使用Otsu阈值.结果将如下所示:
- In the original image, fill these circle areas in a dark color(say black). This will result in an image like your fig 2. We'll call it filled
- Threshold the filled image to obtain the dark areas. We'll call it binary. You can use Otsu thresholding for this. Result will look something like this:
- 进行此 binary 图片的距离变换.为此,请使用准确的距离估算方法.我们将其称为 dist .它看起来像这样.彩色的只是为了更加清晰起见的热图:
- Take the distance transform of this binary image. Use an accurate distance estimation method for this. We'll call this dist. It'll look something like this. The colored one is just a heat map for more clarity:
- 使用遮罩从 dist 获取峰区域.每个此类区域的最大值应为您提供较大圆的半径.您还可以对这些区域进行一些处理,以获取更合理的半径值,而不仅仅是获取最大值.
- 要选择区域,您可以找到遮罩的轮廓,然后从 dist 图像中提取该区域,或者,因为您已经知道了应用霍夫圆变换,从每个圆中准备一个蒙版,然后从 dist 图像中提取该区域.我不确定您是否可以通过设置掩码来计算最大值或其他统计信息. Max绝对可以工作,因为其余像素为0.如果将这些像素提取到另一个数组中,则可以计算区域的统计信息.
- Use the mask to obtain the peak regions from dist. The max value of each such region should give you the radius of the larger circle. You can also do some processing on these regions to arrive at a more reasonable value for radius rather than just picking up the max.
- For selecting the regions, you can either find the contours of the mask and then extract that region from dist image, or, since you already know the smaller circles from applying hough-circle transform, prepare a mask from each of those circles and extract that region from dist image. I'm not sure if you can calculate max or other stats by giving a mask. Max will definitely work because the rest of the pixels are 0. You might be able calculate the stats of the region if you extract those pixels to another array.
下图显示了这样的蒙版和从 dist 中提取的区域.为此,我得到大约29的最大值,该最大值与该圆的半径一致.请注意,图像没有按比例缩放.
Figures below show such mask and the extracted region from dist. For this I get a max around 29 which is consistent with the radius of that circle. Note that the images are not to scale.
遮罩一个圆圈,从 dist
这是代码(我没有使用霍夫圆变换):
Here's the code (I'm not using hough-circles transform):
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();
结果(按比例):
希望这会有所帮助.
这篇关于使用OpenCV查找重叠/复杂的圆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!