OpenCV:使单个圆适合图像(在Python中) [英] OpenCV: Fitting a single circle to an image (in Python)

查看:59
本文介绍了OpenCV:使单个圆适合图像(在Python中)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一张这样的图片:

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

但是我不确定从那里去哪里.我正在用Python编写应用程序,但更多的是我正在寻找的算法设计.

根据回复/评论进行

好的,所以我已经尝试了形态.根据

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

在这里,我进行了Canny边缘检测,结果是:

现在,我在其上使用了 findContours ,但遇到了问题.它在边缘发现了数十个轮廓,每个轮廓沿圆周有一小段.这意味着,即使我采用最大尺寸的轮廓,它也可能仅代表圆周的10%,不足以精确地拟合椭圆.这就是为什么@ Demi-Lune提出的其他问题对我不起作用的原因.它们都具有非常干净,锋利的边缘,并且 findContours 找到了一个不错的单一轮廓,该轮廓覆盖了每种形状的整个贝米特,但是对于我的凌乱图像却没有发生.那么,从这里拟合椭圆的最佳方法是什么?

解决方案

如果对象具有圆形形状,则使用 cv2.minEnclosingCircle 是好的.否则,您可以使用 cv2.fitEllipse 在对象周围找到最合适的椭圆.记住要在黑色背景下找到带有白色物体的轮廓.

  import cv2将numpy导入为npimg = cv2.imread("1.jpg")灰色= cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)_,thresh = cv2.threshold(灰色,0,255,cv2.THRESH_BINARY + cv2.THRESH_OTSU)阈值= cv2.bitwise_not(阈值)元素= 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)等高线,_ = cv2.findContours(morph_img,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)面积= [c中的cv2.contourArea(c)]sorted_areas = np.sort(areas)#bounding box(红色)cnt = contours [areas.index(sorted_areas [-1])]#最大轮廓r = cv2.boundingRect(cnt)cv2.rectangle(img,(r [0],r [1]),(r [0] + r [2],r [1] + r [3]),(0,0,255),2)#min圈(绿色)(x,y),radius = cv2.minEnclosingCircle(cnt)中心=(int(x),int(y))半径= int(半径)cv2.circle(img,center,radius,(0,255,0),2)#fit椭圆(蓝色)椭圆= cv2.fitEllipse(cnt)cv2.ellipse(img,ellipse,(255,0,0),2)cv2.imshow("morph_img",morph_img)cv2.imshow("img",img)cv2.waitKey() 

I have an image like this:

I need to fit an ellipse to the dark area (note: must be an ellipse, not a circle). What is the best way to do this in OpenCV? My first step so far has been to apply an adaptive (Otsu) threshold to it, which results in:

But I'm not sure where to go from there. I'm writing the app in Python, but it's more the algorithm design I'm looking for.

EDIT based on response/comment:

OK, so I have already tried the morphology. Based on the OpenCV documentation, I did a 3-iteration "close" operation on it (dilation, then erosion) to remove the small particles, which results in:

Then, to expand it back out to closerto the original shape, I did a 3-iteration "open" operation (erosion, then dilation), which results in:

From here, I did Canny edge detection, which resulted in:

Now, I used findContours on it, but ran into an issue. It found dozens of contours along the edge, each one a short segment along the circumference. Which means, even if I take the maximum size contour, it might only represent 10% of the circumference, which is insufficient to accurately fit an ellipse. This is why the other questions that @Demi-Lune suggested didn't work for me; they all have very clean, sharp edges and findContours finds a nice single contour that covers the entire perimiter of each shape, but that doesn't happen for my messier image. So, what's the best way to fit the ellipse from here?

解决方案

If the object has circle shape, then use cv2.minEnclosingCircle is good. Or else, you can use cv2.fitEllipse to find the most fitted ellipse around the object. Remember to do find contour with white object in black background.

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()

这篇关于OpenCV:使单个圆适合图像(在Python中)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆