Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Numpy einsum() for rotation of meshgrid

I have a set of 3d coordinates that was generated using meshgrid(). I want to be able to rotate these about the 3 axes.

I tried unraveling the meshgrid and doing a rotation on each point but the meshgrid is large and I run out of memory.

This question addresses this in 2d with einsum(), but I can't figure out the string format when extending it to 3d.

I have read several other pages about einsum() and its format string but haven't been able to figure it out.

EDIT:

I call my meshgrid axes X, Y, and Z, each is of shape (213, 48, 37). Also, the actual memory error came when I tried to put the results back into a meshgrid.

When I attempted to 'unravel' it to do point by point rotation I used the following function:

def mg2coords(X, Y, Z):
    return np.vstack([X.ravel(), Y.ravel(), Z.ravel()]).T

I looped over the result with the following:

def rotz(angle, point):
    rad = np.radians(angle)
    sin = np.sin(rad)
    cos = np.cos(rad)
    rot = [[cos, -sin, 0],
           [sin,  cos, 0],
           [0, 0, 1]]

    return np.dot(rot, point)

After the rotation I will be using the points to interpolate onto.

like image 421
Chris Avatar asked Aug 04 '15 18:08

Chris


People also ask

What does NumPy einsum do?

einsum. Evaluates the Einstein summation convention on the operands. Using the Einstein summation convention, many common multi-dimensional, linear algebraic array operations can be represented in a simple fashion.

How do I rotate a matrix in NumPy?

NumPy: rot90() function The rot90() function is used to rotate an array by 90 degrees in the plane specified by axes. Rotation direction is from the first towards the second axis. Array of two or more dimensions. Number of times the array is rotated by 90 degrees.

How do I rotate an image in NumPy?

Rotate image with NumPy: np. The NumPy function that rotates ndarray is np. rot90() . Specify the original ndarray as the first argument and the number of times to rotate 90 degrees as the second argument.

Is NumPy einsum fast?

einsum is clearly faster. Actually, twice as fast as numpy's built-in functions and, well, 6 times faster than loops, in this case.


1 Answers

Working with your definitions:

In [840]: def mg2coords(X, Y, Z):
        return np.vstack([X.ravel(), Y.ravel(), Z.ravel()]).T

In [841]: def rotz(angle):
        rad = np.radians(angle)
        sin = np.sin(rad)
        cos = np.cos(rad)
        rot = [[cos, -sin, 0],
               [sin,  cos, 0],
               [0, 0, 1]]
        return np.array(rot)
        # just to the rotation matrix

define a sample grid:

In [842]: X,Y,Z=np.meshgrid([0,1,2],[0,1,2,3],[0,1,2],indexing='ij')    
In [843]: xyz=mg2coords(X,Y,Z)

rotate it row by row:

In [844]: xyz1=np.array([np.dot(rot,i) for i in xyz])

equivalent einsum row by row calculation:

In [845]: xyz2=np.einsum('ij,kj->ki',rot,xyz)

They match:

In [846]: np.allclose(xyz2,xyz1)
Out[846]: True

Alternatively I could collect the 3 arrays into one 4d array, and rotate that with einsum. Here np.array adds a dimension at the start. So the dot sum j dimension is 1st, and the 3d of the arrays follow:

In [871]: XYZ=np.array((X,Y,Z))
In [872]: XYZ2=np.einsum('ij,jabc->iabc',rot,XYZ)

In [873]: np.allclose(xyz2[:,0], XYZ2[0,...].ravel())
Out[873]: True

Similary for the 1 and 2.

Alternatively I could split XYZ2 into 3 component arrays:

In [882]: X2,Y2,Z2 = XYZ2
In [883]: np.allclose(X2,xyz2[:,0].reshape(X.shape))
Out[883]: True

Use ji instead of ij if you want to rotate in the other direction, i.e. use rot.T.

like image 91
hpaulj Avatar answered Oct 18 '22 17:10

hpaulj