user3601754
user3601754

Reputation: 3862

Calculating a transform with a circle and lines

I am trying to determine the transformation (rotation + translation + scale) between two images in order to shift them.

The images are taken with two different modalities that produce very different textures. So I can't use techniques based on maintaining the optical flow. I thought it would be nice to threshold the images to extract the geometries (see example below). But then I have trouble seeing what I could do...maybe extract the vertical lines and the central circle to help me extract my transformation.

I work in python, I looked at what Opencv could offer but with few success for the moment.

enter image description here

--- EDIT LATER ---

I detected the circle and lines with the Hough transform (see figure below). Indeed, this will help for a proper registration. However, what tool on Python can I use to register these elements? I often use optical flow conservation, but in this case it's rather complicated...

enter image description here

Upvotes: 5

Views: 880

Answers (3)

Richard
Richard

Reputation: 3414

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.

  1. 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)
  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)
  1. 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)
  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.

Upvotes: 1

ma.mehralian
ma.mehralian

Reputation: 1285

Find at least 4 non-collinear corresponding points:

  1. Disk center
  2. Find the closest points on the side lines to the disk center (at least 2 corresponding points will be calculated). It is on the line perpendicular to the side lines through the disk center (use this method).
  3. Find parallel lines of the side lines through the disk center (this may help) and calculate the intersection point of that lines and disk area (this may help)

Then you can use findHomography to calculate the Homography matrix which is the transformation between two images.

sample code is similar to the following one:

# Read the first image.
im_fst = cv2.imread('img1.jpg')
# Four points in the first image (more is better)
pts_fst = np.array([[141, 131], [480, 159], [493, 630],[64, 601]])
 
# Read the second image.
im_scd = cv2.imread('img2.jpg')
# Four points in the second image
pts_scd = np.array([[318, 256],[534, 372],[316, 670],[73, 473]])
 
# Calculate Homography
h, status = cv2.findHomography(pts_fst, pts_scd)
     
# Warp source image to destination based on homography
im_out = cv2.warpPerspective(im_fst, h, (im_scd.shape[1],im_scd.shape[0]))

Upvotes: 4

user1196549
user1196549

Reputation:

If the pattern is always a disk inside a lane, with clean binarization, this looks like an easy problem.

You can reliably and accurately obtain the disk center and area, hence radius. From the side blobs you can find the verticals (Hough, or line fitting to the inner section of the contours, or just line through pairs of distant points).

Then you get the scale from the ratio of radii, or ratio of distances between the lines. The rotation angle is given by the direction of the verticals. And the translation by the coordinates of the center.

Actually, you have too much data to solve for the 4 DOF, and there are several possible resolutions. Depending on how exactly those images are produced, you should use the most reliable pieces of information.

enter image description here

Upvotes: 2

Related Questions