【问题标题】:OpenCV: Fitting a single circle to an image (in Python)OpenCV:将单个圆圈拟合到图像(在 Python 中)
【发布时间】:2019-04-10 22:06:08
【问题描述】:

我有这样的图像:

我需要在暗区设置一个椭圆(注意:必须是椭圆,而不是圆形)。在 OpenCV 中执行此操作的最佳方法是什么?到目前为止,我的第一步是对其应用自适应 (Otsu) 阈值,结果是:

但我不知道从那里去哪里。我正在用 Python 编写应用程序,但它更像是我正在寻找的算法设计。

根据回复/评论进行编辑:

好的,所以我已经尝试了形态学。基于OpenCV documentation,我对其进行了3次迭代“关闭”操作(膨胀,然后腐蚀)以去除小颗粒,结果是:

然后,为了将其扩展回更接近原始形状,我进行了 3 次迭代“打开”操作(腐蚀,然后膨胀),结果是:

从这里开始,我做了 Canny 边缘检测,结果是:

现在,我在上面使用了findContours,但遇到了问题。它沿着边缘发现了几十个轮廓,每一个都是沿着圆周的一小段。这意味着,即使我采用最大尺寸轮廓,它也可能只代表周长的 10%,这不足以准确拟合椭圆。这就是为什么@Demi-Lune 提出的其他问题对我不起作用的原因;它们都有非常干净、锐利的边缘,findContours 找到了一个很好的单一轮廓,覆盖了每个形状的整个周边,但对于我的混乱图像来说,这不会发生。那么,从这里拟合椭圆的最佳方法是什么?

【问题讨论】:

  • @Demi-Lune 查看我在问题中的编辑。基本上,这些问题的形状很干净,边缘清晰,findContours 为这些问题找到了很好的单一轮廓;这不适用于我的杂乱图像。
  • 找到黑点的minarerect..它代表你的椭圆
  • 只有在圆圈外没有多余的点的情况下才有效,对吧?这就是这个特定图像的情况,但不是普遍的(我处理的一些图像可能在圆圈外到处都有奇怪的点,即使在形态学之后)。此外,如果圆的一侧“变平”(因此看起来更像“D”),则它不会适合最好的椭圆,它会适合更小的椭圆。
  • #1 正确,#2“最佳”是根据度量标准...“最小二乘误差”和“与边界点有更多重叠”产生不同的结果

标签: python opencv computer-vision


【解决方案1】:

如果对象是圆形的,那么使用cv2.minEnclosingCircle 是好的。或者,您可以使用cv2.fitEllipse 找到对象周围最适合的椭圆。记得在黑色背景中找到带有白色物体的轮廓。

import cv2
import numpy as np

img = cv2.imread("1.jpg")

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_,thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
thresh = cv2.bitwise_not(thresh)

element = cv2.getStructuringElement(shape=cv2.MORPH_RECT, ksize=(5, 5))

morph_img = thresh.copy()
cv2.morphologyEx(src=thresh, op=cv2.MORPH_CLOSE, kernel=element, dst=morph_img)

contours,_ = cv2.findContours(morph_img,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

areas = [cv2.contourArea(c) for c in contours]
sorted_areas = np.sort(areas)

#bounding box (red)
cnt=contours[areas.index(sorted_areas[-1])] #the biggest contour
r = cv2.boundingRect(cnt)
cv2.rectangle(img,(r[0],r[1]),(r[0]+r[2],r[1]+r[3]),(0,0,255),2)

#min circle (green)
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv2.circle(img,center,radius,(0,255,0),2)

#fit ellipse (blue)
ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(img,ellipse,(255,0,0),2)


cv2.imshow("morph_img",morph_img)
cv2.imshow("img", img)
cv2.waitKey()

【讨论】:

  • 谢谢,这工作得很好。假设我想“平均”来自minBoundingRectangle(特别是可以在其中嵌入的椭圆)和fitEllipse 函数的结果。我该怎么做呢?
【解决方案2】:

你为什么不先“关闭”然后“打开”来清除所有混乱。

原始图像:

大津:

关闭+打开;两者都具有 7x7 内核;二进制图像现在既漂亮又干净。

只检测一个轮廓:

椭圆如下:(请不要说您的图像是圆形,所以椭圆应该是圆形)

【讨论】:

  • 谢谢@Vu。现在,假设二进制阈值变形图像是实心的,但在侧面有一个“凸起”(一个突出的尖块)。如果我在此使用fitEllipse,凸起会影响拟合并使其更椭圆,但我需要一个最大化拟合点数的解决方案,而不是最小二乘。也就是说,它应该与形状的轮廓匹配尽可能多的点。
  • 不明白你在说什么。你应该添加一些图片来澄清你的问题
猜你喜欢
  • 2021-04-22
  • 1970-01-01
  • 2013-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-20
相关资源
最近更新 更多