David Dean
David Dean

Reputation: 1

Strange python np.resize effects

I got some weird effect when using np.resize. The picture should be a cat but after a small resize the picture is completely different. What is happening? Does this happen to tf.resize too? cat pic: https://www.pexels.com/photo/white-and-grey-kitten-on-brown-and-black-leopard-print-textile-45201/

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
# Read Images of shape 220,230
img = mpimg.imread('cat.jpeg')
img_re = np.resize(img,(224,224,3))
# Output Images
plt.imshow(img_re)

messed up cat

Upvotes: 0

Views: 391

Answers (1)

chrslg
chrslg

Reputation: 13336

numpy resize just resize the arrays. Numpy doesn't care about images or any other interpretation we might have of the array meaning.

Consider this example:

import numpy as np
A=np.array([[1,2,3], [4,5,6], [7,8,9], [10,11,12]])
#A=
#array([[ 1,  2,  3],
#       [ 4,  5,  6],
#       [ 7,  8,  9],
#       [10, 11, 12]])
np.resize(A, (2,6))
#Output
#array([[ 1,  2,  3,  4,  5,  6],
#       [ 7,  8,  9, 10, 11, 12]])

All it does, is rearranging the bunch of 12 values in A. In A, they are interpreted as 4 lines of 3 values. Resized array use the same values, but interpreted as 2 lines of 6 values

if you use np.resize with a new size that leads to have less value than in the original, then, they are truncated

np.resize(A, (3,3))
#array([[1, 2, 3],
#       [4, 5, 6],
#       [7, 8, 9]])

If the new size means more data, then they are repeated

np.resize(A, (3,5))
#array([[ 1,  2,  3,  4,  5],
#       [ 6,  7,  8,  9, 10],
#       [11, 12,  1,  2,  3]])

So, in your case, it is truncated. You had 220×230×3 numbers in your original array, you only have 224×224×3 in the resized ones. But more importantly, they are rearranged. The first line contains the 220 pixels from the first original line, then the 4 first pixels of the second. Then the new second line contains the 216 remaining pixels of the orignal second line, and then 8 pixels of the original 3rd. And so on.

Yet another example maybe using a pattern line/column for values in the original image

im=np.array([[11,12,13],[21,22,23],[31,32,33]])
#Array whose value follows a 2D logic. Think of it as an image.
#array([[11, 12, 13],
#       [21, 22, 23],
#       [31, 32, 33]])
np.resize(im, (2,4))
#array([[11, 12, 13, 21],
#       [22, 23, 31, 32]])

Not only value 33 was truncated from the result. But more importantly we lost the coherence of YX values.

Now, solution: well you need an image specific function to resize the image the way you want, not just some data management functions.

In pure numpy, you could

newImage=np.zeros((224,224,3))
newImage[:224,:220,:]=img[:224,:220,:]

(It drops the 6 last lines of img, and complete the 4 last columns with 0 — assuming that you meant 230 lines of 220 pixels for the original image. Not always clear when one drops the 3, whether shape are meant to be WxH image size, of (H, W, 3) numpy array shape. But you get the idea anyway).

Or, more realisticly, you use an image processing library to resize the image

import cv2
img_re = cv2.resize(img, (224,224))

(Note that here (224,224) are (W,H) dimensions, note (H,W) as in numpy shapes. Not that it matters when W=H, sure)

cv2 is probably overkill here. But it as the advantage to manipulate only ndarray, as you do.

A less overkill solution would be to use PIL

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import PIL
# Read Images of shape 220,230
img = PIL.Image.open('a1.jpg')
img_re = img.resize((224,224))
# Output Images
plt.imshow(img_re)

The difference is that here, img and img_re are no longer ndarray. Put if you need those arrays, you can easily

imgArr=np.array(img)
img_reArr=np.array(img_re)

Upvotes: 2

Related Questions