Pytorch resize 3d numpy array

Dear all,
I have 3d image and I would like to write a dataloader with a rescale trasformation .

What is the best way to do the rescaling? I have [240,240,180] I would like to trasform [128,128,128].
Any suggestion on function for dataloader.
Thanks so much

class Resize(object):
   
    def __init__(self, output_size):
        assert isinstance(output_size, (int, tuple))
        self.output_size = output_size

    def __call__(self, sample):
        image, label = sample["data"], sample["label"]

        h, w = image.shape[:2]
        if isinstance(self.output_size, int):
            if h > w:
                new_h, new_w = self.output_size * h / w, self.output_size
            else:
                new_h, new_w = self.output_size, self.output_size * w / h
        else:
            new_h, new_w = self.output_size

        new_h, new_w = int(new_h), int(new_w)

        # img = transform.resize(image, (new_h, new_w))
        img = scipy.ndimage.zoom(image, 0.5)
        return {"data": img, "label": label}

If you want to use a bilinear or nearest neighbor interpolation, you could use `grid_sample](https://pytorch.org/docs/stable/nn.functional.html?highlight=grid_sample#torch.nn.functional.grid_sample).

Thanks so much… I have a 3d data and I create a tensor like this:
torch.Size([1, 240, 240, 240])

When I try to use grid sample I have this error. Seem I can’t use for only 3D data it is correct?

flow = torch.Tensor([1,128,128,128])
torch.nn.functional.grid_sample(data['data'],flow, mode='bilinear', padding_mode='zeros', align_corners=None)
untimeError: grid_sampler(): expected 4D or 5D input and grid with same number of dimensions, but got input with sizes [1, 240, 240, 240] and grid with sizes [4]

You can use it for 4-D and 5-D data (your case, if you unsqueeze a fake channel dimension).
However, the grid shape should be [N, H_out, W_out, 2], while you are passing 4 values.

Here is a small example of the usage:

N, C, H, W = 1, 24, 24, 24
x = torch.arange(N*C*H*W).view(N, 1, C, H, W).float()

d = torch.linspace(-1, 1, 12)
meshx, meshy, meshz = torch.meshgrid((d, d, d))
grid = torch.stack((meshx, meshy, meshz), 3)
grid = grid.unsqueeze(0) # add batch dim

out = F.grid_sample(x, grid, align_corners=True)

You might want to check, if the order of the meshes is correct for your use case.

1 Like

hi ,I have a 4d data and like this: torch.Size([100, 1, 2, 2]),I want to know how resize it become ([100, 1, 32, 32])?

You cannot resize a tensor with 400 elements to 102400 elements.
Depending on your use case, you could repeat the values in the last two dimensions:

x = torch.randn(100, 1, 2, 2)
y = x.repeat(1, 1, 16, 16)

Nice example! But I think the dimensions D, H, W corresponds to the directions z, y, x, respectively. If this is true, then meshx, meshy, meshz = torch.meshgrid((d, d, d)) should be replaced with meshz, meshy, meshx = torch.meshgrid((d, d, d)). I’m not sure if there is another use case though.

From gridsample documentation:

grid[n, d, h, w] specifies the x, y, z pixel locations for interpolating output[n, :, d, h, w]

So indeed meshx should be put first when stacked. But since meshx changes in the dimension W, it should be the last of torch.meshgrid outputs.

Here is an example motived by yours. The element values indicate their coordinates, e.g. 291 is at (d,h,w) = (2,9,1).

N, C, D, H, W = 1, 1, 3, 10, 10
x = torch.arange(N*C*D*H*W).view(N, C, D, H, W).float()

d = torch.linspace(-1, 1, 2)
h = torch.linspace(-1, 1, 3)
w = torch.linspace(-1, 1, 4)
meshz, meshy, meshx = torch.meshgrid((d, h, w))
grid = torch.stack((meshx, meshy, meshz), 3)
grid = grid.unsqueeze(0) # add batch dim

out = F.grid_sample(x, grid, align_corners=True)
print(x, grid, out)
1 Like