Validate each pixel value when resizing an image with Pillow with nearest neighbor

Overview

When using the Pillow module to resize an image with a neighbor neighbor I tried to verify from which pixel the value is obtained (neighborhood).

With each algorithm (nearest neighbor, bilinear, bicubic) What the image will look like (whether it will be smooth, etc.) I often see articles that mention about I didn't have much information about what the value of each pixel would be, so I wrote it.

About Nearest neighbor (Nearest neighbor)

The algorithm itself is simple. The links below will be helpful. I will omit the details here, but In short, it is an algorithm that brings the pixel value of the nearest location as it is. https://algorithm.joho.info/image-processing/nearest-neighbor-linear-interpolation/

Try to verify

Creating an image sample

I made an image sample for verification

import numpy as np
from PIL import Image
import  matplotlib.pyplot as plt

A = np.eye(10, dtype=int)
B = np.arange(10, dtype=int) * 20
C = Image.fromarray(B * A)

plt.figure()
plt.imshow(C)
print(np.array(C))

Figure_1.png

The stored values are as follows

[[  0   0   0   0   0   0   0   0   0   0]
 [  0  20   0   0   0   0   0   0   0   0]
 [  0   0  40   0   0   0   0   0   0   0]
 [  0   0   0  60   0   0   0   0   0   0]
 [  0   0   0   0  80   0   0   0   0   0]
 [  0   0   0   0   0 100   0   0   0   0]
 [  0   0   0   0   0   0 120   0   0   0]
 [  0   0   0   0   0   0   0 140   0   0]
 [  0   0   0   0   0   0   0   0 160   0]
 [  0   0   0   0   0   0   0   0   0 180]]

It feels like the diagonal elements have a non-zero value.

Resize image sample 10 × 10 ⇒ 5 × 5

Let's resize this image with Pillow's resize (nearest neighbor) First, compress the 10x10 original image to 5x5


C_nn5 = C.resize([5, 5], resample=Image.NEAREST)
plt.figure()
plt.imshow(C_nn5)
print(np.array(C_nn5))

Figure_2.png

[[ 20   0   0   0   0]
 [  0  60   0   0   0]
 [  0   0 100   0   0]
 [  0   0   0 140   0]
 [  0   0   0   0 180]]

Here, as you can see by looking at the value, The nearest neighbor is the pixel's "backward" value (20). For example, the [0, 0] pixels after resizing are Contains the value of [1, 1] pixels of the original image. Also, the [1, 1] pixels after resizing are Contains the [3, 3] pixel value (60) of the original image.

However, it doesn't match the formula I referred to ...? According to the formula, it should be "front" of the pixel

I'(0, 0) = I([0/0.5], [0/0.5]) = I(0, 0) = 0
I'(1, 1) = I([1/0.5], [1/0.5]) = I(2, 2) = 40

So For example, the [0, 0] pixels after resizing are The value (0) of [0, 0] pixels of the original image should be stored

There was an article that solved it for some reason https://qiita.com/yoya/items/3b4a8080516259ece684 (Rather, did it make sense to write this article ...) I see, the pixel start has been changed to 0.5 ...

Then

I'(0, 0) = I([0.5/0.5], [0.5/0.5]) = I(1, 1) = 20
I'(1, 1) = I([1.5/0.5], [1.5/0.5]) = I(3, 3) = 60

And the value matched properly.

Resize image sample 10 × 10 ⇒ 3 × 3

Next, compress the original image of 10x10 to 3x3. Figure_3.png

[[ 20   0   0]
 [  0 100   0]
 [  0   0 160]]
I'(0, 0) = I([0.5/0.3], [0.5/0.3]) = I(2, 2) = 20
I'(1, 1) = I([1.5/0.3], [1.5/0.3]) = I(5, 5) = 100
I'(2, 2) = I([2.5/0.3], [2.5/0.3]) = I(8, 8) = 160

Yes, the value was correct without any problem.

Summary

For nearest neighbor and resize You can calculate the nearest pixel from the formula, Note that the original image starts at "0.5"

Recommended Posts

Validate each pixel value when resizing an image with Pillow with nearest neighbor
Create an image composition app with Flask + Pillow
Image processing with PIL (Pillow)