转载于大佬:[原链接](https://blog.csdn.net/oukohou/article/details/82378552)
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,然后得到的结果是什么样的呢:
看起来好像差不多,但是具体的矩阵对比为:
可以看到,其矩阵值在RGB通道上总是会有那么几个像素值的差异。
3. But why?
这是为什么呢?一张图像,读取、保存、再读取,两次读取的结果不应该是一致的么?
try 1:
猜测会不会是opencv 的imwrite函数的问题呢?其在写入图像的时候会不会有什么不为人知的小秘密?
于是采用了PIL中的Image进行同样的测试,发现结果一样:
- 依然会有一定像素值的差异。
然而,一个不经意的小细节给了我们提示:
debug的时候发现,用于两次读取的图像类不同!最开始用的是PIL.Image.IMage类,但读取保存后的.jpeg图像时,用的是PIL.JpegImagePlugin.JpegImageFile类!好了,这时我们就隐约猜到了,应该与保存的图像格式相关。
try 2:
于是我们把保存的图像格式变为.png,再次测试:
得到的图像对比是这样,看起来还是差不多,那么像素值呢?
哇哦哇哦哇哦,nothing different!两次读取的结果完全一致!
4. Conclusion
所以问题应该在于,.jpeg后缀的图像,其由于jpeg图像本身的编解码问题,写入时的编码与读取时的解码所得不能完美互为逆操作,从而导致的每次写入之后,读取的值都不同。
写到这里,搜了搜关键字”jpeg编解码 有损“的结果 ,也确实如此。Jpeg是一种有损压缩,而png是无损压缩。
到这里,也就解决了这个其实算不上bug的bug:
- 由于图像编解码算法的原因,注定了jpeg图像的写入、读取结果会不一致,而png图像则完全一致。
这应该算是一个小tip吧,对于不是专业搞图像的、但又要日常与图像打交道的我来说,对于图像的存取,以后还是都保存为png格式为妙。
以上,你的赞是我最大的动力!
Scan and we’ll see.