5

I am using and familiar with cv2, today I was giving a try with skimage.

I was trying to read an image using skimage and cv2. It seems that they both read the image perfectly. But when I plot histograms of the image but read through different libraries (skimage and cv2), the histogram shows a significant difference.

Would anyone help me by explaining the difference between the histograms?

My code:

import cv2
import skimage.io as sk
import numpy as np
import matplotlib.pyplot as plt

path = '../../img/lenna.png'

img1 = sk.imread(path, True)
img2 = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
print(img1.shape)
print(img2.shape)

plt.subplot(2, 2, 1)
plt.imshow(img1, cmap='gray')
plt.title('skimage read')
plt.xticks([])
plt.yticks([])

plt.subplot(2, 2, 2)
plt.imshow(img2, cmap='gray')
plt.title('cv2 read')
plt.xticks([])
plt.yticks([])

plt.subplot(2, 2, 3)
h = np.histogram(img1, 100)
plt.plot(h[0])
plt.title('skimage read histogram')

plt.subplot(2, 2, 4)
h = np.histogram(img2, 100)
plt.plot(h[0])
plt.title('cv2 read histogram')

plt.show()

Text Output:

(512, 512)
(512, 512)

Output:

code output



Edit:

Here is the input image:

Arafat Hasan
  • 2,811
  • 3
  • 21
  • 38
  • Would you be able to print `np.mean()` and `np.std()` for both images please so we can see if the difference is in the loading and greyscale conversion or in the histogram generation and display? Also, it would help if you shared the actual Lena image you used. – Mark Setchell Jan 22 '20 at 09:12
  • 1
    You should note that **OpenCV** and **skimage** use a fundamentally different representation of images. **OpenCV** tends to prefer 8-bit unsigned integers in range [0..255] and **skimage** tends to use floats in range [0..1]. – Mark Setchell Jan 22 '20 at 09:42
  • Thanks a lot. Intensity range difference, as you mentioned, is the reason and I've understood that. Here is `np.mean` and `np.std` and they are telling a lot. `skimage mean: 0.4578778306070963 skimage std: 0.19380367354500247 cv2 mean: 123.54518127441406 cv2 std: 47.853738824592234` – Arafat Hasan Jan 22 '20 at 12:07

1 Answers1

5

The two imread functions just have a different default format for reading the images. The skimage.io standard is using a 64-bit float, while the cv2 standard seems to be unsigned byte.
You can see this by converting img1 to the unsigned byte format.

import skimage as skk
img1 = skk.img_as_ubyte(img1)

Now you will get somewhat similar histograms.They are not perfectly the same because they are read initially as different formats.

img

meph
  • 662
  • 3
  • 10
  • Thanks a lot. I think I've understood the reason. As yet there is a difference, isn't it for precision loss while converting? – Arafat Hasan Jan 22 '20 at 12:10
  • 1
    Yes, that too. When reading as unsigned byte(in case of OpenCV) or converting (as shown above) to unsigned byte you will always lose some precision. The difference is how you lose the precision. In the case of OpenCV you lose the precision, because you are trying to represent the .png file format as a byte array. In the case of the conversion in scikt with `img_as_ubyte` you are losing precision, because you are converting from float to byte. Hope that this makes things more clear. – meph Jan 22 '20 at 13:24
  • 1
    Just an idea about how the .png format look like: https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_format – meph Jan 22 '20 at 13:24