画像処理はじめました。

AI/AR/VRという近未来的な言葉に惹かれ、その技術分野に参戦するために立ち上げたブログです。日々の格闘結果を記録に残してゆこうと思います。

2-2 「ガンマ補正」

モチベーション

画像全体を明るくしたり暗くしたりできます。
バイアス値を加えて作成する直線的な画像変換よりも、より自然な出力が得られます。
PCで表示される明るさはディスプレイによってさまざまであり、見え方の差を補正するためにγ補正が用いられることがあります。

やり方

PILライブラリを使用し画像を読み込みます。
各画素値にガンマ変換を適用し計算結果を新たな画素値とします。

プログラム

#!/usr/bin/python
# -*- coding: utf-8 -*-

# ガンマ補正

from PIL import Image 
import numpy as np
from matplotlib import pylab as plt

# 画像の読み込み
im = np.array(Image.open('input.bmp'))
print(im.shape, im.dtype)

# 画像の表示
plt.title("before")
plt.imshow(im)
plt.show()


# 画像サイズを取得
height= im.shape[0]
width = im.shape[1]

# γ値
g = 2.2

##全画素を走査し、γ補正を適用する
for x in range(height):
    for y in range(width):
        im[x,y] = 255.0 * pow( im[x,y]/255.0, 1.0/g )

# 画像の表示
plt.title("after")
plt.imshow(im)
plt.show()

#保存
Image.fromarray(im).save('output.bmp')

実行結果

f:id:genetaka1810:20200127133349p:plain
ガンマ補正の実行結果

解説

折れ線型トーンカーブでは、トーンカーブの切り替わり前後で画素値が急激に変換されてしまいますが、ガンマ補正は曲線のトーンカーブで 次のように表現されます。

f:id:genetaka1810:20200127130942p:plain
ガンマ変換式

ガンマ値を変化させたときのグラフを以下に示します。

f:id:genetaka1810:20200127132553p:plain
ガンマ変換のトーンカーブ
γ > 1の時は上に凸、γ < 1 のときは下に凸のトーンカーブとなります。

ガンマ補正のトーンカーブ

#!/usr/bin/python
# -*- coding: utf-8 -*-

# ガンマ補正のトーンカーブ
#
# 参考
# ガンマ関数
#  ディジタル画像処理(CG-ARTS協会)P85
# 折れ線型トーンカーブでは、トーンカーブの切り替わり前後で画素値が急激に変換されてしまう
#  ガンマ補正は曲線のトーンカーブで y = 255 * (x/255)^(1/γ) と表現される。
#  γ > 1の時は上に凸、γ < 1 のときは下に凸のトーンカーブとなる。

# numpy.empty関数
#   https://deepage.net/features/numpy-empty.html
#
#   np.empty 値の初期化を行うことなくNumPy配列を生成する
#   第一引数に配列数、第二引数にはデータ型を指定
#   実行速度が早く値を初期化する必要がないときはnp.emptyを使う

# numpy.clip関数
#   https://note.nkmk.me/python-numpy-clip/
#
#   np.clip 配列要素の値を任意の最小値・最大値にクリッピングする
#   第一引数にNumpy配列、第二引数に最小値、第三引数には最大値を指定する。


import numpy as np
import matplotlib.pyplot as plt

p = np.empty(256, np.uint8)  
 
for gamma in np.array([0.33, 0.5, 0.66, 1.0, 1.5, 2.0, 3.0]):

    for i in range(256):
        p[i] = np.clip(pow(i / 255.0, 1 / gamma) * 255.0, 0, 255)
    if (gamma >= 1) :
        plt.plot(p, label=str(gamma))
    else:
        plt.plot(p, label=str(gamma), linestyle="dashed")

plt.legend()
plt.xlabel("INPUT")
plt.ylabel("OUTPUT")
plt.show()