您已经知道图像中的较小圆圈(您用黑色绘制)。
- 使用这些圆圈准备蒙版图像,以便具有较小圆圈的区域将具有非零像素。我们将称之为mask:
- 在原始图像中,用深色(例如黑色)填充这些圆形区域。这将产生如图 2 所示的图像。我们将其称为filled
- 阈值filled图像以获得暗区域。我们将称之为binary。为此,您可以使用 Otsu 阈值。结果看起来像这样:
- 对其进行距离变换binary图像。为此,请使用准确的距离估计方法。我们称之为dist。它看起来像这样。为了更清晰起见,彩色图只是一张热图:
- Use the mask获得峰值区域dist。每个此类区域的最大值应该给出较大圆的半径。您还可以对这些区域进行一些处理,以获得更合理的半径值,而不仅仅是选取最大值。
- 为了选择区域,您可以找到区域的轮廓mask然后从中提取该区域dist图像,或者,因为您已经通过应用霍夫圆变换知道了较小的圆,所以从每个圆中准备一个掩模并从dist图像。我不确定您是否可以通过给出掩码来计算最大值或其他统计数据。 Max 肯定会起作用,因为其余像素都是 0。如果将这些像素提取到另一个数组,您也许可以计算该区域的统计数据。
下图显示了这样的掩模和从中提取的区域dist。为此,我得到的最大值约为 29,这与该圆的半径一致。请注意,图像未按比例绘制。
圆的掩模,从中提取的区域dist
这是代码(我没有使用霍夫圆变换):
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();
结果(缩放):
希望这可以帮助。