I have been using skim age's thresholding algorithms to get some binary mask. For example, I obtain binary images like this:
What I am trying to figure out is how can I fit a circle to this binary mask. The constraint is the circle should cover as much of the white areas as possible and the whole circumference of the circle should lie entirely on the white parts.
I have been wrecking my head on how I can do this efficiently but have come up with no solution that works.
One approach I thought that might be something is:
Here is a solution that tries to make an optimal circle fit via minimization. It soon becomes apparent that the bubble isn't a circle :) Note the use of "regionprops" for easily determining area, centroid, etc. of regions.
from skimage import io, color, measure, draw, img_as_bool
import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt
image = img_as_bool(io.imread('bubble.jpg')[..., 0])
regions = measure.regionprops(measure.label(image))
bubble = regions[0]
y0, x0 = bubble.centroid
r = bubble.major_axis_length / 2.
def cost(params):
x0, y0, r = params
coords = draw.disk((y0, x0), r, shape=image.shape)
template = np.zeros_like(image)
template[coords] = 1
return -np.sum(template == image)
x0, y0, r = optimize.fmin(cost, (x0, y0, r))
import matplotlib.pyplot as plt
f, ax = plt.subplots()
circle = plt.Circle((x0, y0), r)
ax.imshow(image, cmap='gray', interpolation='nearest')
ax.add_artist(circle)
plt.show()
This should in general give very good and robust results:
import numpy as np
from skimage import measure, feature, io, color, draw
import matplotlib.pyplot as plt
img = color.rgb2gray(io.imread("circle.jpg"))
img = feature.canny(img).astype(np.uint8)
img[img > 0] = 255
coords = np.column_stack(np.nonzero(img))
model, inliers = measure.ransac(coords, measure.CircleModel,
min_samples=3, residual_threshold=1,
max_trials=500)
print(model.params)
rr, cc = draw.disk((model.params[0], model.params[1]), model.params[2],
shape=img.shape)
img = img * 0.5
img[rr, cc] += 128
plt.imshow(img)
plt.show()
This is actually a mostly solved problem in image processing. Looks like what you want is a Hough Transform, specifically the circular or elliptical kind. I believe the circular one is a bit less computationally intensive in general.
Here are some code examples for scikit-image that show pretty much exactly what you're trying to do. And here is a link to the documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With