Imagine I have these images :
I want the image from left to be rotated like the image of the middle, not the right one. How do I do this using Python and OpenCV. I looked at getRotationMatrix2D
and warpAffine
but the examples about it transform my image to the right one.
The imutils. rotate() function is used to rotate an image by an angle in Python.
This is by far the best solution i have found for rotating images while avoiding cropping the image.
Rotate an image without cropping in OpenCV in C++
import cv2
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
You can add checks to avoid some calculations when the angles are 90*n, but this function will work for any angle as is.
If you only care about 90 degree rotations numpy instead. It's much easier and works on opencv input:
import numpy as np
rotated_image = np.rot90(im)
As I don't know your code I still would guess that using the imutils.rotate_bound
function will solve the problem. E.g.: rotate = imutils.rotate_bound(image, angle)
This is the easiest way to rotate image frames by using cv2.rotate(frame,rotateCode = 1) and rescale or resizing by using cv2.CAP_PROP_FRAME_WIDTH and cv2.CAP_PROP_FRAME_HEIGHT of the frame.
import numpy as np
import cv2
cam = cv2.VideoCapture(2)
while(True):
# Capture frame-by-frame
cam.set(cv2.CAP_PROP_FRAME_WIDTH, 640) # You can change frame width by chaning number.
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) # You can change frame height by chaning number.
ret, frame = cam.read()
new_frame=cv2.rotate(frame,rotateCode = 1)
# Display the resulting frame
cv2.imshow('frame',new_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cam.release()
cv2.destroyAllWindows()
Hopefully, it with help you.
While this question was asked for CV2, you can do this with python's native image library.
rotate_degrees = -90
img = Image.open(input_file_path)
img2 = img.rotate(rotate_degrees, expand=True)
img2.save(output_file_path)
If you leave out expand=True
in the rotate command you will get a result that looks like OP's right hand photo.
Here is an alternative from ndimage.rotate
from SciPy
Related documentation
from scipy.ndimage import rotate as rotate_image
#rotation angle in degree
rotated_img1 = rotate_image(img,90)
rotated_img2 = rotate_image(img,-110)
rotated_img3 = rotate_image(img,-45)
# angles extending beyond 360 are calculated appropriately:
rotated_img4 = rotate_image(img,390)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With