OpenCV – 画像の明るさ、コントラストを補正する方法

目次

概要

OpenCV で画像の明るさやコントラストを変更する方法について紹介します。

積和演算で明るさ、コントラストを変更する

画像の位置 $(x, y)$ の画素値を $\text{src}(x, y)$ としたとき、次の式で明るさ、及びコントラストを変更できます。

$$ \text{dst}(x, y) = \alpha \text{src}(x, y) + \beta $$

$\alpha, \beta$ は定数で、$\alpha$ はゲイン (gain) またはコントラスト (contrast)、$\beta$ はバイアス (bias) または明るさ (brightness) といいます。

各パラメータの効果

明るさを $\beta=0.0$ で固定し、コントラスト $\alpha$ を変化させた結果を確認します。 $\alpha$ の値が大きいほど、画像の明暗の差が大きくなります。

コントラストを $\alpha=1.0$ で固定し、明るさ $\beta$ のパラメータを変化させた結果を確認します。 $\beta$ の値が大きいほど、画像全体が明るくなります。

サンプルコード

cv2.LUT() で $x \rightarrow \alpha x + \beta$ の対応表を作成し、階調変換を行います。

sample.jpg

In [1]:
import cv2
import numpy as np
from IPython.display import Image, display


def imshow(img):
    """ndarray 配列をインラインで Notebook 上に表示する。"""
    ret, encoded = cv2.imencode(".jpg", img)
    display(Image(encoded))
In [2]:
def adjust(img, alpha=1, beta=0):
    # テーブルを作成する。
    table = alpha * np.arange(256) + beta
    # [0, 255] でクリップし、uint8 型にする。
    table = np.clip(table, 0, 255).astype(np.uint8)

    return cv2.LUT(img, table)


src = cv2.imread("sample.jpg")

# コントラスト、明るさを変更する。
dst = adjust(src, alpha=2.0, beta=30.0)
imshow(dst)

ipywidgets を使用したパラメータ調整

Jupyter Notebook で利用できる ipywidgets を使ってパラメータを調整するためのコードを記載します。

ipywidgets

In [3]:
import cv2
from IPython.display import Image, display
from ipywidgets import widgets


def imshow(img):
    """画像を Notebook 上に表示する。"""
    encoded = cv2.imencode(".png", img)[1]
    display(Image(encoded, width=400))


def adjust(img, alpha=1, beta=0):
    # テーブルを作成する。
    table = alpha * np.arange(256) + beta
    # [0, 255] でクリップし、uint8 型にする。
    table = np.clip(table, 0, 255).astype(np.uint8)

    return cv2.LUT(img, table)


def process(img, alpha, beta):
    """明るさ、コントラストを調整し、結果を表示する。"""
    dst = adjust(img, alpha, beta)
    imshow(dst)


param_widgets = {}

# パラメータ α を設定するスライダー
param_widgets["alpha"] = widgets.FloatSlider(
    min=-100.0, max=100.0, step=0.1, value=1.0, description="コントラスト: "
)

# パラメータ β を設定するスライダー
param_widgets["beta"] = widgets.FloatSlider(
    min=-100.0, max=100.0, step=10.0, value=0.0, description="明るさ: "
)

for x in param_widgets.values():
    x.layout.width = "400px"

# 画像を読み込む。
img = cv2.imread("sample.jpg")

# ウィジェットを表示する。
widgets.interactive(process, img=widgets.fixed(img), **param_widgets)

ガンマ補正

画像の位置 $(x, y)$ の画素値を $src(x, y)$ としたとき、次の式で変換する処理をガンマ補正 (gamma correction) といいます。

$$ y = \left(\frac{x}{255}\right)^\gamma \times 255 $$

ただし、$\gamma$ は定数です。$\gamma = 1$ のとき、$y = x$ となり、入力と出力が同じになります。

パラメータ $\gamma$ を変化させた結果を確認します。

サンプルコード

画素値の変換には、cv2.LUT() を使います。ガンマ補正の計算を行ったあと、値を画素値として有効な値にするため、$[0, 255]$ の範囲でクリップを行い、型を numpy.uint8 にキャストします。

In [4]:
import cv2
import numpy as np


def gamma_correction(img, gamma):
    # テーブルを作成する。
    table = (np.arange(256) / 255) ** gamma * 255
    # [0, 255] でクリップし、uint8 型にする。
    table = np.clip(table, 0, 255).astype(np.uint8)

    return cv2.LUT(img, table)


# 画像を読み込む。
src = cv2.imread("sample.jpg")

# コントラスト、明るさを変更する。
dst = gamma_correction(src, gamma=2.0)
imshow(dst)

ipywidgets を使用したパラメータ調整

Jupyter Notebook で利用できる ipywidgets を使ってパラメータを調整するためのコードを記載します。

ipywidgets

In [5]:
import cv2
from IPython.display import Image, display
from ipywidgets import widgets


def imshow(img):
    """画像を Notebook 上に表示する。"""
    encoded = cv2.imencode(".png", img)[1]
    display(Image(encoded, width=400))


def gamma_correction(img, gamma):
    # テーブルを作成する。
    table = (np.arange(256) / 255) ** gamma * 255
    # [0, 255] でクリップし、uint8 型にする。
    table = np.clip(table, 0, 255).astype(np.uint8)

    return cv2.LUT(img, table)


def process(img, gamma):
    """ガンマ補正を行い、結果を表示する。"""
    dst = gamma_correction(img, gamma)
    imshow(dst)


# パラメータ「ガンマ」を設定するスライダー
slider = widgets.FloatSlider(
    min=0.0, max=3.0, step=0.1, value=1.0, description="gamma: "
)
slider.layout.width = "400px"

# 画像を読み込む。
img = cv2.imread("sample.jpg")

# ウィジェットを表示する。
widgets.interactive(process, img=widgets.fixed(img), gamma=slider)

コメント

コメント一覧 (0件)

  • 各パラメータの効果のところ、
    明るさを 1.0 で固定、コントラストを 0.0 で固定、はそれぞれ
    明るさを 0.0 で固定、コントラストを 1.0 で固定、でしょうか?

    • コメントありがとうございます。
      ご指摘いただいた通り、説明が逆になっていましたので修正しました。

コメントする

目次