How to resize TensorImage?

Hello,

I am currently working on the following notebook.

While creating a DataBlock, I wanted to add the resize the TensorImages (very last part of the notebook):

    db = DataBlock(blocks=(TransformBlock(type_tfms=partial(MSTensorImage.create, chnls_first=True),
                                          item_tfms=Resize(100)),
                           TransformBlock(type_tfms=[get_lbl_fn, partial(open_npy, cls=TensorMask)], 
                                          item_tfms=[Resize(100), AddMaskCodes(codes=['clear', 'water', 'shadow'])]),
                   ),
                   get_items=partial(get_files, extensions='.npy'),
                   splitter=RandomSplitter(valid_pct=0.1)
                   )

In the end I would expect my TensorImage objects to be resized to 100x100.
However, if I print out the summary db.summary(source=imgs_path), I see that the image size before and after the resize stays the same:

           (MSTensorImage of size 13x366x366, TensorMask of size 366x366)
    applying Resize -- {'size': (100, 100), 'method': 'crop', 'pad_mode': 'reflection', 'resamples': (2, 0), 'p': 1.0} gives
           (MSTensorImage of size 13x366x366, TensorMask of size 366x366)

Basically, 366x366 before and 366x366 after.

There I have two questions:

  1. Why doesn’t it resize?
  2. How to resize?

Thank you!

3 Likes

I’ve encountered the same issue, and it seems like the Resize function is not able to handle multi-spectral images (i.e. image with channel > 3).

My solution is to replace the Resize with a customized transform class like this (with reference to:
Tutorial - Custom transforms | fastai):

class TensorImageResizer(Transform):
    order=1
    "Resize image to `size` using `resample`"
    def __init__(self, size, resample=None):
        if not is_listy(size): size=(size,size)
        if resample is None: resample = 3 # = Image.BILINEAR
        self.size, self.resample = size, resample

    def resize(self, vol, size, resample):
      '''resample multi-channel numpy'''
      if not is_listy(size): size=(size,size)
      if len(vol.shape)==3 and len(size)==2:
        size = np.array([vol.shape[0],*size])
      zoom_ratio = tuple(size/np.array(vol.shape))
      vol_resize = scipy.ndimage.zoom(vol, zoom_ratio, order=resample)
      return torch.Tensor(vol_resize)

    def encodes(self, o:TensorImageMC): return self.resize(vol=o, size=self.size, resample=3) #self.resample)
    def encodes(self, o:TensorMaskMC):  return self.resize(vol=o, size=self.size, resample=0) # = Image.NEAREST

Then when create your DataBlock, you can swap in this function like this:

    db = DataBlock(blocks=(TransformBlock(type_tfms=partial(MSTensorImage.create, chnls_first=True),
                                          item_tfms=TensorImageResizer(100)),
                           TransformBlock(type_tfms=[get_lbl_fn, partial(open_npy, cls=TensorMask)], 
                                          item_tfms=[TensorImageResizer(100), AddMaskCodes(codes=['clear', 'water', 'shadow'])]),
                   ),
                   get_items=partial(get_files, extensions='.npy'),
                   splitter=RandomSplitter(valid_pct=0.1)
                   )
1 Like