概要
ヒストグラム平坦化を行うPillowのequalizeとOpenCVのequalizeHistの結果を比較する。
ついでにPillowのautocontrastの結果も並べてみる。
バージョン情報
- opencv-python==4.1.0.25
- Pillow==6.0.0
利用する画像
下記のようなとてもかわいい犬の写真を4枚用意して実行する。
from PIL import Image from matplotlib import pylab as plt %matplotlib inline images = [Image.open('images/dog{}.jpg'.format(i)) for i in range(1, 5)] f, ax_list = plt.subplots(2, 2, figsize=(8, 8)) for i, image in enumerate(images): ax = ax_list[i % 2, int(i / 2)] ax.imshow(image) ax.axis('off')
cv2.equalizeHist
OpenCVのequalizeHistについて。
下記は公式のfunctionの説明
The function equalizes the histogram of the input image (中略)
(この関数は入力された画像のヒストグラム平坦化を行う)
The algorithm normalizes the brightness and increases the contrast of the image.
(このアルゴリズムは画像のbrightnessを正規化して、コントラスを増加する)
呼び出す場合の例。
import cv2 from PIL import Image from matplotlib import pylab as plt %matplotlib inline image = Image.open('images/dog1.jpg') image_norm = np.array(image).copy() for j in range(3): image_norm[:, :, j] = cv2.equalizeHist(image_copy[:, :, j]) plt.imshow(image_norm)
PIL.ImageOps.equalize
Pillowのequalizeについて。
公式の説明。
Equalize the image histogram. This function applies a non-linear mapping to the input image, in order to create a uniform distribution of grayscale values in the output image.
(画像のヒストグラム平坦化。この関数は均一な分布のグレースケール値を出力する為に、入力画像に対して非線形のマッピングを適用する)
実行コード。
from PIL import ImageOps image_norm = ImageOps.equalize(image) plt.imshow(image_norm)
PIL.ImageOps.autocontrast
Pillowのautocontrast。
Maximize (normalize) image contrast. This function calculates a histogram of the input image, removes cutoff percent of the lightest and darkest pixels from the histogram, and remaps the image so that the darkest pixel becomes black (0), and the lightest becomes white (255).
(画像のコントラストを最大化(平坦化)する。この関数は入力画像のヒストグラムを計算し、cutoffで指定されたパーセント以上の明るさ/暗さのピクセルを除去し、最も暗いピクセルが黒(0)に、最も明るいピクセルが白(255)になるようマッピングし直す)
引数にcutoffを指定して実行する。
image_norm = ImageOps.autocontrast(image, cutoff=cutoff)
下記は2.5刻みでcutoffを上昇させた場合の結果。
f, ax_list = plt.subplots(3, 5, figsize=(15, 8)) for i in range(15): cutoff = i * 2.5 image_norm = ImageOps.autocontrast(image, cutoff=cutoff) ax = ax_list[int(i / 5)][i % 5] ax.axis('off') ax.set_title('cutoff={:.02f}'.format(cutoff)) ax.imshow(image_norm)
PIL.ImageOps.equalizeとcv2.equalizeHistの比較
紹介した関数を実行した画像を並べて比較してみる。autocontrastはcutoff=10を指定している。
images = [Image.open('images/dog{}.jpg'.format(i)) for i in range(1, 5)] f, ax_list = plt.subplots(4, 2, figsize=(8, 16)) for i, image in enumerate(images): # pillow pil_image = ImageOps.equalize(image) ax = ax_list[i][0] ax.set_title('pillow') ax.imshow(pil_image) ax.axis('off') # opencv cv2_image = np.array(image).copy() for j in range(3): cv2_image[:, :, j] = cv2.equalizeHist(cv2_image[:, :, j]) ax = ax_list[i][1] ax.set_title('opencv') ax.imshow(pil_image) ax.axis('off') # autocontrast ac_image = ImageOps.autocontrast(image, cutoff=10) ax = ax_list[i][2] ax.set_title('autocontrast') ax.imshow(ac_image) ax.axis('off')
ヒストグラム平坦化の2つの結果はほぼ変わらず。autocontrastは当然ながらコントラストが少し強めになっている。
ヒストグラムで比較してみる。
images = [Image.open('images/dog{}.jpg'.format(i)) for i in range(1, 5)] f, ax_list = plt.subplots(4, 1, figsize=(8, 8)) for i, image in enumerate(images): np_image = np.array(image) ax = ax_list[i] # original hist, bins = np.histogram( np_image.flatten(), bins=50 ) ax.plot(hist, alpha=0.5, color='g', label='original') # pillow pil_image = ImageOps.equalize(image) hist, bins = np.histogram( np.array(pil_image).flatten(), bins=50 ) ax.plot(hist, alpha=0.5, color='r', label='pillow') # opencv cv2_image = np.array(image).copy() for j in range(3): cv2_image[:, :, j] = cv2.equalizeHist(cv2_image[:, :, j]) hist, bins = np.histogram( cv2_image.flatten(), bins=50 ) ax.plot(hist, alpha=0.5, color='b', label='opencv') if i == 0: ax.legend(bbox_to_anchor=(1.2, 1), loc='upper right')
双方とも元のイメージ(original)と比べてヒストグラムが平坦化されている。まったく同一の結果にはならず若干の差異は出ている。
autocontrast(黄色の線)も加えるとこんな感じ。
実際のコードも追っておきたいところだけど時間がないので本日はここまで。
改定履歴
Author: Masato Watanabe, Date: 2020-04-05, 記事投稿