如何通过opencv计算图像中两个圆的距离
How to calculate the distance of two circles in a image by opencv
带有两个圆圈的图片
我有一张包含两条纤维的图像(在图像中显示为两个圆圈)。如何计算两根光纤的距离?
我发现很难检测到光纤的位置。我试过使用HoughCircles函数,但是参数很难优化,而且很多时候不能精确定位圆。我应该先减去背景还是有其他方法?非常感谢!
很遗憾,您没有显示预处理步骤。在我的方法中,我将执行以下操作:
- 将输入图像转换为灰度(参见
cvtColor
)。
- 中值模糊,保持 "edges"(参见
medianBlur
)。
- 自适应阈值(参见
adaptiveTreshold
)。
- 去除小噪声的形态学开放(参见
morphologyEx
)。
- 按
HoughCircles
查找圈子。
- 此处未完成:可能对找到的圈子进行改进。排除太小或太大的圆圈。使用您拥有的所有先前信息!例如,圆到底可以有多大?
这是我的全部代码:
// Read image.
cv::Mat img = cv::imread("images/i7aJJ.jpg", cv::IMREAD_COLOR);
// Convert to grayscale for processing.
cv::Mat blk;
cv::cvtColor(img, blk, cv::COLOR_BGR2GRAY);
// Median blurring to improve following thresholding.
cv::medianBlur(blk, blk, 11);
// Adaptive thresholding.
cv::adaptiveThreshold(blk, blk, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 51, -2);
// Morphological opening to get rid of small noise.
cv::morphologyEx(blk, blk, cv::MORPH_OPEN, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3)));
// Find circles using Hough transform.
std::vector<cv::Vec4f> circles;
cv::HoughCircles(blk, circles, cv::HOUGH_GRADIENT, 1.0, 300, 50, 25, 100);
// TODO: Refinement of found circles, if there are more than two.
// For example, calculate areas: Neglect too small or too large areas.
// Compare all areas, and keep the two with nearly matching areas and
// suitable areas.
// Draw circles in input image.
for (Vec4f& circle : circles) {
cv::circle(img, cv::Point(circle[0], circle[1]), circle[2], cv::Scalar(0, 0, 255), 4);
cv::circle(img, cv::Point(circle[0], circle[1]), 5, cv::Scalar(0, 255, 0), cv::FILLED);
}
// --- Assuming there are only the two right circles left from here. --- //
// Draw some debug output in input image.
const cv::Point c1 = cv::Point(circles[0][0], circles[0][1]);
const cv::Point c2 = cv::Point(circles[1][0], circles[1][1]);
cv::line(img, c1, c2, cv::Scalar(255, 0, 0), 2);
// Calculate distance, and put in input image.
double dist = cv::norm(c1 - c2);
cv::putText(img, std::to_string(dist), cv::Point((c1.x + c2.x) / 2 + 20, (c1.y + c2.y) / 2 + 20), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255, 0, 0));
最终输出如下所示:
HoughCircles
操作之前的中间图像如下所示:
总的来说,我对 HoughCircles
并没有那么怀疑。你"just"要注意你的预处理。
希望对您有所帮助!
使用霍夫圆检测是可以的,但如果你想要更稳定的检测,你应该提供更多的图像。我只是去噪并直接进行圆圈检测。使用 non-local 意味着去噪在保留边缘方面非常好,这反过来又有利于 hough 圆算法中包含的 canny 边缘算法。
我的代码是用 Python 编写的,但可以很容易地翻译成 C++。
import cv2
from matplotlib import pyplot as plt
IM_PATH = 'your image path'
DS = 2 # downsample the image
orig = cv2.imread(IM_PATH, cv2.IMREAD_GRAYSCALE)
orig = cv2.resize(orig, (orig.shape[1] // DS, orig.shape[0] // DS))
img = cv2.fastNlMeansDenoising(orig, h=3, templateWindowSize=20 // DS + 1, searchWindowSize=40 // DS + 1)
plt.imshow(orig, cmap='gray')
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, dp=1, minDist=200 // DS, param1=40 // DS, param2=40 // DS, minRadius=210 // DS, maxRadius=270 // DS)
if circles is not None:
for x, y, r in circles[0]:
c = plt.Circle((x, y), r, fill=False, lw=1, ec='C1')
plt.gca().add_patch(c)
plt.gcf().set_size_inches((12, 8))
plt.show()
重要
进行一些图像处理只是良好(且稳定!)目标检测的第一步。您必须利用每一个细节和 属性 您可以动手并应用一些统计数据来改善您的结果。例如:
- 使用Yves' approach作为加法并过滤所有检测到的不与关节相交的圆。
- 一个圆圈总是在另一个圆圈下面吗?过滤掉水平对齐的对。
- 你能降低投资回报率吗(圆圈总是在图像中的特定区域还是到处都是)?
- 两个圆圈总是一样大吗?过滤掉大小不同的对。
- ...
如果您可以使用多个指标,则可以应用统计模型(例如多数投票或 knn)来找到最佳的一对圆圈。
再说一次:总是想想你对你的对象、环境及其行为的了解,并利用这些知识。
带有两个圆圈的图片
我有一张包含两条纤维的图像(在图像中显示为两个圆圈)。如何计算两根光纤的距离?
我发现很难检测到光纤的位置。我试过使用HoughCircles函数,但是参数很难优化,而且很多时候不能精确定位圆。我应该先减去背景还是有其他方法?非常感谢!
很遗憾,您没有显示预处理步骤。在我的方法中,我将执行以下操作:
- 将输入图像转换为灰度(参见
cvtColor
)。 - 中值模糊,保持 "edges"(参见
medianBlur
)。 - 自适应阈值(参见
adaptiveTreshold
)。 - 去除小噪声的形态学开放(参见
morphologyEx
)。 - 按
HoughCircles
查找圈子。 - 此处未完成:可能对找到的圈子进行改进。排除太小或太大的圆圈。使用您拥有的所有先前信息!例如,圆到底可以有多大?
这是我的全部代码:
// Read image.
cv::Mat img = cv::imread("images/i7aJJ.jpg", cv::IMREAD_COLOR);
// Convert to grayscale for processing.
cv::Mat blk;
cv::cvtColor(img, blk, cv::COLOR_BGR2GRAY);
// Median blurring to improve following thresholding.
cv::medianBlur(blk, blk, 11);
// Adaptive thresholding.
cv::adaptiveThreshold(blk, blk, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 51, -2);
// Morphological opening to get rid of small noise.
cv::morphologyEx(blk, blk, cv::MORPH_OPEN, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3)));
// Find circles using Hough transform.
std::vector<cv::Vec4f> circles;
cv::HoughCircles(blk, circles, cv::HOUGH_GRADIENT, 1.0, 300, 50, 25, 100);
// TODO: Refinement of found circles, if there are more than two.
// For example, calculate areas: Neglect too small or too large areas.
// Compare all areas, and keep the two with nearly matching areas and
// suitable areas.
// Draw circles in input image.
for (Vec4f& circle : circles) {
cv::circle(img, cv::Point(circle[0], circle[1]), circle[2], cv::Scalar(0, 0, 255), 4);
cv::circle(img, cv::Point(circle[0], circle[1]), 5, cv::Scalar(0, 255, 0), cv::FILLED);
}
// --- Assuming there are only the two right circles left from here. --- //
// Draw some debug output in input image.
const cv::Point c1 = cv::Point(circles[0][0], circles[0][1]);
const cv::Point c2 = cv::Point(circles[1][0], circles[1][1]);
cv::line(img, c1, c2, cv::Scalar(255, 0, 0), 2);
// Calculate distance, and put in input image.
double dist = cv::norm(c1 - c2);
cv::putText(img, std::to_string(dist), cv::Point((c1.x + c2.x) / 2 + 20, (c1.y + c2.y) / 2 + 20), cv::FONT_HERSHEY_COMPLEX, 1.0, cv::Scalar(255, 0, 0));
最终输出如下所示:
HoughCircles
操作之前的中间图像如下所示:
总的来说,我对 HoughCircles
并没有那么怀疑。你"just"要注意你的预处理。
希望对您有所帮助!
使用霍夫圆检测是可以的,但如果你想要更稳定的检测,你应该提供更多的图像。我只是去噪并直接进行圆圈检测。使用 non-local 意味着去噪在保留边缘方面非常好,这反过来又有利于 hough 圆算法中包含的 canny 边缘算法。
我的代码是用 Python 编写的,但可以很容易地翻译成 C++。
import cv2
from matplotlib import pyplot as plt
IM_PATH = 'your image path'
DS = 2 # downsample the image
orig = cv2.imread(IM_PATH, cv2.IMREAD_GRAYSCALE)
orig = cv2.resize(orig, (orig.shape[1] // DS, orig.shape[0] // DS))
img = cv2.fastNlMeansDenoising(orig, h=3, templateWindowSize=20 // DS + 1, searchWindowSize=40 // DS + 1)
plt.imshow(orig, cmap='gray')
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, dp=1, minDist=200 // DS, param1=40 // DS, param2=40 // DS, minRadius=210 // DS, maxRadius=270 // DS)
if circles is not None:
for x, y, r in circles[0]:
c = plt.Circle((x, y), r, fill=False, lw=1, ec='C1')
plt.gca().add_patch(c)
plt.gcf().set_size_inches((12, 8))
plt.show()
重要
进行一些图像处理只是良好(且稳定!)目标检测的第一步。您必须利用每一个细节和 属性 您可以动手并应用一些统计数据来改善您的结果。例如:
- 使用Yves' approach作为加法并过滤所有检测到的不与关节相交的圆。
- 一个圆圈总是在另一个圆圈下面吗?过滤掉水平对齐的对。
- 你能降低投资回报率吗(圆圈总是在图像中的特定区域还是到处都是)?
- 两个圆圈总是一样大吗?过滤掉大小不同的对。
- ...
如果您可以使用多个指标,则可以应用统计模型(例如多数投票或 knn)来找到最佳的一对圆圈。
再说一次:总是想想你对你的对象、环境及其行为的了解,并利用这些知识。