Katerina T
Katerina T

Reputation: 15

Restore an image after rotation without black borders in python

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

Answers (1)

Rotem
Rotem

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()

ModifiedVersionRotation:
enter image description here

unrotated_img:
enter image description here

Original image:
enter image description here


The "restored" image looks blurred, because each warp (forward and backward) applies bi-linear interpolation that blurs the image a little.

Upvotes: 3

Related Questions