Oscar
Oscar

Reputation: 11

How to measure rotation angle of an image compared to a known template

I've succeeded on it by using the below method, but I'm sure there must be other more time-efficient alternatives to provide exact angle of rotation instead of an approximation as the method below. I'll be pleased to hear your feedback.

The procedure is based on the following steps:

  1. Import a template image (i.e.: with orientation at 0º)
  2. Create a discrete array of the same image but each one rotated at 360º/rotatesteps compared to its nearest neighbour (i.e.: 30 to 50 rotated images)

# python 3 / opencv 3

# Settings:
rotate_steps = 36
step_angle = round((360/rotate_steps), 0) # one image at each 10º

# Rotation function
def rotate_image(image, angle):
# ../..
return rotated_image

# Importing a sample image and creating a n-dimension array where to store images in:
image = cv2.imread('sample_image.png')
image_Array = np.zeros((image.shape[1], image.shape[0], 1), dtype='uint8')

# Rotating sample image and saving it into the array as a new channel:
while rotation_angle <= (360 - step_angle):
                           angles.append(rotation_angle)
                           image_array[:,:,channel] = rotate_image(image.copy(), rotation_angle)
# ../..

So I get:

angles = [0, 10.0, 20.0, 30.0, .../..., 340.0, 350.0]

image_array = [image_1, image_2, image_3, ...] where image_i is a different channel on a numpy array.

  1. Retrieve the 'test_image' for which I'm looking at the angle compared to the sample image we have previously rotated and stored into an array
  2. Follow a series of cv2.matchTemplate() and cv2.minMaxLoc() to find what rotated image's angle best matches the 'test_image'

for i in range(len(angles)):
  res = cv2.matchTemplate(test_image, image_array[:,:,i], cv2.TM_CCOEFF_NORMED)
  min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
  # ../..

  1. And finally I pick the discretized angle matching the sample image as the one corresponding to the template image with 'max_val' highest value.

This has proved to work well having in mind the resulting precision is based on an approximation with higher / lower precision depending on the amount of rotated template images, and also the rising time taken when rotated template number increases...

I'm sure there must be other smarter alternatives based on different methods such as generating a kind of "orientation vector" of an image, and so comparing just the resulting number with a previously known one from a sample template...

Your feedback will be highly appreciated.

Upvotes: 1

Views: 2856

Answers (1)

Soltius
Soltius

Reputation: 2273

I think your problem doesn't have an easy solution. It's in fact a registration problem, warping (in this case, rotating) an image to fit another. And it's a known difficult problem, as segmentation is.

I heard image processing researchers say that "he who masters segmentation and registration masters image processing", which might be a little bit of a hyperbole, but it gives the general idea.

Anyway, your technique is how I would have gone with it. Looking on researchgate, https://www.researchgate.net/post/How_can_one_determine_the_rotation_angle_between_two_images, lots of answers also go your way. The alternative would be using feature matching, but I'm not sure it would be faster than your solution.

Maybe you can have a look at OpenCV registration methods http://docs.opencv.org/trunk/db/d61/group__reg.html (the method in this link uses pixel matching and not feature matching, maybe it's faster)

Upvotes: 0

Related Questions