Python3とopenCV3のガンマ補正でストライプ錯視を作る

#環境
  windows8.1
  python3.4.4
  opencv3.1.0
#概要
まずはストライプ錯視の現物をご覧ください。

![out03.jpg](https://qiita-image-store.s3.amazonaws.com/0/144906/61a3d69a-445a-ad2a-ba92-c73918c90220.jpeg)

※白黒のストライプしか見えない人はちょっと下がって、首を左右にぶんぶん振ってください。多分見えてきます


こんなりすが見えてきませんか？
(画像は「フリー写真素材ぱくたそ」さんより)
![out1.jpg](https://qiita-image-store.s3.amazonaws.com/0/144906/f8d97c7f-b6ac-e803-e7c6-ec14c55d5e94.jpeg)



イラストでもやってみます。
例のごとく「いらすとや」さんからお借りした、メキシコ人のイラストです。
![mexico.jpg](https://qiita-image-store.s3.amazonaws.com/0/144906/0a469dce-e817-7341-50be-08da7d2b655b.jpeg)

では、これをストライプ錯視にしてみます。
#手順
大きく分けて３つの段階を踏んでいます。

1. 画像をモノクロに変換する
2. ガンマ補正で明るくする
3. ストライプと合成する

#本体
```py3:stripe.py
import numpy as np
import cv2

"""
環境：python3.4.4 openCV
元の画像 : image_name
保存する画像: out_name
画像をストライブ錯視にして出力
(一見ただのストライブだが首を振りながら見ると浮かび上がってくる錯視)
"""

image_name = 'mexico.jpg'
out_name1 = 'out01.jpg'
out_name2 = 'out02.jpg'
out_name3 = 'out03.jpg'

#画像の読み込み
Img0 = cv2.imread(image_name,-1)

#モノクロに変換
Img0 = cv2.cvtColor(Img0, cv2.COLOR_RGB2GRAY)

#画像のサイズを取得
Height, Width = Img0.shape[:2]

#行列のサイズ
rows = Height
cols = Width

#真っ白な背景をつくる
whiteImg = np.zeros((rows, cols), np.uint8)
whiteImg.fill(255)
#元のImg0と合成
whiteImg += Img0
#途中表示
cv2.imshow("white back image", whiteImg)
k = cv2.waitKey(0)
if k == 27:
    cv2.destroyAllWindows()
elif k == ord('s'):
    cv2.imwrite(out_name1,whiteImg)


#明るさ調整(ガンマ補正)
#ガンマ値(通常よりかなり大きい)
gamma = 19.0

#変換用配列look_up_tableを作る
look_up_table = np.zeros((256, 1), np.uint8)

for i in range(256):
	look_up_table[i][0] = 255 * pow(float(i) / 255, 1.0 / gamma)

# LookUpTableで先ほどの画像を変換
newImg = cv2.LUT(whiteImg, look_up_table)

# 途中表示
cv2.imshow("higher brightness image", newImg)
k = cv2.waitKey(0)
if k == 27:
    cv2.destroyAllWindows()
elif k == ord('s'):
    cv2.imwrite(out_name2,newImg)


#ストライプ用配列を作る。
stripe = np.zeros((rows, cols), np.uint8)

#ストライプの幅はwidth/160(経験則)
if Width >= 640:
	w = Width/160
else:
	w = 4

w = int(w)

#0~640を4ずつ白で
for i in range(0, w):
	stripe[0:rows, i:cols:w*2] = 0

#0~64を4ずつ黒で
for i in range(0, w):
	stripe[0:rows, i:cols:w*2] = 1
#画像を行列として扱うときは論理積ではなく
#数の掛け算として扱われるので、0から1にする

#ストライプを重ね合わせる
newImg *= stripe

#出力する画像
cv2.imshow('final stripe image', newImg)

#何かキーを押すと終了
#sを押すと保存する
k = cv2.waitKey(0) & 0xFF
if k == 27:
    cv2.destroyAllWindows()
elif k == ord('s'):
    cv2.imwrite(out_name3,newImg)

#python stripe.pyで実行
```

#出力
![out01.jpg](https://qiita-image-store.s3.amazonaws.com/0/144906/b3d937ba-f5c3-bd76-a26c-c7b10ec94fb0.jpeg)

見えるでしょうか。
元気なメキシコ人です。


#詳細
pngなど透過部がある場合は、透過部は黒色になってしまいますので背景を白くする必要があります。今回は、全ての画素値に255を足すことで、明るさ0の部分を255(白)に、それ以外の部分は元の画素値から1引かれた値（例えば、画素値が1なら1+255=256 つまり0）にするという手法をとりました。


ガンマ補正の式は[こちら](https://www.blog.umentu.work/python-opencv3%E3%81%A7%E3%82%AC%E3%83%B3%E3%83%9E%E5%A4%89%E6%8F%9Bgamma-conversion-2/)などでご確認ください。光信号の強さと電気信号は比例しているわけではないので、一律に値を底上げするのではなく、このような補正を行っています。


また、画像処理に便利な行列計算として、以下の3つを紹介します。
・ 全ての要素が0の行列を生成する
　　　```Img = np.zeros((rows, cols), np.uint8)```
・ 行列をある値で埋める
　　　```Img.fill(255)```
・ 行列の(row1, col1)から(row2, col2)に、列方向w1間隔、行方向w2間隔で値を代入
　　　```Img[row1:row2:w1, col1:col2:w2] = 0```


#参考
[BlankTar](http://blanktar.jp/blog/2015/02/python-opencv-overlay.html)
[FROM UMENTU IMPORT STUPID](https://www.blog.umentu.work/python-opencv3%E3%81%A7%E3%82%AC%E3%83%B3%E3%83%9E%E5%A4%89%E6%8F%9Bgamma-conversion-2/)
[opencv v2.1 documentation 配列操作](http://opencv.jp/opencv-2.1/py/operations_on_arrays.html#cv-lut)
[フリー写真素材ぱくたそ](https://www.pakutaso.com/userpolicy.html)
[いらすとや](http://www.irasutoya.com/)