天天看點

使用Python,OpenCV和Scikit-Image檢測低對比度圖像

使用Python,OpenCV和Scikit-Image檢測低對比度圖像

    • 1. 效果圖
    • 2. 原理
    • 3. 源碼
    • 參考

這篇部落格将介紹如何使用Python,OpenCV和Scikit-Image檢測低對比度圖像。

在良好受控的光照條件下拍攝照片,将更便于處理。

在動态條件下拍攝的照片将更具有個别性,使得不能覆寫所有的場景及邊緣案例。

檢測低對比度的一個應用是:在應用算法前,過濾掉低對比度的圖像,因其往往會導緻不夠準确的結果。

1. 效果圖

非低對比度圖像效果圖,可以看到最大輪廓正确檢測且展示。右側的邊緣圖也很清晰,前景與背景較好的區分開。

使用Python,OpenCV和Scikit-Image檢測低對比度圖像

低對比度圖像效果圖,可以看到輪廓檢測的結果map圖,邊界框模糊,前景與背景的分界處并沒有正确展示。是以在檢測時會直接跳過繪制最大邊緣:

使用Python,OpenCV和Scikit-Image檢測低對比度圖像

2. 原理

  • 低對比度圖像/幀會産生什麼問題?怎樣才能檢測到它們?

    低對比度圖像在光線亮區域和暗區域之間具有很小的差異,使得難以看到對象的邊界與背景的分界處。

    越是在光照良好的條件下拍照的圖像,越是便于編碼處理。邊緣案例的複雜通道圖像難以覆寫全,且不易處理。

    低對比度圖像會使寫死算法(例如,模糊尺寸,門檻值限制,Canny Edge檢測參數等)可能導緻不正确/無法使用的輸出。是以,在圖像進行中,可以檢測并丢棄掉低對比度的圖像,以保證算法能得出正确的結果。

3. 源碼

# USAGE
# python detect_low_contrast_image.py --input images

# 導入必要的包
from skimage.exposure import is_low_contrast  # 該函數用于通過檢查圖像的直方圖然後确定亮度範圍跨越全範圍的分數量來檢測低對比度圖像。
from imutils.paths import list_images
import argparse
import imutils
import cv2

# 建構指令行參數及解析
# --input 輸入圖像路徑
# --thresh 低對比度的門檻值,0.35意味着當亮度區域少于整個圖像的0.35時,認為時低對比度圖像;由于OpenCV中的圖像是由一系列值的無符号8位整數表示[0,255]。
#          如果像素強度的分布占據該[0,255]範圍的35%,則圖像被認為是低對比度。
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--input", required=True,
                help="path to input directory of images")
ap.add_argument("-t", "--thresh", type=float, default=0.45,
                help="threshold for low contrast")
args = vars(ap.parse_args())

# 擷取輸入圖像路徑
imagePaths = sorted(list(list_images(args["input"])))

# 周遊圖像路徑
for (i, imagePath) in enumerate(imagePaths):
    # 從磁盤加載,保持寬高比的縮放圖像,轉換為灰階圖
    print("[INFO] processing image {}/{}".format(i + 1, len(imagePaths)))
    image = cv2.imread(imagePath)
    image = imutils.resize(image, width=450)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # 高斯平滑圖像以減少高頻噪音,并執行邊緣檢測
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    edged = cv2.Canny(blurred, 30, 150)

    # 初始化非低對比度的文本及顔色,綠色
    text = "Low contrast: No"
    color = (0, 255, 0)

    # 檢查圖像是否低對比度
    if is_low_contrast(gray, fraction_threshold=args["thresh"]):
        # 更新低對比度檔案及顔色,紅色
        text = "Low contrast: Yes"
        color = (0, 0, 255)
    # 如果不是低對比度,繼續處理
    else:
        # 在邊緣圖中找到最大的輪廓,認為其實彩色校正圖檔的外輪廓
        cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
                                cv2.CHAIN_APPROX_SIMPLE)
        cnts = imutils.grab_contours(cnts)
        c = max(cnts, key=cv2.contourArea)

        # 在圖像上繪制最大輪廓
        cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
        # for i,c in enumerate(cnts):
        #     # 在圖像上繪制最大輪廓
        #     cv2.drawContours(image, [c], -1, (0, 255, 0), 2)

    # 輸出圖像上繪制文本
    cv2.putText(image, text, (5, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
                color, 2)
    # 展示輸出圖像和邊緣圖
    cv2.imshow("Image", image)
    cv2.imshow("Edge", edged)
    cv2.waitKey(0)
           

參考

  • https://www.pyimagesearch.com/2021/01/25/detecting-low-contrast-images-with-opencv-scikit-image-and-python/