I have binarized images like this one:
I need to determine the center and radius of the inner solid disk. As you can see, it is surrounded by a textured area which touches it, so that simple connected component detection doesn't work. Anyway, there is a void margin on a large part of the perimeter.
A possible cure could be by eroding until all the texture disappears or disconnects from the disk, but this can be time consuming and the number of iterations is unsure. (In addition, in some unlucky cases there are tiny holes in the disk, which will grow with erosion.)
Any better suggestion to address this problem in a robust and fast way ? (I tagged OpenCV, but this is not mandated, what matters is the approach.)
My second attempt on this case. This time I am using morphological closing operation to weaken the noise and maintain the signal. This is followed by a simple threshold and a connectedcomponent analysis. I hope this code can run faster.
Using this method, i can find the centroid with subpixel accuracy
('center : ', (184.12244328746746, 170.59771290442544))
Radius is derived from the area of the circle.
('radius : ', 101.34704439389715)
Here is the full code
import cv2 import numpy as np # load image in grayscale image = cv2.imread('radius.png',0) r,c = image.shape # remove noise blured = cv2.blur(image,(5,5)) # Morphological closing morph = cv2.erode(blured,None,iterations = 3) morph = cv2.dilate(morph,None,iterations = 3) cv2.imshow("morph",morph) cv2.waitKey(0) # Get the strong signal th, th_img = cv2.threshold(morph,200,255,cv2.THRESH_BINARY) cv2.imshow("th_img",th_img) cv2.waitKey(0) # Get connected components num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(th_img) print(num_labels) print(stats) # displat labels labels_disp = np.uint8(255*labels/np.max(labels)) cv2.imshow("labels",labels_disp) cv2.waitKey(0) # Find center label cnt_label = labels[r/2,c/2] # Find circle center and radius # Radius calculated by averaging the height and width of bounding box area = stats[cnt_label] radius = np.sqrt(area / np.pi)#stats[cnt_label]/2 + stats[cnt_label]/2)/2 cnt_pt = ((centroids[cnt_label]),(centroids[cnt_label])) print('center : ',cnt_pt) print('radius : ',radius) # Display final result edges_color = cv2.cvtColor(image,cv2.COLOR_GRAY2BGR) cv2.circle(edges_color,(int(cnt_pt),int(cnt_pt)),int(radius),(0,0,255),1) cv2.circle(edges_color,(int(cnt_pt),int(cnt_pt)),5,(0,0,255),-1) x1 = stats[cnt_label] y1 = stats[cnt_label] w1 = stats[cnt_label] h1 = stats[cnt_label] cv2.rectangle(edges_color,(x1,y1),(x1+w1,y1+h1),(0,255,0)) cv2.imshow("edges_color",edges_color) cv2.waitKey(0)