opencv的cv2.imwrite()函数写图像之后,再次读取,其像素值不相等的bug

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/oukohou/article/details/82378552

我的博客已全部迁往个人博客站点:oukohou.wang,敬请前往~~


opencv的cv2.imwrite()函数写图像之后,再次读取,其像素值不相等的bug

1. 今天刚发现的一个小bug:

用opencv的imread()函数读取一张图像之后,将其保存为’.jpeg’后缀的图像,然后再次读取刚刚保存的图像,会发现两次读取的图像,其像素值不相等?

2. Bug复现:

复现代码如下:

# -*- coding: utf-8 -*-

__author__ = 'kohou.wang'
__time__ = '18-9-3'

# If this runs wrong, don't ask me, I don't know why;
# If this runs right, thank god, and I don't know why.
# Maybe the answer, my friend, is blowing in the wind.

import cv2
import matplotlib.pyplot as plt

if __name__ == "__main__":
    img1 = cv2.imread('temp.jpeg')  # 读取图像
    cv2.imwrite('temp1.jpeg', img1)  # 保存图像
    img2 = cv2.imread('temp1.jpeg')  # 读取图像
    
    # 打印两次图像以作对比
    plt.subplot(1, 2, 1)
    plt.imshow(img1)
    plt.title('origin')
    plt.subplot(1, 2, 2)
    plt.imshow(img2)
    plt.title('after')
    plt.show()

OK,然后得到的结果是什么样的呢:
对比图
看起来好像差不多,但是具体的矩阵对比为:
img1的像素值
img2的像素值
可以看到,其矩阵值在RGB通道上总是会有那么几个像素值的差异。

3. But why?

这是为什么呢?一张图像,读取、保存、再读取,两次读取的结果不应该是一致的么?

try 1:

猜测会不会是opencv 的imwrite函数的问题呢?其在写入图像的时候会不会有什么不为人知的小秘密?
于是采用了PIL中的Image进行同样的测试,发现结果一样:

  • 依然会有一定像素值的差异。

然而,一个不经意的小细节给了我们提示:
两个图像的类不同
debug的时候发现,用于两次读取的图像类不同!最开始用的是PIL.Image.IMage类,但读取保存后的.jpeg图像时,用的是PIL.JpegImagePlugin.JpegImageFile类!好了,这时我们就隐约猜到了,应该与保存的图像格式相关。

try 2:

于是我们把保存的图像格式变为.png,再次测试:
PNG_result
得到的图像对比是这样,看起来还是差不多,那么像素值呢?
img1_png
img2_png
哇哦哇哦哇哦,nothing different!两次读取的结果完全一致!

4. Conclusion

所以问题应该在于,.jpeg后缀的图像,其由于jpeg图像本身的编解码问题,写入时的编码与读取时的解码所得不能完美互为逆操作,从而导致的每次写入之后,读取的值都不同。
写到这里,搜了搜关键字”jpeg编解码 有损“的结果 ,也确实如此。Jpeg是一种有损压缩,而png是无损压缩。
到这里,也就解决了这个其实算不上bug的bug:

  • 由于图像编解码算法的原因,注定了jpeg图像的写入、读取结果会不一致,而png图像则完全一致。

这应该算是一个小tip吧,对于不是专业搞图像的、但又要日常与图像打交道的我来说,对于图像的存取,以后还是都保存为png格式为妙。

以上,你的赞是我最大的动力!


Scan and we’ll see.
oukohou

猜你喜欢

转载自blog.csdn.net/oukohou/article/details/82378552