5

I want to resize images. My images contain specific values [0, 1, 2, 7, 9]. After resizing, new values are introduced like 5 and whatnot. I want to prevent that.

I'm currently using scikit image resize function. I've tried all interpolation flags but to no avail.

EDIT: a simple code to show the problem

import numpy as np
from skimage.transform import resize
vals = [0, 1, 4, 6]
N, M = 100, 100
image = np.random.choice(vals, N * M).reshape(N, M).astype('uint8')
resized_image = resize(image, (50, 50), preserve_range=True).astype('uint8')

print('vals before resizing ', np.unique(image))
print('vals after resizing ', np.unique(resized_image))
Muhammad Usman Bashir
  • 1,441
  • 2
  • 14
  • 43
Alex Deft
  • 2,531
  • 1
  • 19
  • 34

3 Answers3

3

Set anti_aliasing to False:

resized_image = resize(image, (50, 50), order=0, preserve_range=True, anti_aliasing=False).astype('uint8')

anti_aliasingbool, optional
Whether to apply a Gaussian filter to smooth the image prior to down-scaling. It is crucial to filter when down-sampling the image to avoid aliasing artifacts.

The aliasing filter applies Gaussian filter, that produces new values.


Result:

vals before resizing  [0 1 4 6]
vals after resizing  [0 1 4 6]
Rotem
  • 30,366
  • 4
  • 32
  • 65
2

If you want to avoid introducing new values, you need to avoid linear, bi-linear, quadratic and other "calculated" types of interpolation and use NEAREST_NEIGHBOUR interpolation. This is especially important with palette (i.e. indexed) images and classification images where each number represents a class, which could mean that interpolating between a class that represents, say, "forest" and an adjacent class that represents "highway" suddenly introduces some new value between the two that means you have constructed a beach in Arizona!

That means, use order=0 (corresponding to "nearest neighbour") rather than the default order=1 (corresponding to "bilinear") when resizing.

The various types of interpolation are expounded here.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • I've gone ahead and put order=0, still new values are introduced. – Alex Deft Jan 25 '20 at 09:33
  • Kindly show a **Minimum Complete Verifiable Example* of your code https://stackoverflow.com/help/minimal-reproducible-example and I'll take a look and see what I can see :-) – Mark Setchell Jan 25 '20 at 09:36
  • I've gone ahead and added a simple code showing the problem. Thanks. – Alex Deft Jan 25 '20 at 09:45
  • I am about to go offline, but have a read here about `astype()` https://scikit-image.org/docs/stable/user_guide/data_types.html and `preserve_range` later on same page. – Mark Setchell Jan 25 '20 at 09:51
1

You don't want anti-aliasing, but the resize function will apply it by default,(so the function will apply a Gaussian kernel on image to get rid off aliasing) so if you want to retain original pixels you must disable this flag by anti_aliasing=False

resized_image = resize(image, (50, 50), preserve_range=True, anti_aliasing=False,order=0).astype('uint8')

By this change the output will be:

vals before resizing  [0 1 4 6]
vals after resizing  [0 1 4 6]

By looking at the resize function documentation, we can see that Gaussian kernel will apply only when your resized image is smaller than original one.(which is your case)

anti_aliasingbool, optional

Whether to apply a Gaussian filter to smooth the image prior to down-scaling. It is crucial to filter when down-sampling the image to avoid aliasing artifacts.

Saeed Masoomi
  • 1,703
  • 1
  • 19
  • 33
  • "Gaussian kernel will apply only when your resized image is smaller than original one" that statement is incorrect. – Wodzu Nov 04 '22 at 10:30