OpenCV計算機視覺學習(14)——淺談常見圖像後綴(png, jpg, bmp)的區別(opencv讀取語義分割mask的坑)

如果需要處理的原圖及代碼,請移步小編的GitHub地址

  傳送門:請點擊我

  如果點擊有誤:https://github.com/LeBron-Jian/ComputerVisionPractice

 

  本來不想碎碎念,但是我已經在圖像後綴上栽倒兩次了。而且因爲無意犯錯,根本找不到問題。不論是在深度學習的語義分割中,還是在圖像處理的軟件(Halcon, Cognex)中都載過跟頭,於是痛定思痛,決定將自己的經驗寫進這篇博客中,如果看到這篇的看官,希望不要再犯了。

問題1:亂修改圖像後綴名稱,部分軟件會報錯(halcon error #5580:PNG:file is not a PNG file)

  首先是下面的報錯,因爲openCV使用多了,我們經常會通過cv2.imread()加載出三通道的圖像,所以默認圖像都是BGR的,無論圖像是png, bmp 還是 jpg。反正都可以讀出三通道的,即使有時候無意將圖像後綴命名爲png或者jpg(或者我們網上下載的數據集中被修改了後綴),我們都不在意。但是實際上部分軟件不會像opencv自動處理,我在這裏就報錯了。

  具體深入下去,就是下圖,實際上圖像後綴是jpg,但是我拿到的數據是png,而我直接喂入軟件就報錯如上:

   實際上這兩個圖像都是png圖像,但是可能就會出現有些人誤命名,將其圖像後綴命名爲jpg。這就導致了上面的問題。

  我們具體分析,當我們將圖像後綴從.png修改爲.jpg時,實際上並沒有改變圖像的編碼方式和文件結構。而如我上面所說,OpenCV是一個功能強大的計算機視覺庫,它可以根據文件的實際內容來識別圖像格式,而不僅僅依賴於文件後綴。因此,OpenCV能夠讀取被錯誤命名的圖像文件。

  然而,其他一些軟件可能只依賴於文件後綴來確定圖像格式,而不會嘗試解析文件內容。當你將圖像後綴從.png修改爲.jpg時,這些軟件可能會嘗試按照JPEG格式去解析該文件,但是由於文件實際上是一個PNG格式的圖像,所以會報錯並指出文件不是一個有效的PNG文件。

  所以要正確地處理圖像文件,建議使用正確的文件後綴來反映實際的圖像格式。這樣可以確保不同的軟件能夠正確地解析和處理圖像文件。

問題2:圖像隨便保存爲jpg,結果mask結果對不上

  當我寫這篇博客的時候,我發現也有網友有同樣的問題,哈哈哈,於是我就更堅決了自己要寫這個的原因。

  首先復現一下下面問題,並解釋一下。

  我們就將輸出的圖像保存爲圖像(即jpg和png),然後讀取出來,看看結果:

import sys
import os
import numpy as np


def count_pixel_values(image):
    count_res = {}
    # 統計像素值數量
    pixel_counts = np.bincount(image.flatten())
    # 顯示結果
    for pixel_value, count in enumerate(pixel_counts):
        if count > 0:
            count_res[pixel_value] = count
    return count_res


# 讀取一張圖像,將其轉換爲灰度圖
image = cv2.imread(r"./Abyssinian_1.png", 0)

# 創建二值圖像
binary_image = np.zeros_like(image, dtype=np.uint8)
binary_image[image == 1] = 0  # 像素值1對應0像素
binary_image[image == 2] = 125  # 像素值2對應125像素
binary_image[image == 3] = 255  # 像素值3對應255像素

# 1, 我將二值圖結果保存爲jpg 和png,我們分別看看
# cv2.imwrite(r"./cat.png", binary_image)
# cv2.imwrite(r"./cat.jpg", binary_image)

# 2, 我分別打開png 和 jpg 的圖像

png_mask = cv2.imread(r"./cat.png", 0)
jpg_mask = cv2.imread(r"./cat.jpg", 0)
print(np.array_equal(png_mask, binary_image), np.sum(png_mask != binary_image))
pixel_counts_png = count_pixel_values(png_mask)
print(pixel_counts_png)
print(np.array_equal(jpg_mask, binary_image), np.sum(jpg_mask != binary_image))
pixel_counts_jpg = count_pixel_values(jpg_mask)
print(pixel_counts_jpg)

# 使用sys.getsizeof()函數來獲取圖像對象的大小
# 使用os.path.getsize()函數來獲取圖像文件的大小
binary_image_memory_size = sys.getsizeof(binary_image)
png_mask_memory_size = sys.getsizeof(png_mask)
jpg_mask_memory_size = sys.getsizeof(jpg_mask)
print("二值圖圖像內存大小: {} 字節".format(binary_image_memory_size))
print("jpg二值圖圖像內存大小: {} 字節".format(png_mask_memory_size))
print("png二值圖圖像內存大小: {} 字節".format(jpg_mask_memory_size))
binary_image_file_size = os.path.getsize(r"./Abyssinian_1.png")
png_mask_file_size = os.path.getsize(r"./cat.png")
jpg_mask_file_size = os.path.getsize(r"./cat.jpg")
print("二值圖圖像文件大小: {} 字節".format(binary_image_file_size))
print("jpg二值圖圖像文件大小: {} 字節".format(png_mask_file_size))
print("png二值圖圖像文件大小: {} 字節".format(jpg_mask_file_size))

"""
True 0
{0: 22938, 125: 198766, 255: 18296}
False 8258
{0: 21455, 1: 701, 2: 414, 3: 234, 4: 95, 5: 27, 6: 7, 7: 4, 8: 1, 119: 2, 120: 27, 121: 147, 122: 259, 123: 517, 124: 839, 125: 195208, 126: 879, 127: 449, 128: 258, 129: 123, 130: 38, 131: 17, 132: 3, 248: 7, 249: 12, 250: 71, 251: 170, 252: 421, 253: 911, 254: 1625, 255: 15079}


"""

  

  分析: 實際上我的binary_image圖像只有1,2,3三個像素,即使我轉換爲0, 125, 255後,仍然只有三個像素 但是當我保存結果爲PNG的時候,結果無誤,仍然是三個像素 而我保存結果是JPG的時候,結果存在誤差,爲多個像素

  結論: 當將二值化的圖像保存爲jpg的時候,會出現圖像損壞,所以保存圖像的時候,使用jpg需要謹慎 。

  當我查看圖像本身的大小的時候 :

二值圖圖像內存大小: 240120 字節 
jpg二值圖圖像內存大小: 240120 字節 
png二值圖圖像內存大小: 240120 字節 

二值圖圖像文件大小: 2994 字節 
jpg二值圖圖像文件大小: 3814 字節 
png二值圖圖像文件大小: 18127 字節

  在OpenCV中,圖像保存爲不同後綴(如PNG、JPEG、BMP)的文件時,它們的文件格式和存儲方式是不同的,儘管它們可能在視覺上看起來相同。 這是因爲不同的圖像格式使用不同的壓縮算法和編碼方式來存儲圖像數據。這些格式有各自的優勢和特點,適用於不同的應用和需求。

  還有下面的:

     比如我們查看一張特殊的png格式的mask圖像,如下(特殊是因爲是彩色的灰度圖):

  和一張正常的mask圖像,如下:

 

  我們對比一下,實驗如下:

import cv2
from PIL import Image
import numpy as np

"""
測試任務:
    1,使用opencv直接讀取png圖像
    2,使用opencv讀取png圖像,以原始的通道順序讀取PNG圖像,而不進行任何顏色通道的轉換
    3,使用PIL庫讀取png圖像
    4,判斷opencv讀取的圖像是否修改像素值

測試方案及結論:
    1,使用語義分割的mask圖像,像素只有1,2,3進行測試。
        測試結果如下:
                cv_img shape:  (400, 600)
                cv_origin_img shape:  (400, 600)
                pil_img_np shape:  (400, 600)
                0
                0
                pixel_counts_png_cv1:  {1: 22938, 2: 198766, 3: 18296}
                pixel_counts_png_cv2:  {1: 22938, 2: 198766, 3: 18296}
                pixel_counts_png_pil:  {1: 22938, 2: 198766, 3: 18296}
        測試結論:
            對於像素只有1,2,3的圖像,無論用什麼讀取結果都一樣。
            
    2, 測試我截圖的那個哥們,我使用的是PNG圖片,而且是8bit的深度,但是有些圖像會不變,有些會變。
        使用語義分割的mask圖像,是彩色圖像。
        測試結果如下:
            cv_img shape:  (468, 625)
            cv_origin_img shape:  (468, 625, 3)
            pil_img_np shape:  (468, 625)
            128589
            1
            pixel_counts_png_cv1:  {0: 163911, 15: 16626, 72: 36210, 75: 5261, 95: 12644, 135: 37681, 220: 20167}
            pixel_counts_png_cv2:  {0: 584361, 64: 12644, 128: 133459, 192: 106702, 224: 40334}
            pixel_counts_png_pil:  {0: 163911, 2: 5261, 4: 16626, 13: 36210, 25: 12644, 39: 37681, 255: 20167}
            385767
            
        測試結論:
            對於像素存在多個不同的pixel的話,可以看出opencv讀取數據,會修改像素值。
"""


def count_pixel_values(image):
    count_res = {}
    # 統計像素值數量
    pixel_counts = np.bincount(image.flatten())
    # 顯示結果
    for pixel_value, count in enumerate(pixel_counts):
        if count > 0:
            count_res[pixel_value] = count
    return count_res


# img_path = r"./Abyssinian_1.png"
img_path = r"./000004.png"

# opencv 直接讀取圖像(會默認轉換爲BGR)
cv_img = cv2.imread(img_path)
# 因爲我們知道要對比的是單通道的圖像,所以先轉換爲灰度圖
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)

# opencv讀取原始通道
cv_origin_img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)

# PIL 庫讀取image

pil_img = Image.open(img_path)
pil_img_np = np.array(pil_img)
print("cv_img shape: ", cv_img.shape)
print("cv_origin_img shape: ", cv_origin_img.shape)
print("pil_img_np shape: ", pil_img_np.shape)

print(np.sum(cv_img != pil_img_np))
print(np.sum(cv_origin_img != pil_img_np))
pixel_counts_png_cv1 = count_pixel_values(cv_img)
pixel_counts_png_cv2 = count_pixel_values(cv_origin_img)
pixel_counts_png_pil = count_pixel_values(pil_img_np)
print("pixel_counts_png_cv1: ", pixel_counts_png_cv1)
print("pixel_counts_png_cv2: ", pixel_counts_png_cv2)
print("pixel_counts_png_pil: ", pixel_counts_png_pil)

merge_cv = cv2.merge([cv_img, cv_img, cv_img])
merge_pil = cv2.merge([pil_img_np, pil_img_np, pil_img_np])
print(np.sum(merge_cv != merge_pil))

  

總結:對兩個問題的分析和總結

  上面的實驗和錯誤點,都說明了一個問題。對於保存圖像格式爲png還是jpg,我們根本不清楚,也不是很理解這二者到底有啥區別,到底哪個保存像素高,哪個低。哪個佔的內存大,哪個小。哪個改變像素,哪個保存原始像素,實際上都一臉懵逼。

  於是我覺得要解決上面問題,首先必須瞭解其構成原理。下面詳細學習一下。

 

1,圖像後綴jpg, bmp, png的定義

1.1 JPG的定義

  JPEG(Joint Photographic Experts Group)是一種常見的有損壓縮位圖圖像格式,廣泛用於存儲和傳輸照片和其他真實場景圖像。它的目標是通過壓縮算法在圖像質量和文件大小之間找到平衡。它通過犧牲一些細節來減小圖像文件的大小。JPEG格式通常用於保存照片、彩色圖像等,以便在網絡上共享或用於顯示,因爲它可以在相對較小的文件大小下提供較好的視覺質量。

  以下是JPEG圖像格式的一些簡介:

  1. 有損壓縮:JPEG使用有損壓縮算法,通過犧牲一些圖像細節來減小文件大小。壓縮程度可以通過調整壓縮質量參數來控制,不同的壓縮質量會導致不同程度的圖像質量損失。

  2. 適用於連續色調圖像:JPEG主要用於存儲連續色調的圖像,特別是照片和真實場景圖像。它對顏色和亮度的變化有較好的表示能力,適用於自然圖像的壓縮和顯示。

  3. 24位位深:JPEG支持真彩色圖像,即每個像素使用24位(RGB三通道)來表示顏色。這使得JPEG可以表示約1677萬種顏色。

  4. 可調壓縮質量:JPEG允許用戶根據需要選擇不同的壓縮質量。較高的壓縮質量會產生較大的文件大小,同時保留更多的圖像細節。較低的壓縮質量會產生更小的文件大小,但會引入更明顯的圖像質量損失。

  5. 不支持透明度:JPEG不支持像PNG那樣的透明度,它只能表示不透明像素。這使得它不適合用於需要透明背景的圖像,如圖標和疊加圖像。

  6. 平臺無關性:JPEG圖像格式是平臺無關的,可以在不同的操作系統和軟件中進行讀取和顯示。

  JPEG圖像格式在圖像壓縮和存儲領域具有廣泛應用,特別是用於照片和真實場景圖像。然而,由於有損壓縮的特性,JPEG格式不適合用於需要精確無損表示和透明度的應用,如圖形設計、圖像處理和需要保留細節的專業應用。

1.2 PNG的定義

  PNG(Portable Network Graphics)是一種無損的位圖圖像格式,廣泛用於存儲和傳輸圖像。它的目標是提供一種比傳統的GIF格式更好的替代方案,同時避免了GIF格式的一些限制和專利問題。它可以保留圖像的原始質量和細節。PNG格式通常用於保存需要保持高質量且不損失細節的圖像,例如圖標、透明背景的圖像等。

  以下是PNG圖像格式的一些簡介:

  1. 無損壓縮:PNG使用無損壓縮算法,不會引入圖像質量損失。相比於有損壓縮格式如JPEG,PNG適用於那些需要保留細節和圖像質量的應用,例如圖像編輯、圖形設計和Web圖像。

  2. Alpha通道支持:PNG支持透明度和半透明效果,通過Alpha通道可以定義像素的不透明度。這使得PNG成爲合適的選擇用於圖像疊加和合成。

  3. 256級灰度和真彩色支持:PNG支持灰度圖像(8位位深)和真彩色圖像(24位位深)。真彩色PNG圖像可以顯示約1677萬種顏色,提供更豐富和精確的顏色表示。

  4. 支持無損透明度:PNG的透明度支持不僅限於簡單的完全透明和完全不透明,還可以定義不同的透明度級別,實現更復雜的透明效果。

  5. 平臺無關性:PNG圖像格式是平臺無關的,可以在不同的操作系統和軟件中進行讀取和顯示。

  6. 版權和專利:PNG是一種開放標準格式,沒有涉及專利或版權限制。這使得PNG成爲一種廣泛採用的圖像格式。

  總體而言,PNG圖像格式在保持圖像質量、支持透明度和顏色表示方面具有優勢,並被廣泛應用於圖像處理、Web圖像、圖形設計和其他需要保留圖像細節和質量的應用中。

1.3 GIF的定義

  GIF(Graphics Interchange Format)是一種常見的無損壓縮位圖圖像格式,廣泛用於存儲和傳輸簡單的動畫和圖形。GIF圖像格式最初由CompuServe開發,後來成爲互聯網上最流行的圖像格式之一。

以下是GIF圖像格式的一些簡介:

  1. 無損壓縮:GIF使用無損壓縮算法,不會引入圖像質量損失。這使得它適用於存儲和傳輸需要保留細節和圖像質量的應用。

  2. 索引調色板:GIF使用調色板技術,其中圖像中的每個像素值通過調色板中的索引來表示。調色板最多可以包含256種不同的顏色。

  3. 動畫支持:GIF支持多幀動畫,可以在一張圖像文件中存儲多個圖像幀,通過控制幀間延遲時間來創建簡單的動畫效果。

  4. 透明度支持:GIF支持透明像素,其中一個顏色被定義爲透明。這使得GIF圖像可以顯示透明背景,並與其他圖像疊加。

  5. 簡單圖形和動畫:GIF主要用於存儲簡單的圖形、圖標和動畫。它對於圖像的顏色數目和細節有一定的限制,通常不適用於照片和真實場景圖像。

  6. 支持LZW壓縮算法:GIF使用LZW(Lempel-Ziv-Welch)壓縮算法來減小文件大小。該算法通過創建和使用字典來編碼圖像數據,以進一步壓縮數據。

  GIF圖像格式在Web圖像、圖標、簡單動畫和圖形設計中得到廣泛應用。由於它的無損壓縮和透明度支持,GIF圖像通常用於需要保留圖像質量和簡單動畫的情況。然而,由於調色板限制和對顏色和細節的限制,GIF不適用於需要更高質量和更豐富顏色表示的照片和真實場景圖像。

 

1.4 BMP的定義

  BMP(Bitmap)是一種常見的無壓縮位圖圖像格式,它是Windows操作系統中最常見的圖像格式之一。BMP圖像格式以像素爲單位存儲圖像數據,提供了對象的精確控制和編輯,以下是BMP圖像格式的一些簡介:

  1. 無壓縮:BMP使用無壓縮的位圖數據存儲圖像,不會引入圖像質量損失。它以原始像素數據的形式存儲每個像素的顏色值,因此文件大小相對較大。
  2. 位深度:BMP支持不同的位深度,包括1位(黑白圖像)、8位(256級灰度或調色板索引顏色)和24位(真彩色,約1677萬種顏色)。高位深的BMP圖像可以提供更精確的顏色表示和圖像細節。
  3. 像素數據佈局:BMP圖像按行存儲像素數據,每行的像素從左到右依次排列。每個像素可以使用RGB顏色模式(對於24位位深)或調色板索引(對於8位位深)來表示。
  4. 支持透明色:BMP圖像可以指定一個顏色作爲透明色,使得該顏色在圖像顯示時變爲透明,適用於一些特殊效果的實現。
  5. 平臺無關性:BMP圖像格式是平臺無關的,可以在不同的操作系統和軟件中進行讀取和顯示。
  6. 大文件大小:由於無壓縮的特性,BMP圖像文件大小相對較大,對存儲和傳輸的需求較高。這使得BMP不太適用於Web圖像和需要節省存儲空間的應用。

  BMP圖像格式適用於那些需要對圖像進行精確編輯、保留圖像細節和顏色準確性的應用。然而,由於文件大小較大和缺乏壓縮,BMP圖像在Web圖像和存儲空間受限的場景中使用較少。


1.5 常見的JPEG和PNG的區別

  雖然我上面已經摘抄出了其定義,但是我估計大多數人不仔細看,所以我直接將常見的JPEG和PNG的區別整理如下。

  JPEG和PNG是常見的圖像格式,它們在圖像壓縮、質量損失、透明度支持等方面存在一些區別。下面是一些主要的區別:

  1. 壓縮算法:

    • JPEG使用有損壓縮算法,它通過減少圖像中的細節和顏色信息來減小文件大小。這導致在高壓縮比下會損失一些細節,併產生一些壓縮僞影。
    • PNG使用無損壓縮算法,它能夠保持圖像的原始質量和細節。它適用於保存需要保持高質量且不損失細節的圖像,但文件大小通常比JPEG大。
  2. 顏色支持:

    • JPEG主要適用於彩色圖像,它能夠顯示數百萬種顏色
    • PNG支持全綵色圖像,並能夠顯示透明度。它還支持索引調色板,可以減小文件大小。
  3. 透明度支持:

    • JPEG不支持透明度。任何圖像中的透明部分將以黑色或白色進行填充。
    • PNG支持透明度,並能夠將圖像中的某些部分設置爲完全透明,以便與背景融合。
  4. 文件大小:

    • JPEG在相同視覺質量下,文件大小通常比PNG要小。這使得它適用於在帶寬受限的環境下傳輸圖像,如網絡傳輸。
    • PNG文件大小通常比JPEG大,因爲它使用無損壓縮算法。這使得它適用於需要保持高質量的圖像存儲,如圖標、透明背景等。

 

1.6 什麼是圖像位深

   當我們看到一張數字圖像時,我們常常會關注圖像的顏色、細節和質量。這些特徵與圖像的位深(Bit Depth)密切相關。圖像位深是指數字圖像中每個像素所使用的二進制位數,用於表示顏色或亮度的信息量或精度。本文將介紹圖像位深的定義、常見的位深類型以及它們之間的區別。

  位深定義: 位深表示每個像素值所使用的二進制位數。較高的位深可以提供更多的顏色或灰度級別,從而實現更準確的顏色表示和更細緻的圖像細節。例如,一個8位位深的圖像可以表示256個不同的亮度或顏色級別(0-255),而一個16位位深的圖像可以表示65,536個級別。

  常見的位深類型

  1. 1位(2色):1位位深的圖像只能表示兩個顏色或灰度級別,通常爲黑色和白色。
  2. 8位(256色):8位位深的圖像可表示256個不同的顏色或灰度級別。這種位深常用於網頁圖像、簡單的圖形和圖像處理應用。
  3. 24位(真彩色):24位位深的圖像通常稱爲真彩色圖像,因爲它能夠表示約1677萬種顏色。這是最常見的圖像位深,適用於照片、圖像處理和顯示應用。
  4. 32位(增強色彩):32位位深的圖像在真彩色基礎上加入了額外的通道,通常爲透明度通道(Alpha通道)。這種位深常用於圖像合成和透明效果。

  位深之間的區別: 不同的位深具有不同的顏色精度和可表示範圍。較高的位深可以提供更豐富的顏色或灰度級別,更好地保留圖像的細節和質量。然而,較高的位深也需要更多的存儲空間來保存圖像數據,並對圖像處理和顯示的計算資源有更高的要求。

  總結: 圖像位深是指數字圖像中每個像素所使用的二進制位數,用於表示顏色或亮度的信息量或精度。不同的位深可以提供不同的顏色精度和細節級別,常見的位深包括1位、8位、24位和32位。通過選擇適當的位深,我們可以平衡圖像質量和存儲需求,以滿足特定應用的需求。

 

2  如何查看真實的圖像後綴

  如果真的被修改了後綴,那麼我們如何查看文件後綴呢,下面方法可以讓其原形畢露。

2.1  常見的圖像格式及其十六進制

  下面是一些常見圖像格式及其文件頭的十六進制表示:

  1. JPEG/JPG:

    • 文件頭:FF D8 FF
    • 文件尾(結束標記):FF D9
  2. BMP:

    • Windows BMP(非壓縮)文件頭:42 4D
    • Windows BMP(壓縮)文件頭:42 4D
    • OS/2 BMP文件頭:42 4D
  3. PNG:

    • 文件頭:89 50 4E 47 0D 0A 1A 0A
    • 文件尾(IEND標記):49 45 4E 44 AE 42 60 82
  4. GIF:

    • 文件頭:47 49 46 38 39 61 或 47 49 46 38 37 61
    • 文件尾(結束標記):00 3B
  5. TIFF:

    • Little-Endian(Intel)格式文件頭:49 49 2A 00
    • Big-Endian(Motorola)格式文件頭:4D 4D 00 2A
  6. ICO:

    • 文件頭:00 00 01 00
  7. PSD (Photoshop):

    • 文件頭:38 42 50 53
  8. WebP:

    • 文件頭:52 49 46 46 ?? ?? ?? ?? 57 45 42 50
  9. SVG (可縮放矢量圖形):

    • 文件頭:3C 73 76 67

  這些是一些常見的圖像格式及其文件頭的十六進制表示。請注意,文件頭的確切值可能因特定軟件、文件版本或其他因素而有所變化。因此,在實際應用中,最好使用專門的圖像處理庫或工具來解析和處理不同圖像格式的文件。

2.2  使用專門的工具解析圖像

  下面看看我們上面整理的文件頭是否正確,下面查看四種常見的不同後綴的文件的文件頭:

 

 

3,爲什麼opencv讀取數據的格式都是BGR呢?

  爲了瞭解清楚,我還特意查了爲什麼opencv讀取數據的格式是BGR而不是RGB呢?

  OpenCV讀取圖像時將其表示爲BGR(藍綠紅)通道順序的像素排列。這是因爲在許多計算機視覺應用中,BGR通道順序是最常用的,尤其是在早期的彩色圖像處理中。歷史上,BGR通道順序的選擇與許多計算機視覺庫和工具的設計有關,包括OpenCV。這些庫和工具在早期的硬件和軟件平臺上的開發中,採用了BGR通道順序的表示方式。

  OpenCV讀取圖像爲BGR的歷史原因可以追溯到早期計算機視覺應用的發展和硬件限制。在計算機視覺領域的早期,主要應用是在基於CRT(陰極射線管)顯示器的計算機系統上進行圖像處理。在這些系統中,圖像數據通常是以RGB(紅綠藍)通道順序存儲的,因爲CRT顯示器的光柵掃描方式是從左上角開始,按照RGB的順序逐行掃描。

  然而,在早期的計算機體系結構和操作系統中,處理圖像數據的方式可能與顯示器的存儲方式不同。由於BGR通道順序在一些早期圖像處理庫和工具中被採用,OpenCV也選擇了這種通道順序。

  此外,早期的計算機系統在內存中存儲圖像數據時採用了連續的行優先(row-major)存儲方式。而BGR通道順序在這種存儲方式下能夠更好地利用內存的連續性,從而提高圖像數據的讀取效率。

  儘管現代計算機和顯示器普遍使用RGB通道順序,但由於OpenCV的廣泛應用和與現有代碼的兼容性考慮,保持了BGR通道順序作爲默認的圖像表示方式。

  需要注意的是,雖然OpenCV默認將圖像讀取爲BGR通道順序,但可以使用適當的函數將圖像轉換爲其他通道順序,如前面提到的cv2.cvtColor()函數。這使得在OpenCV中進行RGB格式圖像的處理仍然是可行的。

  在現代計算機視覺領域,許多其他工具和庫使用RGB(紅綠藍)通道順序來表示圖像。RGB通道順序更符合人眼感知顏色的方式,因爲光的三原色是紅、綠和藍。

 

4,python如何轉換png到JPG,JPG到PNG

   當然,OpenCV也是OK的,直接保存的時候設置圖像後綴即可,但是因爲我推薦使用PIL庫。所以我的示例腳本都是使用PIL庫實現的,代碼如下:

from PIL import Image

"""
使用PIL庫保存不同格式的圖像(常見的轉換,比如jpg轉png, png轉jpg)
這裏驗證的是:
    1,將 jpg 轉換爲 png,並保存
    2,將保存的png 讀取出來再保存爲 jpg
    3,對於保存的jpg 和原始的jpg 看結果是否相等
    
結論:
    False
    原因:
    JPEG格式對圖像進行壓縮時,會丟失一些細節和像素信息,因此還原回去的圖像與原始的PNG圖像可能存在一些差異。
    將PNG圖像保存爲JPEG格式會引起一定程度的圖像壓縮損失,因爲JPEG是一種有損壓縮格式。因此,還原回去的圖像和原始的img不會完全相等。

"""

# step1: 將 jpg 格式保存爲png
img_jpg = Image.open("./test/cat.jpg")
# save()有兩個參數,第一個是保存轉換後文件的文件路徑,第二個參數是要轉換的文件格式。
img_jpg.save("./test/cat_jpg2png.png", "PNG")

#
img_png = Image.open("./test/cat_jpg2png.png")
img_png.save("./test/cat_jpg2png2jpg.jpg", "JPEG")

img_origin_jpg = Image.open("./test/cat.jpg")
img_convert_jpg = Image.open("./test/cat_jpg2png2jpg.jpg")
print(img_origin_jpg.getdata(), type(img_convert_jpg.getdata()))
# <ImagingCore object at 0x000001D5E4197590> <class 'ImagingCore'>
pixels1 = list(img_origin_jpg.getdata())
pixels2 = list(img_convert_jpg.getdata())
print(pixels1 == pixels2)
# False

  

 

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