The Dude
The Dude

Reputation: 4005

Rotation of a 2D array over an angle using rotation matrix

What I want to do is to rotate a 2D numpy array over a given angle. The approach I'm taking is using a rotation matrix. The rotation matrix I defined as:

angle = 65.
theta = (angle/180.) * numpy.pi

rotMatrix = numpy.array([[numpy.cos(theta), -numpy.sin(theta)], 
                         [numpy.sin(theta),  numpy.cos(theta)]])

The matrix I want to rotate is shaped (1002,1004). However, just for testing purposes I created a 2D array with shape (7,6)

c = numpy.array([[0,0,6,0,6,0], [0,0,0,8,7,0], [0,0,0,0,5,0], [0,0,0,3,4,0], [0,0,2,0,1,0], [0,8,0,0,9,0], [0,0,0,0,15,0]])

Now, when I apply the rotation matrix on my 2D array I get the following error:

c = numpy.dot(rotMatrix, c)
print c

c = numpy.dot(rotMatrix, c)
ValueError: matrices are not aligned
Exception in thread Thread-1 (most likely raised during interpreter shutdown):

What am I doing wrong?

Upvotes: 2

Views: 59738

Answers (5)

hawkjo
hawkjo

Reputation: 420

You seem to be looking for scipy.ndimage.rotate, or similar. If you specifically want 90, 180, or 270 degree rotations, which do not require interpolation, then numpy.rot90 is better.

Upvotes: 8

laurenz
laurenz

Reputation: 306

I guess there is a misunderstanding. You cannot rotate an image by multiplying it with the rotation matrix. What you actually need to do is to multiply a matrix containing the image coordinates (of shape 2 x (n*m) for an image of shape n x m ) with the rotation matrix. This might look like this in numpy:

import numpy as np

image = np.arange(10000).reshape((100, 100))

theta = np.radians(180)  # rotate 180 degrees
rot_matrix = np.array([[np.cos(theta), -np.sin(theta)],
                       [np.sin(theta), np.cos(theta)]])

# some steps to create coordinate matrix
x_len, y_len = image.shape
x_range = np.arange(x_len)
y_range = np.arange(y_len)
x_coords, y_coords = np.meshgrid(x_range, y_range)

coordinates = np.vstack([x_coords.flatten(), y_coords.flatten()])
# example for coordniates for image with shape n x n like:
# x: x0, x1, x2,  ... xn-2, xn-1, xn
# y: y0, y1, y2,  ... yn-2, yn-1, yn

# here we apply matrix multiplication
rotated_coordinates = rot_matrix @ coordinates
rotated_coordinates = rotated_coordinates.astype(int)

rotated_image = np.zeros(image.shape)
# This might generate missing values that need to be interpolated! Will be skipped here
rotated_image[rotated_coordinates[0], rotated_coordinates[1]] = image.flatten()

Upvotes: 1

Shiv Krishna Jaiswal
Shiv Krishna Jaiswal

Reputation: 376

You can not rotate any ndim vector using 2D matrix.

I did not find an in built function in numpy. I was hoping that this is a very common functionality and should be there. Let me know if you find it.

Mean while I have create function of my own.

def rotate(vector, theta, rotation_around=None) -> np.ndarray:
    """
    reference: https://en.wikipedia.org/wiki/Rotation_matrix#In_two_dimensions
    :param vector: list of length 2 OR
                   list of list where inner list has size 2 OR
                   1D numpy array of length 2 OR
                   2D numpy array of size (number of points, 2)
    :param theta: rotation angle in degree (+ve value of anti-clockwise rotation)
    :param rotation_around: "vector" will be rotated around this point, 
                    otherwise [0, 0] will be considered as rotation axis
    :return: rotated "vector" about "theta" degree around rotation
             axis "rotation_around" numpy array
    """
    vector = np.array(vector)

    if vector.ndim == 1:
        vector = vector[np.newaxis, :]

    if rotation_around is not None:
        vector = vector - rotation_around

    vector = vector.T

    theta = np.radians(theta)

    rotation_matrix = np.array([
        [np.cos(theta), -np.sin(theta)],
        [np.sin(theta), np.cos(theta)]
    ])

    output: np.ndarray = (rotation_matrix @ vector).T

    if rotation_around is not None:
        output = output + rotation_around

    return output.squeeze()


if __name__ == '__main__':
    angle = 30
    print(rotate([1, 0], 30))  # passing one point
    print(rotate([[1, 0], [0, 1]], 30))  # passing multiple points


Upvotes: 0

veda905
veda905

Reputation: 772

You may want to look at skimage.transform. This module has several useful functions including rotation. No sense in rewriting something that is already done.

Upvotes: 2

mathematician1975
mathematician1975

Reputation: 21351

Matrix dimensions will need to be compatible in order to obtain a matrix product. You are trying to multiply a 7x6 matrix with a 2x2 matrix. This is not mathematically coherent. It only really makes sense to apply a 2D rotation to a 2D vector to obtain the transformed coordinates.

The result of a matrix product is defined only when the left hand matrix has column count equal to right hand matrix row count.

Upvotes: 7

Related Questions