【画像処理】静止画・カメラ動画の輝度ヒストグラム調整と明度自動調整をやってみる♬

画像認識の一つの事前処理として輝度を変更してみる。
この記事は、以下の二つの記事を参考にしています。
【参考】
・①[Python OpenCVの基礎　LUTで画像の暗部を持ち上げてみる](http://peaceandhilightandpython.hatenablog.com/entry/2016/02/05/004445)
・②[【OpenCV】【Python】ルックアップテーブルでガンマ補正](https://qiita.com/Kazuhito/items/c43e96ab16f400a35721)

やりたいことは、学習時の画像で暗いものがあるので、それらを輝度を変更して明るくすると精度が上がるだろうという期待に基づいています。
参考①を見ると単純にgamma値を変更して、輝度を上げると見やすくなっています。
そして、参考②ではそれをカメラ入力の動画に対して実施しています。
さらに、参考①に戻ると、輝度をヒストグラムで変更前後で比較できることが示されています。
###やったこと
・簡単に参考②の記事のカメラ入力を画像読込みにする
・リアルタイムで輝度ヒストグラムを比較する
・カメラ動画をリアルタイムで輝度ヒストグラム比較する
・適用的ヒストグラム平坦化を実施する 
・明度自動調整と輝度ヒストグラム調整を実施
###・簡単に参考②の記事のカメラ入力を画像読込みにする
コードは以下のとおり
※基本、参考①のまんまです
変更点は、ret, frame = video_input.read()をコメントアウトして、frame = cv2.imread('61.jpg', 1)に変更するだけです。必要ないので、video_input = cv2.VideoCapture(0)もコメントアウトします。
ここで、look_up_tableの式は、参考①では以下の式を適用しています。
外形は変わってますが効果は変更ありません。
※以下では`len(look_up_table)-1 = 255`とおいています。

```py
lookUpTable = np.zeros((256, 1), dtype = 'uint8')
for i in range(256):
    lookUpTable[i][0] = 255 * pow(float(i) / 255, 1.0 / gamma)
```


```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import pylab as plt

def nothing(x):
    pass
def main():
    #video_input = cv2.VideoCapture(0)
    size =(1280,960) #(640,480)
    # ガンマ値設定用のトラックバー用意(小数点を扱えないため、10倍の値で準備)
    cv2.namedWindow("gammma correction", cv2.WINDOW_NORMAL)
    cv2.createTrackbar("gamma(0.1)", "gammma correction", 1, 50, nothing)
    cv2.setTrackbarPos("gamma(0.1)", "gammma correction", 10)
    while(1):
        #ret, frame = video_input.read()
        frame = cv2.imread('61.jpg', 1) #k1 61
        frame1 = cv2.resize(frame, dsize=size, interpolation=cv2.INTER_CUBIC)
        # ガンマ値取得（0は強制的に0.1相当に引き戻し）
        gamma = cv2.getTrackbarPos("gamma(0.1)", "gammma correction") * 0.1
        if gamma == 0:
            gamma = 0.1
            cv2.setTrackbarPos("gamma(0.1)", "gammma correction", 1)
        # ガンマ補正用ルックアップテーブル
        look_up_table = np.zeros((256, 1), dtype = 'uint8')
        for i in range(len(look_up_table)):
            look_up_table[i][0] = (len(look_up_table)-1) * pow(float(i) / (len(look_up_table)-1), 1.0 / gamma)
        # ルックアップテーブルによるガンマ補正
        gamma_correction_image = cv2.LUT(frame1, look_up_table)
        # ウィンドウ表示
        #cv2.putText(gamma_correction_image, "gamma:" + str(gamma), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,0),2)
        cv2.imshow("gammma correction", gamma_correction_image)
        
        k = cv2.waitKey(30) & 0xff
        if k == 27:
            break
    video_input.release()
    cv2.destroyAllWindows()
if __name__ == '__main__':
    main()
```
###・リアルタイムで輝度ヒストグラムを比較する
以下の関数を導入して輝度をプロットする。
この関数を以下のとおり追加する。

```py
def something(gamma_correction_image, frame):
    imgOrg = frame  #cv2.imread('61.jpg', 1)
    imgLut = gamma_correction_image  #cv2.imread('LUT.jpg', 1)

    #BGRをYCrCbに変換します
    orgYCrCb = cv2.cvtColor(imgOrg, cv2.COLOR_BGR2YCR_CB)
    lutYCrCb = cv2.cvtColor(imgLut, cv2.COLOR_BGR2YCR_CB)

    #輝度のヒストグラムを作成
    histOrgY = cv2.calcHist([orgYCrCb], [0], None, [256], [0, 256]) #0:Y 1:Cr 2:Cb
    histLutY = cv2.calcHist([lutYCrCb], [0], None, [256], [0, 256])

    #ヒストグラムの表示
    plt.plot(histOrgY)
    plt.plot(histLutY)
    plt.xlim([0, 256])
    plt.ylim([0,max(histOrgY)])  #15000])
    plt.pause(1)
def main():
    ...
    while(1):
        ...
        cv2.imshow("gammma correction", gamma_correction_image)
        something(gamma_correction_image,frame1)   #ここ追加
        k = cv2.waitKey(30) & 0xff
        if k == 27:
            break
```
###・カメラ動画をリアルタイムで輝度ヒストグラム比較する
ここまでくるとカメラ動画に変更するには、先ほどコメントアウトしたvideo_input = cv2.VideoCapture(0)とret, frame = video_input.read()を元に戻してやればよい（コード省略）
###・自動的に輝度調整して表示する
実は、ここまで来て、さて何を基準にして輝度調整すればいいのという疑問にぶつかる。
ということで、ググってみました。輝度・明るさ自動調整
・④[ヒストグラム その2: ヒストグラム平坦化@OpenCV](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_histograms/py_histogram_equalization/py_histogram_equalization.html)
・⑤[How to apply CLAHE on RGB color images](https://stackoverflow.com/questions/25008458/how-to-apply-clahe-on-rgb-color-images)
・⑥[明るさを自動調整する＠GIMP入門](https://www.gimp.jp.net/knowledge_colors_autoleveladjust.html)
####Gray画像の輝度自動調整
参考④によれば以下のコードで輝度自動調整できる。実際やってみると、白黒で読み込んだ画像は綺麗に明るくなる。
実際、参考のページのとおり美しいグレー画像が得られる。

```py
import numpy as np
import cv2

img = cv2.imread('s1.jpg',0)
# create a CLAHE object (Arguments are optional).
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
cv2.imwrite('clahe_2.jpg',cl1)
```
実は、参考⑤は市販品のツールのようだが、これによればどうやら明るさ自動調整ができるらしい。
ということで、そちら掲載の画像を利用して比較していきたいので、グレー化して輝度調整してみる。
元画像
![s1.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/72ee0bc8-1dbb-978a-2845-bbe73b4df8cb.jpeg)
グレー画像；輝度自動調整済
![s1_clahe_2_gray.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/db6eb10e-e965-8e0e-6995-bbbed8ee6519.jpeg)
###カラー画像の輝度自動調整
一応、明るくなっているが、残念ながらグレー画像
ということで、カラーができないものか探してみると参考⑤が見つかりました。
コードは以下のとおりです。

```py
import numpy as np
import cv2
import pylab as plt

size=(640,480)
#cv2.namedWindow("gammma correction", cv2.WINDOW_NORMAL)
while(1):
    gridsize=8
    bgr = cv2.imread('s1.jpg',1) #カラー画像読込
    lab = cv2.cvtColor(bgr, cv2.COLOR_BGR2LAB) #GBRからLABに変換
    lab_planes = cv2.split(lab) #LABに分離
    clahe = cv2.createCLAHE(clipLimit=2.0,tileGridSize=(gridsize,gridsize)) #L(明度)に対してGray画像と同様な抽出・処理を実施
    lab_planes[0] = clahe.apply(lab_planes[0]) #L(明度)に対して明るくする
    lab = cv2.merge(lab_planes) #LABをマージ
    bgr = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR) #LABからBGRに変換
    cv2.imshow("gammma correction", bgr) 
    k = cv2.waitKey(30) & 0xff
    if k == 27:
        break
    cv2.imwrite('clahe_2.jpg',bgr)
```
変換カラー画像は以下のとおり得られました。このカラー画像は一応満足なレベルだと思います。
しかし、上述の参考⑥で最終的に得られた画像はより明るく、カラーもより美しくでており、さらに工夫が必要なことを示しています。
![s1_clahe_2_color.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/54062d04-1dcb-ee68-ab97-5f91d48ceb1c.jpeg)
###・明度自動調整と輝度ヒストグラム調整を実施
おまけ掲載のプログラムで上記でやった輝度ヒストグラム調整も併せて実施することができます。
ここで、上記のプログラムにLABの概念を導入して作ることもできますが、ここは自動調整しつつ輝度ヒストグラムを見ながら輝度調整を実施するプログラムを載せておきます。
![hist_auto.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/801a7b5d-3bab-2445-22f2-c374839ca433.jpeg)
###まとめ
・静止画及びカメラ動画の輝度調整を実施した
・明るさ自動調整と輝度ヒストグラム調整を実施できるようになった

・カラーの自動調整もできそうなのでやってみたいと思う
・Cifar10やCifar100の入力画像を事前処理することにより精度が変わるかどうか試そうと思う
###おまけ
```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import cv2
import numpy as np
import pylab as plt

def something(gamma_correction_image, frame):
    imgOrg = frame  #cv2.imread('61.jpg', 1)
    imgLut = gamma_correction_image  #cv2.imread('LUT.jpg', 1)

    #BGRをYCrCbに変換します
    orgYCrCb = cv2.cvtColor(imgOrg, cv2.COLOR_BGR2YCR_CB)
    lutYCrCb = cv2.cvtColor(imgLut, cv2.COLOR_BGR2YCR_CB)

    #輝度のヒストグラムを作成
    histOrgY = cv2.calcHist([orgYCrCb], [0], None, [256], [0, 256]) #0:Y 1:Cr 2:Cb
    histLutY = cv2.calcHist([lutYCrCb], [0], None, [256], [0, 256])

    #ヒストグラムの表示
    plt.plot(histOrgY)
    plt.plot(histLutY)
    plt.xlim([0, 256])
    plt.ylim([0,max(histOrgY)])  #15000])
    plt.pause(1)

def treatise(frame,size):
    frame1 = cv2.resize(frame, dsize=size, interpolation=cv2.INTER_CUBIC)
    gridsize=8
    bgr = cv2.imread('s1.jpg',1) #k1.jpg
    lab = cv2.cvtColor(bgr, cv2.COLOR_BGR2LAB)
    lab_planes = cv2.split(lab)
    clahe = cv2.createCLAHE(clipLimit=2.0,tileGridSize=(gridsize,gridsize))
    lab_planes[0] = clahe.apply(lab_planes[0])
    lab = cv2.merge(lab_planes)
    bgr = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)
    return bgr 

def nothing(x):
    pass

def main():
    video_input = cv2.VideoCapture(0)
    size =(1280,960) #(640,480)
    # ガンマ値設定用のトラックバー用意(小数点を扱えないため、10倍の値で準備)
    cv2.namedWindow("gammma correction", cv2.WINDOW_NORMAL)
    cv2.createTrackbar("gamma(0.1)", "gammma correction", 1, 50, nothing)
    cv2.setTrackbarPos("gamma(0.1)", "gammma correction", 10)

    while(1):
        ret, frame = video_input.read()
        #frame = cv2.imread('61.jpg', 1) #k1 61
        frame1 = treatise(frame,size)
        # ガンマ値取得（0は強制的に0.1相当に引き戻し）
        gamma = cv2.getTrackbarPos("gamma(0.1)", "gammma correction") * 0.1
        if gamma == 0:
            gamma = 0.1
            cv2.setTrackbarPos("gamma(0.1)", "gammma correction", 1)

            
        # ガンマ補正用ルックアップテーブル
        look_up_table = np.zeros((256, 1), dtype = 'uint8')
        for i in range(len(look_up_table)):
            look_up_table[i][0] = (len(look_up_table)-1) * pow(float(i) / (len(look_up_table)-1), 1.0 / gamma)
        # ルックアップテーブルによるガンマ補正
        gamma_correction_image = cv2.LUT(frame1, look_up_table)
        # ウィンドウ表示
        #cv2.putText(gamma_correction_image, "gamma:" + str(gamma), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,0),2)
        cv2.imshow("gammma correction", gamma_correction_image)

        something(gamma_correction_image,frame1)
        k = cv2.waitKey(30) & 0xff
        if k == 27:
            break
    video_input.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()
```