DeepLearningで暗い写真を明るくするやつやってみた

## 前置き

Googleが出したPixel3のカメラが話題ですね。
暗い場所でも圧倒的な明るさで写真を撮れる、みたいなやつです。

例えば別所さんの記事とか。1000ブクマ到達しそうな勢いです。
[Googleの新スマートフォンPixel 3の「夜景モード」が問いかけるもの（あるいはAIとはなんなのかという実感について）](https://note.mu/takahirobessho/n/n6dd8735ad968)

この記事を見て、とりあえず今年5月に出た[この論文](http://cchen156.web.engr.illinois.edu/paper/18CVPR_SID.pdf)を思い出しました。
めっちゃ暗い写真をDeepLearningで明るくするやつ。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/268599/2cb044c1-289f-6acf-3446-452c89c8681d.png)

普通にすごい。
今回、これをiPhoneのカメラで撮った写真で試してみました。

## 実装について

論文中では実装についてはざっくりと触れられている程度ですが、[github](https://github.com/cchen156/Learning-to-See-in-the-Dark)上にコード一式が置かれています。

論文を読む前はGANに暗い画像ぶちこんでるのかなと思っていましたが、コード見てもらえれば分かる通り実際はU-Netでした。
想像通り、暗いRAW画像 -> 明るい画像 という変換を行っています。

特徴としては入力がRAWなので、通常の画像のような3channelではなく、4channel(RGBG)になってます。
また、明るさを調節するためのレートを事前に指定します。
RAW画像のデータをネットワークに入力する前に画素値にレートを掛けています。

## iPhoneで試してみた
というわけで、実際に動いてるところが見たいなと思ったので動かしてみました。
iPhoneで撮った写真を明るくしてみます。

動かした環境
* Python 3.6.7
* tensorflow 1.1.0

二通りの学習モデルが用意されています。
SonyのベイヤーセンサーとFujifilmのX-transセンサー。
何も考えず脳死で手持ちのRAW画像をぶち込んでみました。ちなみにPanasonicのミラーレスとiPhoneのRAW持ってます。どちらもベイヤーセンサーのはずなのでSonyのモデルで試します。

```python
# test_Sony.py上で適当に
raw = rawpy.imread(filename)
input_full = np.expand_dims(pack_raw(raw), axis=0) * ratio

output = sess.run(out_image, feed_dict={in_image: input_full})
output = np.minimum(np.maximum(output, 0), 1)
output = output[0, :, :, :]
plt.imshow(output)
plt.show()
```

 <img alt="スクリーンショット 2018-11-22 23.58.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/268599/564f373d-79f8-3571-d22d-505a9bfd5641.png" width=50%><img alt="スクリーンショット 2018-11-22 23.50.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/268599/17ad0ad7-4cd8-2606-04bc-bcd61c6f8ec6.png" width=50%>

色がおかしいのですが。。。
RGBGの順番が違うのかなと思ってpixel部分の並びを総当たりしてみる。
総当たりするときPythonだと`itertools.permutations([0,1,2,3])`で一行で書けるので便利ですね。

```python
input_full = np.expand_dims(pack_raw(raw)[:,:,perm], axis=0) * ratio
```

二行目の部分を上のように書き換えて、pixel部分の順番(perm部分)を`(2, 1, 0, 3)`もしくは`(2, 3, 0, 1)`にするとiPhoneのRAWは自然な色合いになりました。
PanasonicのRAWはどの順番でも色合いが変でした。自社センサー積んでるカメラなのでSonyセンサーのモデルと相性が悪いんでしょうね。

## 比較
RAWをそのままjpeg化したものと、ネットワークに入力したものの比較をしてみます。
ネットワーク自体はSonyの(それもフルサイズの)ミラーレスで撮った画像で学習が行われているので、iPhoneでうまくいくかというと微妙なところです。
実用を目指すなら、iPhoneで撮った写真のデータセット集めてFine-tuningする必要がありそう。

今回はiPhoneで撮ったRAW画像を、直接Sonyで学習したモデルに突っ込んだ結果です。
RAWでの撮影が必要なため、カメラアプリは[ProCam6](https://itunes.apple.com/jp/app/procam-6/id730712409?mt=8)を使いました。昔無料の時にダウンロードしたやつ。


元画像, Macのプレビューで無理やり明るくした画像, ニューラルネットに突っ込んだ画像の順番,で並べてます。


<img alt="212_r.png" src="https://qiita-image-store.s3.amazonaws.com/0/268599/a26b409e-2bdf-dfcd-78b6-67211e96949d.png" width=30%><img alt="212_m.png" src="https://qiita-image-store.s3.amazonaws.com/0/268599/bd1defc0-511b-e8bf-27dc-ecbbf3951f84.png" width=30%><img alt="212_n.png" src="https://qiita-image-store.s3.amazonaws.com/0/268599/54a58e1d-5c21-3cd8-3983-ee61b8d70b04.png" width=30.32%>

<img alt="049_r.png" src="https://qiita-image-store.s3.amazonaws.com/0/268599/b47de294-8025-ca27-1c5d-a8099cc02499.png" width=30.1%><img alt="049_m.png" src="https://qiita-image-store.s3.amazonaws.com/0/268599/246f1c0f-6b32-ac4c-dff4-cbc6a65d0d80.png" width=30.2%><img alt="049_n.png" src="https://qiita-image-store.s3.amazonaws.com/0/268599/2b723153-6227-1e65-c33f-f04261ee484b.png" width=30%>

<img alt="422_r.png" src="https://qiita-image-store.s3.amazonaws.com/0/268599/653de304-807a-06cf-2b8c-479075f25556.png" width=30%><img alt="0.03.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/268599/a635c22c-3945-79b5-f895-ef71cec78864.png" width=30%><img alt="422_n.png" src="https://qiita-image-store.s3.amazonaws.com/0/268599/2efa7f52-8b8b-e2d8-6dfd-6bbc84d30358.png" width=29.9%>


なるほど？
確かに効果があるみたいですね。かなりノイズが削減できています。
色乗りはよくないですが、ここら辺はちゃんとiPhone用のモデルを作れば解決できそう。

逆に元が明るい写真の場合は崩れてしまうことが多かったです。
元画像, ニューラルネットに突っ込んだ画像の並び。

<img alt="346_r.png" src="https://qiita-image-store.s3.amazonaws.com/0/268599/a0a2f543-8f60-5322-067b-1df2a99acd3d.png" width=40%><img alt="346_n.png" src="https://qiita-image-store.s3.amazonaws.com/0/268599/0d1edc3f-ebbc-e136-dca2-7361cda1e448.png" width=40%>

## ちなみに
Googleの[AIブログの記事](https://ai.googleblog.com/2018/11/night-sight-seeing-in-dark-on-pixel.html
)を読んだのですが、「夜景モード」は複数枚の写真を自動で重ね合わせることで実現されているようです。

>Thus, depending on which Pixel phone you have, camera selection, handshake, scene motion and scene brightness, Night Sight captures 15 frames of 1/15 second (or less) each, or 6 frames of 1 second each, or anything in between.

動体か風景かで写真を撮る間隔や枚数を変えるみたいです。へー。

これ読んでると「夜景モード」ってもしかしてDeepLearning関係ない気がしてきてしまったわけなんですが、となるとこのQiitaの記事を書いた意味は。。。