opencv的cv2.imwrite()函數寫圖像之後,再次讀取,其像素值不相等的bug

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章