In the previous blog, we discussed image translation. In this blog, we will discuss another type of transformation known as rotation. So, let’s get started. (Here, we will use a Left-hand coordinate system commonly used in image processing).
Suppose we have a point P(x,y) at an angle alpha and distance r from the origin as shown below. Now we rotate the point P about the origin by an angle theta in the clockwise direction. The rotated coordinates can be obtained as shown below.
So, we just need to create the transformation matrix (M) and then we can rotate any point as shown above. That’s the basic idea behind rotation. Now, let’s take the case with an adjustable center of rotation O(x0, y0).
Note: The above expression is for clockwise rotation. For anti-clockwise minor changes in the sign will occur. You can easily derive that.
Numpy
For the numpy implementation, you can refer to the previous blog. You just need to change the transformation matrix and rest everything is the same. Below is the code for this using numpy. For an explanation, you can refer to the previous blog.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import numpy as np import cv2 # Read an image img = cv2.imread('D:/downloads/opencv_logo.PNG') rows,cols,_ = img.shape # Create the transformation matrix angle = np.radians(90) x0, y0 = ((cols-1)/2.0,(rows-1)/2.0) M = np.array([[np.cos(angle), -np.sin(angle), x0*(1-np.cos(angle))+ y0*np.sin(angle)], [np.sin(angle), np.cos(angle), y0*(1-np.cos(angle))- x0*np.sin(angle)]]) # get the coordinates in the form of (0,0),(0,1)... # the shape is (2, rows*cols) orig_coord = np.indices((cols, rows)).reshape(2,-1) # stack the rows of 1 to form [x,y,1] orig_coord_f = np.vstack((orig_coord, np.ones(rows*cols))) transform_coord = np.dot(M, orig_coord_f) # Change into int type transform_coord = transform_coord.astype(np.int) # Keep only the coordinates that fall within the image boundary. indices = np.all((transform_coord[1]<rows, transform_coord[0]<cols, transform_coord[1]>=0, transform_coord[0]>=0), axis=0) # Create a zeros image and project the points img1 = np.zeros_like(img) img1[transform_coord[1][indices], transform_coord[0][indices]] = img[orig_coord[1][indices], orig_coord[0][indices]] # Display the image out = cv2.hconcat([img,img1]) cv2.imshow('a2',out) cv2.waitKey(0) |
Below is the output image for the 90-degree clockwise rotation. Here, the left image represents the original image while the right one is the rotated image.
While rotating an image, you may encounter an aliasing effect or holes in the output image as shown below for 45-degree rotation. This can be easily tackled using interpolation.
OpenCV
Now, let’s discuss how to rotate images using OpenCV-Python. In order to obtain the transformation matrix (M), OpenCV provide a function cv2.getRotationMatrix2D() which takes center, angle and scale as arguments and outputs the transformation matrix. The syntax of this function is given below.
1 2 3 4 5 |
transform_matrix = cv2.getRotationMatrix2D(center, angle, scale) #center: Center of the rotation in the source image. #angle: Rotation angle in degrees. Positive values mean counter-clockwise rotation (the coordinate origin is assumed to be the top-left corner). #scale: Isotropic scale factor. |
Once the transformation matrix (M) is calculated, pass it to the cv2.warpAffine() function that applies an affine transformation to an image. The syntax of this function is given below.
1 2 3 4 5 6 |
dst = cv.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]] ) # src: input image # M: Transformation matrix # dsize: size of the output image # flags: interpolation method to be used |
Below is an example where the image is rotated by 90 degrees counterclockwise with respect to the center without any scaling.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import numpy as np import cv2 # Read an image img = cv2.imread('D:/downloads/opencv_logo.PNG') rows,cols,_ = img.shape # Create the transformation matrix M = cv2.getRotationMatrix2D(((cols-1)/2.0,(rows-1)/2.0),90,1) # Pass it to warpAffine function dst = cv2.warpAffine(img,M,(cols,rows)) # Display the concatenated image out = cv2.hconcat([img, dst]) cv2.imshow('img',out) cv2.waitKey(0) |
Below is the output. Here, left image represents the original image while the right one is the rotated image.
Compare the outputs of both implementations. That’s all for image rotation. Hope you enjoy reading.
If you have any doubts/suggestions please feel free to ask and I will do my best to help or improve myself. Good-bye until next time.