Center cropping without resizing

I am trying out the Kaggle Histopathological Cancer Detection competition.
The competition’s page states that only the 32*32 pixels in the center are relevant, so I’m trying to crop the images. However, when I use tfms=tfms_from_model(arch, 32) in ImageClassifierData.from_csv() I get resized images, rather than cropped, which I guess in most cases would be the right approach. Is there any built in method for cropping without resizing?

Thanks!

You can write your own image transformations.

e.g. transforms_top_down_crop = transforms_top_down + [CenterCrop(32)] should transform the images like normal top down images but should also crop them in the center to a size of 32x32, exactly what we want.

But somehow I get an error when trying this. Now I tried to set the crop_type argument in tfms_from_model to CropType.CENTER and the size to 32 but I’m not sure that it does what I want. I’m afraid that it resizes the images first to 32x32 and then crops the center to 32x32, so doing nothing.

Maybe someone can help us there :smiley:

1 Like

Now I tried to set the crop_type argument in tfms_from_model to CropType.CENTER and the size to 32 but I’m not sure that it does what I want.

This doesn’t work, since the transformer first scales to the given size, and only then crops. I now managed to get this working, by using tfms = tfms_from_model(arch, sz=32, scale=Scale(96)) which uses the default CropType.CENTER after it scales the image to 96*96 (the original size, equivalent to no scaling). Maybe there’s a cleaner way to do this, but it works :slight_smile:

And this will apply the scaling first and then crop it back down to the 32x32? and are you sure that the default is CropType.CENTER and not CropType.RANDOM ?

And this will apply the scaling first and then crop it back down to the 32x32? and are you sure that the default is CropType.CENTER and not CropType.RANDOM ?

No. I was wrong. Use CropType.CENTER .

1 Like

This seems to work, thanks!
But… is there a better way to crop? I don’t fully understand all the options… are we actually “scaling”?

Regards
Bliss

It doesn’t feel like a natural way to crop, but it works. We’re not actually scaling, since we change the scale from 96 to 96. But we are centre-cropping, rather then resizing the images to 32, which happens when we use tfms=tfms_from_model(arch, 32).

I think in general tfms_from_model is not built for pre-processing, as we are using it. Meaning, the images should be cropped prior to loading them to the model. But I’m not sure if that is indeed the author’s intent.

This is how i use center crop in this competition, i do not know is it the right way or just a hack.
I use the functions __crop_default(), crop_image_points() from transform.py and defined my own function _crop() with predefined crop seize that i wanted.

    def _crop(x, size=68, row_pct:uniform=0.5, col_pct:uniform=0.5):
        f_crop = _crop_image_points if isinstance(x, ImagePoints) else _crop_default
        return f_crop(x, size, row_pct, col_pct)

cntr_crop = TfmPixel(_crop)
tfms = get_transforms(flip_vert=True, max_rotate=180, max_lighting=0.2, max_zoom=1.05, p_lighting=0.5, p_affine=0.5, max_warp=0, xtra_tfms = [cntr_crop()])

Do you specify a certain size in your .transform() function?

You can also create your own ImageList class which crops images soon after it reads them. One advantage with this approach is that it will apply cropping on test images too.
Here is a sample implementation:

ORIGINAL_SIZE = 96
CROP_SIZE = 64

def readCroppedImage(path, augmentations = True):
    bgr_img = cv2.imread(str(path))
    rgb_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2RGB)
    start_crop = (ORIGINAL_SIZE - CROP_SIZE) // 2
    end_crop = start_crop + CROP_SIZE
    rgb_img = rgb_img[start_crop:end_crop, start_crop:end_crop] / 255
    return rgb_img

class CroppedImageList(ImageList):
    def open(self, fn:PathOrStr)->Image:
        img = readCroppedImage(fn)
        return vision.Image(px=pil2tensor(img, np.float32))

And then use this when you are creating your ImageList object.
x = CroppedImageList.from_csv(....)

1 Like