Reputation: 15
I've used the following code in order to rotate an image (initial image) and make some processing:
def rotate_image(mat, angle):
"""
Rotates an image (angle in degrees) and expands image to avoid cropping
"""
height, width = mat.shape[:2] # image shape has 3 dimensions
image_center = (width/2, height/2) # getRotationMatrix2D needs coordinates in reverse order (width, height) compared to shape
rotation_mat = cv2.getRotationMatrix2D(image_center, angle, 1.)
# rotation calculates the cos and sin, taking absolutes of those.
abs_cos = abs(rotation_mat[0,0])
abs_sin = abs(rotation_mat[0,1])
# find the new width and height bounds
bound_w = int(height * abs_sin + width * abs_cos)
bound_h = int(height * abs_cos + width * abs_sin)
# subtract old image center (bringing image back to origo) and adding the new image center coordinates
rotation_mat[0, 2] += bound_w/2 - image_center[0]
rotation_mat[1, 2] += bound_h/2 - image_center[1]
# rotate image with the new bounds and translated rotation matrix
rotated_mat = cv2.warpAffine(mat, rotation_mat, (bound_w, bound_h))
return rotated_mat
ModifiedVersionRotation = rotate_image(img, 35)
cv2.imwrite("lenarot.jpg", ModifiedVersionRotation)
The function adds black borders to the image so it wont be cropped at the rotation rotated image which is what I actually need. But, how can I rotate back the image and remove the black borders?
Upvotes: 1
Views: 780
Reputation: 32094
For rotating back, we may compute the inverse transformation, and apply it to the rotated image:
Example:
inv_rotation_mat = cv2.invertAffineTransform(rotation_mat) # Get inverse transformation matrix
unrotated_mat = cv2.warpAffine(rotated_mat, inv_rotation_mat, (mat.shape[1], mat.shape[0])) # Apply warp (and set the destination size to original size of mat).
Complete code sample:
import cv2
img = cv2.imread('lena.jpg')
def rotate_image(mat, angle):
"""
Rotates an image (angle in degrees) and expands image to avoid cropping
"""
height, width = mat.shape[:2] # image shape has 3 dimensions
image_center = (width/2, height/2) # getRotationMatrix2D needs coordinates in reverse order (width, height) compared to shape
rotation_mat = cv2.getRotationMatrix2D(image_center, angle, 1.)
# rotation calculates the cos and sin, taking absolutes of those.
abs_cos = abs(rotation_mat[0,0])
abs_sin = abs(rotation_mat[0,1])
# find the new width and height bounds
bound_w = int(height * abs_sin + width * abs_cos)
bound_h = int(height * abs_cos + width * abs_sin)
# subtract old image center (bringing image back to origo) and adding the new image center coordinates
rotation_mat[0, 2] += bound_w/2 - image_center[0]
rotation_mat[1, 2] += bound_h/2 - image_center[1]
# rotate image with the new bounds and translated rotation matrix
rotated_mat = cv2.warpAffine(mat, rotation_mat, (bound_w, bound_h))
return (rotated_mat, rotation_mat) # Also return rotation_mat
ModifiedVersionRotation, T = rotate_image(img, 35)
iT = cv2.invertAffineTransform(T)
unrotated_img = cv2.warpAffine(ModifiedVersionRotation, iT, (img.shape[1], img.shape[0]))
#cv2.imwrite("lenarot.jpg", ModifiedVersionRotation)
#cv2.imwrite("lenarotback.jpg", unrotated_img)
cv2.imwrite("lenarot.png", ModifiedVersionRotation)
cv2.imwrite("lenarotback.png", unrotated_img)
# Show images for testing
cv2.imshow('ModifiedVersionRotation', ModifiedVersionRotation)
cv2.imshow('img', img)
cv2.imshow('unrotated_img', unrotated_img)
cv2.waitKey()
cv2.destroyAllWindows()
The "restored" image looks blurred, because each warp (forward and backward) applies bi-linear interpolation that blurs the image a little.
Upvotes: 3