1

I have an image of size 72x96. Windows says its size is 72x96. PIL Image also says it is 72x96:

from PIL import Image, ImageOps

with Image.open(<path>) as img:
    print(img.size) # (72, 96)
    print(ImageOps.exif_transpose(img).size) # (72, 96)

But when I read the image with cv2.imread or skimage.io.imread it says, that the shape of the image is (96, 72, 3):

from skimage.io import imread
im0 = imread(<path>)
print(im0.shape) # (96, 72, 3)

What is wrong here? Even if I do something like that:

import matplotlib.pyplot as plt
plt.imshow(im0)

It shows the image with the correct size, but the written size looks to be transposed.

Kim Zoze
  • 33
  • 1
  • 6
  • You probably have a palette image. Have a read here... https://stackoverflow.com/a/52307690/2836621 – Mark Setchell Mar 31 '21 at 12:58
  • Thank you, but actually it's an `RGB` – Kim Zoze Mar 31 '21 at 13:32
  • Try `print(img)` – Mark Setchell Mar 31 '21 at 14:02
  • Can you check if your image's Exif flags are set? And if so, is the "Orientation" flag set to 6 (=90°)? If so, your OpenCV will apply all these Exif flags to the read image. Maybe use `IMREAD_IGNORE_ORIENTATION` or `IMREAD_UNCHANGED `? Or maybe go back and unset Exif flags on the image? `from PIL import Image, ExifTags for k, v in im.getexif().items(): if k in ExifTags.TAGS: print(f"{ExifTags.TAGS[k]}:{v}")` – RahulDamineni Apr 10 '23 at 19:05

1 Answers1

4

This is expected behavior.

PIL returns the size of an image as (width, height) (PIL documentation), whereas numpy returns the shape of an array as the lengths of the first and then second dimension (in the case of a 2d array), so (height, width) (Numpy documentation).

desertnaut
  • 57,590
  • 26
  • 140
  • 166
Ewran
  • 328
  • 4
  • 15
  • Does it mean that that the shape of `np.zeros((72, 96, 3))` should be `(96, 72, 3)`? Because it's not – Kim Zoze Mar 31 '21 at 12:48
  • No, as I said in my answer, the shape of the array in your comment is (72, 96, 3), as it corresponds to the lengths of the first, then second, then third dimension of the array. – Ewran Mar 31 '21 at 13:04
  • Okay, than. My question is why the shape of the image is not `(72, 96, 3)`. `cv2` and `skimage` should show shape this way: `(width, height, channels)` – Kim Zoze Mar 31 '21 at 13:15
  • It is a question of convention: the array defined by your image (obtained with imread) is a numpy.ndarray, whose shape is (by definition), returned as (height, width, channels). The same image, as a PIL.Image object, has a size (not a shape), returned as (width, height). The image is the same, only the way of presenting its shape (or size) changes. – Ewran Mar 31 '21 at 13:27
  • I know, that `PIL.Image` does not return a shape. The question is why `PIL.Image.size` returns (**72**, **96**) and `skimage.io.imread.shape` returns (**96**, **72**, 3). The **width** and the **height** are mixed up. Why? – Kim Zoze Mar 31 '21 at 13:31
  • 1
    The answer, as stated above, is a convention. The shape method of numpy.ndarray objects has to be defined for n-dimensional arrays (hence the name), so the shape is returned as the length of each dimension of the array, starting form 0. PIL, on the other hand, is focused on images, and then returns, by convention, the size of images as (width, height). You just have to keep that in mind when extracting the shape / size of images, and assign the width and height carefully based on which objects you use (np.ndarray or PIL.Image). – Ewran Mar 31 '21 at 13:36