今回はOpenCVでガンマ補正を実装する方法についてです。
ガンマ補正はOpenCVに関数が実装されていないため自前で実装する必要があります。
1. ガンマ補正とは
画像データを入力Input, ディスプレイに表示される明るさをOutputとした場合、 入力と出力の関係は
\[Output = Input^{γ}\]
で表されます(入力は0.0~1.0)。

γ値が1.0であれば入力と出力が一致するので比例関係となり補正をかける必要はありません。
しかし、ディスプレイのγ値は2.2が一般的とされており比例関係が成立しないため、以下のような計算を行い入力と出力が比例関係になるように補正します。
\[Output = Input^{\frac{1}{γ}}\]

上記の補正をガンマ補正と呼びます。
2. LUT(ルックアップテーブル)
画像にガンマ補正を適応する場合は各画素に対して上記の式を適用することになるのですが、その場合は処理時間が膨大になってしまいます。
そこで、ルックアップテーブル(LUT)に画素ごとの計算結果をあらかじめ格納しておきます。
例えば8bitグレースケール画像の場合は0~255の値に対して計算した結果をあらかじめLUTに格納します。
そして実際に変換する際はLUTに格納された値を参照するようにします。
ガンマ補正の式は入力が0.0~1.0の範囲なので画像に適応する場合は以下の式を使用します。
\[Output’ = 255×(\frac{Input}{255})^{\frac{1}{γ}}\]
以下の表はγ値を2.2に設定したLUTの例です。

3. OpenCVによる実装(C++)
C++版OpenCVでガンマ補正を実装してみます。
OpenCVにはガンマ補正の関数が実装されていないため、「cv::LUT」を使用して変換します。
#include<iostream>
#include<opencv2/opencv.hpp>
int main(void){
cv::Mat mat_img = cv::imread("shimons_labo.png");
double dGamma = 2.2;
uchar uLut[256];
for (int i = 0; i < 256; i++) {
// LUT計算
uLut[i] = (uchar)(pow((double)i / 255.0, 1.0/dGamma) * 255.0);
}
cv::Mat lut = cv::Mat(1, 256, CV_8U, uLut);
cv::Mat mat_result;
cv::LUT(mat_img, lut, mat_result);
cv::imshow("result", mat_result);
cv::waitKey();
return 0;
}
4. OpenCVによる実装(Python)
Python版OpenCVでガンマ補正を実装してみます。
Python版では「cv2.LUT」を使用します。
import cv2
import numpy as np
mat_img = cv2.imread("shimons_labo.png")
gamma = 0.2
lut = []
for i in range(256):
lut.append(pow(float(i)/255.0, 1.0/gamma)*255.0)
nlut = np.empty([256,1], dtype='uint8')
nlut[:,0] = np.array(lut)
mat_result = cv2.LUT(mat_img, nlut)
cv2.imshow("result", mat_result)
cv2.waitKey()
5. 実行結果



γ=1.0
γ=0.5
γ=2.2
γ値を変更することで画像の明るさを調整することもできます。
今回は以上です。
6. 参考サイト
・ガンマ補正
https://fujiwaratko.sakura.ne.jp/infosci/gamma.html
・OpenCV 2.2 C++ リファレンス
http://opencv.jp/opencv-2svn/cpp/
・OpenCV 2.2 Python リファレンス
http://opencv.jp/opencv-2svn/py/



コメント