OpenCV のヒストグラム平坦化でコントラストを強調する

画像のコントラストを上げるのに、OpenCV の cv2.equalizeHist や、cv2.createCLAHE といったヒストグラム平坦化機能が活用できる。これらを試してみた結果を投稿する。

元画像

元画像は野鳥観察壁。壁を主役にするには、少し暗い。

野鳥観察壁:小窓からバードウォッチングができる

cv2.equalizeHist で各色を平坦化

明るさのヒストグラムを平坦にするために、cv2.equalizeHist を使ってみた。cv2.equalizeHist は単色でしか扱えないため、cv2.split で b, g, r の3色にし、それぞれヒストグラム平坦化をした。

cv2.equalizeHist で各色をヒストグラム平坦化
    # 各色で平坦化                                                                                                                          
    b1,g1,r1 = cv2.split(img)
    b2 = cv2.equalizeHist(b1)
    g2 = cv2.equalizeHist(g1)
    r2 = cv2.equalizeHist(r1)
    eqh_rgb = cv2.merge((b2,g2,r2))

壁の様子は分かるようになるが、赤が強調されすぎて、元の画像から印象が変化しすぎた。

cv2.equalizeHist で HSV 空間の V を平坦化

色合いを保存しつつ平坦化するために、色空間を BGR から HSV に変換した後に cv2.equalizeHist を適用する。

cv2.equalizeHist で HSV 空間の V を平坦化
    # HSVのvだけ編集                                                                                                                        
    h1,s1,v1 = cv2.split(cv2.cvtColor(img,cv2.COLOR_BGR2HSV))  # 色空間をBGRからHSVに変換                                                   
    v2 = cv2.equalizeHist(v1)
    eqh_hsv = cv2.cvtColor(cv2.merge((h1,s1,v2)), cv2.COLOR_HSV2BGR)

出力したかった画像に近づいた。ただ、同じ色の面積が大きいと、少しザラザラした印象になる。

cv2.createCLAHE による平坦化

cv2.createCLAHE でも調整ができる。cv2.createCLAHE は部分的にヒストグラム平坦化を行いコントラスト強調する。equalizeHist と違い、2つの引数(lipLimit と tileGridSize) を持てるため、引数を変更することで画像の調整が可能になる。clipLimit を大きくすればコントラストが強くなり、荒くなる。tileGridSize は大きいと大局的に平坦化、小さいと部分的に平坦化する。

cv2.createCLAHE による平坦化 パラメータは clipLimit = 2. と tileGridSize = (4, 4) の設定
# 部分的にヒストグラム平坦化でコントラスト強調                                                                                              
def clc(img,cl,gsize):
    b1,g1,r1 = cv2.split(img)
    clahe = cv2.createCLAHE(clipLimit=cl, tileGridSize=(gsize,gsize))
    b2 = clahe.apply(b1)
    g2 = clahe.apply(g1)
    r2 = clahe.apply(r1)
    return cv2.merge((b2,g2,r2))

clipLimit が大きいのか、やや白っぽい画像になった。

全部混ぜて画像を作る

元画像を含め、4枚の画像の平均をとって、無難な画像に仕上げる。

4枚の画像の平均
# 全部混ぜる                                                                                                                                
ave_img = ct((np.float32(img) \
            + np.float32(eqh_rgb) \
            + np.float32(eqh_hsv) \
            + np.float32(clc_img))/4.)

コード

今回のコードの全文。上記で紹介した、各画像を出力する。

import cv2
import sys
import numpy as np

# ヒストグラム平坦化でコントラスト強調                                                                                                      
def eqh(img):
    # 各色で平坦化                                                                                                                          
    b1,g1,r1 = cv2.split(img)
    b2 = cv2.equalizeHist(b1)
    g2 = cv2.equalizeHist(g1)
    r2 = cv2.equalizeHist(r1)
    eqh_rgb = cv2.merge((b2,g2,r2))

    # HSVのvだけ編集                                                                                                                        
    h1,s1,v1 = cv2.split(cv2.cvtColor(img,cv2.COLOR_BGR2HSV))  # 色空間をBGRからHSVに変換                                                   
    v2 = cv2.equalizeHist(v1)
    eqh_hsv = cv2.cvtColor(cv2.merge((h1,s1,v2)), cv2.COLOR_HSV2BGR)

    return eqh_rgb, eqh_hsv

# 部分的にヒストグラム平坦化でコントラスト強調                                                                                              
def clc(img,cl,gsize):
    b1,g1,r1 = cv2.split(img)
    clahe = cv2.createCLAHE(clipLimit=cl, tileGridSize=(gsize,gsize))
    b2 = clahe.apply(b1)
    g2 = clahe.apply(g1)
    r2 = clahe.apply(r1)
    return cv2.merge((b2,g2,r2))

# 値を0-255にclipして、typeをuint8にする                                                                                                    
def ct(img):
    return np.clip(img,0,255).astype(np.uint8)

file_name = sys.argv[1]
img = cv2.imread(file_name)

# コントラスト強調画像を作成                                                                                                                
eqh_rgb, eqh_hsv = eqh(img)
clc_img = clc(img,2.,4)

# 全部混ぜる                                                                                                                                
ave_img = ct((np.float32(img) \
            + np.float32(eqh_rgb) \
            + np.float32(eqh_hsv) \
            + np.float32(clc_img))/4.)

# 保存する                                                                                                                                  
cv2.imwrite(file_name.replace(".",".out_eqh_rgb."),eqh_rgb)
cv2.imwrite(file_name.replace(".",".out_eqh_hsv."),eqh_hsv)
cv2.imwrite(file_name.replace(".",".out_clc."),clc_img)
cv2.imwrite(file_name.replace(".",".out_all."),ave_img)

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)