I had a very similar problem to yours, with trying to center circular objects within both CT and MR images - and went down various routes with registration, hough transforms etc etc. All sort of worked, but slow and complex and not hugely robust.
I ended up using a much simpler, more robust, and much faster approach by stepping back and thinking about it differently.
You have two circles in an an image and you want to find the location and scale.
- So first get two 1D profiles of your image - one in rows and one in columns. Your object is a circle, so that will result in two gaussian like 1-D profiles. This is simple array slicing with mean, so is very fast:
# r/c 1/0 are variables you can use to set limits on which areas of
# the image you want to limit the search to, or you can use the entire
# image size
r0 = c0 = 0
r1, c1 = image.shape
r_prof = np.mean(image[r0:r1, :], axis=0)
c_prof = np.mean(image[:, c0:c1], axis=1)
- Find the center point of those gaussian profiles. This is easy with any peak finding algorithms. That gives you the center of your circle.
# find_peak is a function to find the peak index in a profile
circle_r = find_peak(r_profile)
circle_c = find_peak(c_profile)
- To find the scale you need to find the size of the circle. To do that, just re-do the image profiles, but this time with the row/column narrowed to a single pixel at the center of the circle you got above. That will give you a pretty much square profile.
# get single pixel width profile across center of circle
r_prof = np.mean(image[circle_r, :], axis=0)
c_prof = np.mean(image[:, circle_c], axis=1)
- From a square profile it's easy to calculate the edges, and the difference between the locations of the two edges gives you the diameter.
So from that you end up with the center and diameter of the circle.
I use this approach to do what you're doing - location and size of circular profile - in both CT and MR. It's ended up being at least order magnitude faster than anything else, and much more robust.