HOWTO · Python

在 Python 中使用 OpenCV 模組反轉影象

瞭解如何使用 Python 中的 OpenCV 模組反轉影象

本頁內容

在 Python 中,將 OpenCV 傳回的陣列交給 cv2.bitwise_not(),即可反轉影像。對無符號 8 位元影像通道而言,每個值 v 都會變成 255 - v。以下各節會說明通道的處理方式,以範例像素資料展示計算過程,並示範如何處理彩色或灰階影像檔及儲存結果。

準備環境並載入影像

請在執行腳本的環境中安裝 Python 和 OpenCV。套件名稱是 opencv-python,但 Python 程式使用 cv2 匯入。若尚未安裝,請執行 pip install opencv-python。NumPy 範例也需要 NumPy;標準的 OpenCV Python 套件會將 NumPy 安裝為相依套件。

將 input_path 設為可讀取的影像檔路徑。OpenCV 預設會依 BGR 通道順序載入彩色影像。指定 image = cv2.imread(input_path) 即可載入影像;處理前請確認 image is not None,因為檔案不存在或無法讀取時,imread 會傳回 None。以下範例使用 8 位元通道值,這是常見影像檔通常採用的表示方式。

影像反轉的原理

反轉會將每個通道值轉換為其補數。對於介於 0 到 255 的無符號 8 位元值,黑色會變成白色,白色會變成黑色,而像 40 這樣的值則會變成 215。這項操作會分別套用至每個通道,因此彩色像素的藍、綠、紅值都會各自反轉。OpenCV 預設的彩色陣列通道順序是 BGR,而非 RGB;反轉會保留通道順序,因此不會交換顏色。

使用 OpenCV 反轉影像

OpenCV 的 cv2.bitwise_not() 會對陣列中的每個元素套用位元 NOT。對無符號 8 位元影像資料而言,結果等同於用 255 減去各個值。這個簡短的標準函式庫範例不需要影像檔或影像處理套件,能直接呈現像素的計算方式。可用它理解數值;處理 OpenCV 影像陣列時,請先確認影像載入成功,再呼叫 cv2.bitwise_not(image)。

執行以下範例:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

pixel = [10, 40, 200]
inverted_pixel = [255 - value for value in pixel]
print("original:", pixel)
print("inverted:", inverted_pixel)
original: [10, 40, 200]
inverted: [245, 215, 55]

若要處理影像檔,請將 input_path 和 output_path 設為影像來源與輸出目的地,再執行此範例。請先安裝 OpenCV。下方路徑是明確的佔位值,請替換成電腦上的檔案路徑;若影像載入或寫入失敗,程式會回報問題,且不會繼續處理不存在的影像。

try:
    import cv2
except ImportError:
    print("Install opencv-python to run this example.")
else:
    input_path = "input.png"
    output_path = "inverted.png"
    image = cv2.imread(input_path)

    if image is None:
        print(f"Could not read {input_path}")
    else:
        inverted = cv2.bitwise_not(image)
        written = cv2.imwrite(output_path, inverted)
        if not written:
            print(f"Could not write {output_path}")

        show_preview = False
        if show_preview:
            cv2.imshow("Original", image)
            cv2.imshow("Inverted", inverted)
            cv2.waitKey(0)
            cv2.destroyAllWindows()

載入的彩色陣列及其反轉結果分別儲存在 image 和 inverted 中。OpenCV 預設以 BGR 順序傳回彩色通道,而此操作會逐一反轉通道,不會重新排列。上方的像素計算範例展示了相同的無符號 8 位元結果。

反轉灰階影像

灰階影像的每個像素只有一個亮度值,而不是三個色彩通道。使用 cv2.IMREAD_GRAYSCALE 直接載入灰階影像,確認 gray_image is not None,再套用相同的位元操作。結果仍是二維單通道陣列,可以使用 cv2.imwrite() 儲存。

本節中的程式碼以及顯示的標籤或輸出仍為英文。

try:
    import cv2
except ImportError:
    print("Install opencv-python to run this example.")
else:
    input_path = "input.png"
    gray_output_path = "inverted-gray.png"
    gray_image = cv2.imread(input_path, cv2.IMREAD_GRAYSCALE)

    if gray_image is None:
        print(f"Could not read {input_path} as grayscale")
    else:
        inverted_gray = cv2.bitwise_not(gray_image)
        written = cv2.imwrite(gray_output_path, inverted_gray)
        if not written:
            print(f"Could not write {gray_output_path}")

使用 NumPy 反轉影像

如果影像資料已經是 NumPy 陣列,可以改用 NumPy 提供的 numpy.invert。此函式會對每個元素執行位元 NOT;對無符號 8 位元值而言,結果與 OpenCV 的通道補數相同。此範例會讀取 8 位元彩色影像、使用 NumPy 反轉,並確認結果已儲存。此處的 255 - v 解釋僅適用於無符號 8 位元資料;不要將它套用到有號或較寬的整數陣列,因為 NumPy 在這些情況下仍執行的是位元補數運算。

本節中的程式碼以及顯示的標籤或輸出仍為英文。

try:
    import cv2
    import numpy as np
except ImportError:
    print("Install opencv-python and numpy to run this example.")
else:
    input_path = "input.png"
    numpy_output_path = "inverted-numpy.png"
    image = cv2.imread(input_path)

    if image is None:
        print(f"Could not read {input_path}")
    else:
        inverted_numpy = np.invert(image)
        written = cv2.imwrite(numpy_output_path, inverted_numpy)
        if not written:
            print(f"Could not write {numpy_output_path}")

一般的 8 位元影像檔使用 cv2.bitwise_not(image) 和 numpy.invert(image) 時,會得到相同的逐通道結果。如果工作流程其他部分已使用 OpenCV,建議使用 OpenCV 的操作;若需要 NumPy 的陣列運算,則使用 NumPy 函式。

儲存並顯示反轉後的影像

請寫入對應於已反轉影像的陣列:彩色結果使用 cv2.imwrite(output_path, inverted),灰階結果則使用 cv2.imwrite(gray_output_path, inverted_gray)。請檢查傳回的布林值;False 表示 OpenCV 無法寫入檔案,例如目的地路徑無法使用或格式不受支援。範例會透過 written 檢查結果,並在寫入失敗時回報。

OpenCV 範例包含一段可選的預覽程式碼。將該處的 show_preview 設為 True,即可開啟兩個視窗。圖形介面顯示需要圖形環境,因此在無頭工作階段中可能無法使用。使用 cv2.imwrite() 儲存不需要開啟視窗。OpenCV 與 NumPy 的影像檔範例適用於已安裝相應套件且有可讀取 input.png 的環境;本文提供的執行證據僅涵蓋上方簡短的像素計算範例。