OpenCVによるコントラストと明るさの調整


#はじめに
GIMPなどに明るさ・コントラストを調整する画面があります。
こんな機能を明るさ・コントラストをOpenCVとPythonで実装してみたいと思います。
GIMPは、明るさ・コントラストを0～127段階で調整できますが、この調整項の段階に
ついては同様にはいたしません。

**GIMP操作風景**
![GIMP_SCREEN.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391380/398e18cd-4bcb-8bf3-3bcf-4590dcc49278.jpeg)



#処理方法
今回の入力画像としては、今年鉄道が運休するほど大雪が降った日の写真です。
朝なので暗いです。この暗い感じを何とかしたいと思います。

![snow400.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391380/85468507-70db-3cd6-a214-285189e148b5.jpeg)

まずはヒストグラムで現状確認します。
![q_first_hist_graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391380/ea760ec1-8fed-b977-358b-61b13e7a85d2.png)

処理としては、グラフの山を左右に広げるとコントラストが改善します。
また、山全体を左に寄せると暗くなり、右側に寄せると明るくなります。
この辺の操作を計算で行います。


##計算方法
alphaをコントラスト係数とし、betaを明るさ係数とします。

R ← R × apha ＋ beta
G ← G × apha ＋ beta
B ← B × apha ＋ beta

##OpenCVによる実装
convertScaleAbs()関数を使います。

関数
**dst = cv.convertScaleAbs(src[, dst[, alpha[, beta]]])**
&emsp;src - 入力イメージ
&emsp;alpha - scaleファクタ
&emsp;beta - スケーリングされた値に加算する値(デルタ)
&emsp;dst - 出力イメージ

このような式の計算を行います。

dst(I)=saturate_cast<uchar>(|src(I)∗alpha+beta|)

機能としては下記コードと等価です。

```python
for y in range(image.shape[0]):
    for x in range(image.shape[1]):
        for c in range(image.shape[2]):
            res_image[y,x,c] = np.clip(alpha*image[y,x,c] + beta, 0, 255)
```

詳細は下記リンクを参照してください。

[opencv.org - Operations on arrays](https://docs.opencv.org/4.5.1/d2/de8/group__core__array.html#ga3460e9c9f37b563ab9dd550c4d8c4e7d)


#プログラム

```python
import cv2
import numpy as np
import matplotlib.pyplot as plt

# ヒストグラム表示
def histgram(image, filename):
    histR = cv2.calcHist([image],[0,], None, [256,], [0, 255,] )
    histG = cv2.calcHist([image],[1,], None, [256,], [0, 255,] )
    histB = cv2.calcHist([image],[2,], None, [256,], [0, 255,] )

    plt.title("Histgram")
    plt.plot(histR,c='red', label='red')
    plt.plot(histG,c='green', label='green')
    plt.plot(histB,c='blue', label='blue')
    plt.grid()
    plt.show()

def main():
    image = cv2.imread('snow400.JPG', cv2.IMREAD_COLOR)
    if image is None:
        print('ファイルオープンエラー')
        exit(0)
    # 入力画像表示
    cv2.imshow('Original Image', image)
    cv2.waitKey()

    alpha = 1.3 # コントラスト項目
    beta = 30    # 明るさ項目

    # 明るさ・コントラスト操作
    res_image = cv2.convertScaleAbs(image,alpha = alpha,beta = beta)

    # 画像表示
    capt = 'New Image alpha=%.1f beta=%.1f' % (alpha,beta )
    cv2.imshow(capt, res_image)
    cv2.waitKey()

    # ヒストグラム表示
    histgram(res_image, capt + '.png')

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

入力画像ファイル名はsnow400.JPGとし、
パラメータ alpha = 1.3 , beta = 30  を仮で入力しています。


#明るさ・コントラスト処理結果
#処理条件 aplha=1.0 beta=80
![bconv_1.0_80.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391380/8834047e-cb14-0767-7009-51607fba8f05.jpeg)
明るさは改善していますが、全体的にコントラストが悪いです。

![q_Image alpha=1.0 beta=80.0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391380/7a27295c-267b-9222-c0f3-cfe3700450e4.png)
全体的にグラフの山が右に移動しているのが分かるかと面ます。


#処理条件 aplha=1.3 beta=40
![bconv_1.3_40.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391380/c196bd43-36d4-cdab-da14-cb43e2f09d54.jpeg)
明るさ、コントラストが改善しています。

![q_Image alpha=1.3 beta=40.0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391380/07e77967-2833-ce40-8126-9c79d74cabc5.png)


#処理条件 aplha=1.6 beta=80
![bconv_1.6_80.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391380/f6854cbb-e3f5-d748-680f-10a8ba3b4934.jpeg)
露光オーバーな感じになっています。

![q_Image alpha=1.6 beta=80.0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391380/dbf4675e-4d2f-8fcb-a5e3-1a54e6e801f1.png)
計算値が255からオーバーフローしているのが分かるかともいます。

#終わりに
明るさ・コントラストを自動で改善する方法もありますが、OpenCVによる
明るさ・コントラストの基本的操作について書かれた記事が見つけられなかったので
書かせていただきました。
このアルゴリズムは人の確認が必要だったりしますが、下手に自動にすると
再現性のない画像を量産することにもなるため、その目的などに応じて
適用してくのが良いかと思います。
ありがとうございました。


#実行環境
Windows10 Anaconda 3(Miniforge)
Python 3.9.2 packaged by conda-forge
OpenCV 4.5.1
numpy 1.20.1


#参考
[Emotion Explorer - OpenCV 画像のコントラストと明るさの調整](https://emotionexplorer.blog.fc2.com/blog-entry-327.html)