Search code examples
imagepython-imaging-libraryscikit-imageopencvndimagepython

How to down sample image array, without changing pixel values


I have image segmentation project, and ground truth labels given as images where pixel value stands for the label. I need to resize the images and labels, while keeping the labels in the same value set.

I tried many things, All change the value set.

Lets create dummy data

from skimage.transform import rescale, resize
from scipy import ndimage
from PIL import Image
import cv2

mask = np.zeros((30,20), dtype=np.uint16)
mask[22:26,12:30]=70
mask[25:27,14:17]=30
print('original label', mask.shape, np.unique(mask))
Outputs: original label shape: (30, 20) original label values: [ 0 30 70]

I need to resize label, so the result will have only 0, 30, 70 values.

What I tried
skimage_resized = resize(mask, (mask.shape[0]//2, mask.shape[1]//2), mode='constant')
print(skimage_resized.shape, np.unique(mask_resized))

skimage_rescale = rescale(mask, 1.0/2.0, mode='constant')
print(skimage_rescale.shape, np.unique(mask_resized))

ndimage_resized = ndimage.interpolation.zoom(mask, 0.5)
print(ndimage_resized.shape, np.unique(mask_resized))


cv2_resized = cv2.resize(mask, (mask.shape[0]//2, mask.shape[1]//2),
                        interpolation=cv2.INTER_NEAREST)
print(cv2_resized.shape, np.unique(mask_resized))

mask_pil = Image.fromarray(mask, mode=None)
pil_resized = mask_pil.thumbnail((mask.shape[0]//2, mask.shape[1]//2), Image.NEAREST)
print(skimage_resized.shape, np.unique(pil_resized))

Output:

(15, 10) [ 0  5  6 28 29 30 31 61 62 65 70 71 74 75 76]
(15, 10) [ 0  5  6 28 29 30 31 61 62 65 70 71 74 75 76]
(15, 10) [ 0  5  6 28 29 30 31 61 62 65 70 71 74 75 76]
(10, 15) [ 0  5  6 28 29 30 31 61 62 65 70 71 74 75 76]
(15, 10) [None]

Solution

  • Found a solution with openCV.

    import numpy as np
    import cv2
    resizeto = 2
    small_lable = cv2.resize(mask, (mask.shape[1]//resizeto, 
                             mask.shape[0]//resizeto),
                            interpolation=cv2.INTER_NEAREST)
    small_lable = (np.array(small_lable)).astype('uint8')
    print(small_lable.shape, np.unique(small_lable))
    plt.imshow(small_lable)
    

    output:

    (15, 10) [ 0 30 70]