iMind Developers Blog

iMind開発者ブログ

Pillowのequalize/autocontrastとOpenCVのequalizeHistの比較

概要

ヒストグラム平坦化を行う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')

f:id:mwsoft:20200329215030p:plain

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)

f:id:mwsoft:20200329215242p:plain

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は当然ながらコントラストが少し強めになっている。

f:id:mwsoft:20200329215404p:plain

ヒストグラムで比較してみる。

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)と比べてヒストグラムが平坦化されている。まったく同一の結果にはならず若干の差異は出ている。

f:id:mwsoft:20200329215449p:plain

autocontrast(黄色の線)も加えるとこんな感じ。

f:id:mwsoft:20200405112330p:plain

実際のコードも追っておきたいところだけど時間がないので本日はここまで。

改定履歴

Author: Masato Watanabe, Date: 2020-04-05, 記事投稿