简体   繁体   中英

OpenCV: Fitting a single circle to an image (in Python)

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?

why don't you do thing like "close" then "open" to clear all the mess.

Raw image :

原始图像

Otsu :

大津

Close + open ; both with 7x7 kernel ; The binary image is beauty and clean now.

关闭+打开

Only one contour is detect :

一个轮廓

The ellipse is as : (please not that your image is circle so ellipse should be in circle shape)

椭圆

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

在此输入图像描述 在此输入图像描述

After applying an adaptive threshold to the image, you can use morphological operations to smooth your image with cv2.erode() and cv2.dilate() . By doing these operations, you will be able to isolate your main circle image and remove small particles of noise. Next, you can locate the circle in the image by using cv2.findContours() and filtering for the maximum size contour. This will give you bounding box coordinates where you can find the center of the circle. Once you have the center coordinates, you can then fit your eclipse.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM