How to rotate 90 and 270 degrees of 5D tensor

According to https://github.com/pytorch/pytorch/pull/7873, the flip function have been merged in pytorch. I am using version 0.41 and it works for 5D tensor. My 5D tensor is BxCxDxHxW. For flipping, I just use

images=images.flip(4) # flip along 4th dim
images=image.flip(3) # flip along 3rd dim

However, the above functions are equivalent to the vertical and horizontal axis. How could I rotate the tensor 90 degrees or 270 degrees along 3rd or 4th dim?

Thanks!

I guess you could achieve it with transpose:

x = torch.zeros(1, 1, 1, 4, 4)
x[:, :, :, 3] = 1.
x90 = x.transpose(3, 4)

Would that work for you?

4 Likes

Great, it works. How about rotation 270 degree?

This should work for 270 degrees. Sorry for missing it in the first reply:

x270 = x.transpose(3, 4).flip(4)
2 Likes

@ptrblck I am currently using torch 0.4 and tried to run your snippet. I get an attribute error saying ‘Tensor’ object has no attribute ‘flip’.

Upgrade it to 0.4.10…

1 Like

@ptrblck For a 4D tensor, how to rotate 90, 180 and 270 degrees? Thanks in advance.

Is these right?
x90=x.transpose(2,3)
x180=x.flip(3)
x270=x.transpose(2,3).flip(2)

There are some minor issue. I think this would work for you :wink:


x = torch.zeros(1, 1, 4, 4)
x[:, :, 3] = 1.

x90 = x.transpose(2, 3)
x180 = x.flip(2)
x270 = x.transpose(2, 3).flip(3)

print(x)
print(x90)
print(x180)
print(x270)
2 Likes

That works for me, thank you.

Hi, @ptrblck do you know to rotate any degrees, such as 36 and 72?

I’m not sure, but I think transforms.LinearTransformation would be a good approach. You would need to create the transformation matrix offline and apply it on the tensor. I’m currently not on my computer, otherwise I would create a small example. Let me know if that’s desirable and I could write it a bit later.

Sure, could you mind providing the example? Thank you in advance.

Sorry for the late answer. Apparently I was mistaken and LinearTransformation will probably not work in this case.

If you are dealing with image data, the easiest approach would be to use transforms.functional.rotate.

However, this won’t work on arbitrary tensors.
Therefore, I’ve created a small (quick and dirty) example using a rotation matrix to rotate your tensor.
The first part uses nested for loops to perform the rotation and will most likely be slow. It’s just for the sake of debugging and I think the code is a bit easier to understand.
In the second part I’ve basically used the first code and used some matmuls to speed it up.
Note that I haven’t tested all edge cases, so please ping me, if you encounter any issues.

# Create dummy image
im = torch.zeros(1, 1, 10, 10)
im[:, :, :, 2] = 1.

# Set angle
angle = torch.tensor([72 * np.pi / 180.])

# Calculate rotation for each target pixel
x_mid = (im.size(2) + 1) / 2.
y_mid = (im.size(3) + 1) / 2.
im_rot = torch.zeros_like(im)
for r in range(im.size(2)):
    for c in range(im.size(3)):
        x = (r - x_mid) * torch.cos(angle) + (c - y_mid) * torch.sin(angle)
        y = -1.0 * (r - x_mid) * torch.sin(angle) + (c - y_mid) * torch.cos(angle)
        x = torch.round(x) + x_mid
        y = torch.round(y) + y_mid
        
        if (x >= 0 and y>=0 and x<im.size(2) and y<im.size(3)):
            im_rot[:, :, r, c] = im[:, :, x.long(), y.long()]


# Calculate rotation with inverse rotation matrix
rot_matrix = torch.tensor([[torch.cos(angle), torch.sin(angle)],
                            [-1.0*torch.sin(angle), torch.cos(angle)]])

# Use meshgrid for pixel coords
xv, yv = torch.meshgrid(torch.arange(im.size(2)), torch.arange(im.size(3)))
xv = xv.contiguous()
yv = yv.contiguous()
src_ind = torch.cat((
    (xv.float() - x_mid).view(-1, 1),
    (yv.float() - y_mid).view(-1, 1)),
    dim=1
)
    
# Calculate indices using rotation matrix
src_ind = torch.matmul(src_ind, rot_matrix.t())
src_ind = torch.round(src_ind)

src_ind += torch.tensor([[x_mid, y_mid]])

# Set out of bounds indices to limits
src_ind[src_ind < 0] = 0.
src_ind[:, 0][src_ind[:, 0] >= im.size(2)] = float(im.size(2)) - 1
src_ind[:, 1][src_ind[:, 1] >= im.size(3)] = float(im.size(3)) - 1
 
im_rot2 = torch.zeros_like(im)
src_ind = src_ind.long()
im_rot2[:, :, xv.view(-1), yv.view(-1)] = im[:, :, src_ind[:, 0], src_ind[:, 1]]
im_rot2 = im_rot2.view(1, 1, 10, 10)
print(im_rot)
print(im_rot2)
1 Like

I was wondering if rotation can be achieved using tensor.permute()

Thinking in dimensions permute performs a rotation. For example if we go from a matrix [channels,H,W] 1x5x10 to a matrix 5x10x1 we are doing nothing but a rotation.

I was wondering if permute also rearrange tensors (makes no sense to me, cos then it would be replacing .view())

I think this may be correct.

import torch
import numpy as np
x= torch.tensor(np.arange(8)).view(2,2,2)
x90 = x.transpose(0, 1).flip(0)
x180 = x.flip(0).flip(1)
x270 = x.transpose(0, 1).flip(1)

I have tried.

3 Likes

@ptrblck sorry for late reply.
And I got the following error,

xv, yv = torch.meshgrid(torch.arange(im.size(2)), torch.arange(im.size(3)))
TypeError: meshgrid() takes 1 positional argument but 2 were given

And I find the answer,

xv, yv = torch.meshgrid(torch.arange(im.size(2)), torch.arange(im.size(3)))

should be,

xv, yv = torch.meshgrid([torch.arange(im.size(2)), torch.arange(im.size(3))])

Sorry for the confusion.
I’ve used the 1.0 preview and didn’t realize the arguments of torch.meshgrid were changed.
Glad you figured it out!

I think amazing_coder’s code is right.

x[…, 3] = torch.tensor([1,2,3,4])

In this case, think about your code.
x90 = x.transpose(2, 3)

than x90 is
tensor([[[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[1., 2., 3., 4.]]]])

It’s not right way about rotate 90 degree. This should have a flip.

Another upvote for @amazing_coder’s code.
@ptrblck’s code looks like working but it actually flips along another axis. Suppose you have a cat image, and you apply a horizontal flip and call it a 180 degree rotation, that’s not accurate, right? The same happens with tensor.transpose. That’s why you need another flip to correct the orientation (e.g., a vertical flip for the cat case).

Here, just to generalize the solution.

# x is a tensor, and d1, d2 are the dimensions of your interest, then
x90 = x.transpose(d1, d2).flip(d1)
x180 = x.flip(d1).flip(d2)
x270 = x.transpose(d1, d2).flip(d2)

Note that d1,d2 are 0-indexed.

4 Likes

Hi,

How I can upgrade pytorch. I work cpu-based and the version of my pytorch is 0.4.0.
I tried this command:
conda install pytorch-cpu torchvision-cpu -c pytorch
and now flip is known but the version is not upgraded. But I do not know exactly what I did :smile:

Thanks