「印刷物撮影時に生じた影と映り込みの除去」のweb実装概要

印刷物撮影時の影と映り込みの除去をCNN（畳み込みニューラルネットワーク）で学習し、WEBに実装しました。

[印刷物の影・映り込み除去](https://printsharefremoval2020.pythonanywhere.com/)

さらっと概要だけ紹介したいと思います。

#なぜ作ったか
ある時、預金通帳のコピーが必要になりました。

預金通帳は実家置いてきていたので、母親に写真を撮って送ってもらいました。
![1581086282241.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579498/3e249ec5-434f-8687-ac83-ce4d9f279ad6.jpeg)
ああ、影と映り込みが…
この場合は特に映り込みで名前が見にくい…（モザイクで皆さんにはわからないけど）


あと、
Twitterとかでも、紙に描いたイラストに影が生じちゃってる投稿、見たことありませんか。
![P_20200208_010350.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579498/0b8e295f-6317-88ca-6e61-f25539b39a78.jpeg)
（大好きなごきげんパンダを描きました）

自分は写真が趣味なので、光源の位置を考えて撮ろうと思いますが、
そうじゃない人は多いのでは、と思いました。


印刷物の撮影時に生じた影と映り込み除去したいな〜

研究した。

せっかくの成果物なのに、HDDに封印するのもったいない…

…webに実装しよう！

#除去手法の概要
こんな感じのCNN構造を提案しました。
除去復元ネットワークと言います。

![img_network.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579498/2d16e0c2-eaed-1f64-2fbf-91a1a1207eff.jpeg)

除去ネットワークは、入力画像から、影または映り込みを除去します。
復元ネットワークは、除去ネットワークの出力画像から、影または映り込みを復元します。

そして、GANのように除去ネットワークは復元ネットワークに復元されないように敵対して学習します。

今回は除去ネットワークと復元ネットワークをそれぞれU-Netで構築しました。

この除去復元ネットワークには、強力な除去効果がありましたが、出力画像がぼやけると言う問題点を抱えていたので、通常のGANのようにディスクリミネータを追加しときました。

これで強力な除去はそのままに、少しはぼやけが改善しました。

また、領域情報の考慮（印刷物のマスク画像も入力すること）で除去精度を向上させました。

除去復元ネット+GANが本手法です。
↓
![18_00_result_remo_restore_shadow_cropped_page-0001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579498/68cc4d5f-c66c-80c9-166a-cea3d5f586b9.jpeg)
![19_00_result_remo_restore_reflection_cropped_page-0001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579498/4ec49719-8ec6-aede-bf5d-360cff1c5921.jpeg)


#web実装の概要
みんなが使えるようにwebで動かしたい！サーバが必要！


CNNはTensorFlowで実装しました。pythonなので、python動く無料レンタルサーバ検索したら、[PythonAnywhere](https://www.pythonanywhere.com)というサイトを見つけました。

TensorFlowも標準で使えて良さそう。


[こちらのサイト](https://blog.codecamp.jp/programming-free-server-1)で使い方がとても分かりやすく紹介されています。
このサイトを参考にpythonのウェブフレームワークのFlaskで構築しました。

フロントとのやり取りはjinja2で行います。

##TensorFlow実装時の問題点
一方、PythonAnywhereにTensorFlowで構築したCNNのコードをアップしたはいいものの、問題がありました。
今までTensorFlowのバージョンは1.10.0を使っていたのですが、
PythonAnywhereの標準で入っているバージョンは2.0.0でした。

コードを変えるのはめんどうなので、
PythonAnywhereのコンソールからpipでダウングレードを試みました。

しかし、
無料版で与えられた容量512MBでは、インストール中にギリギリ容量が足らなくなり、
`Disk quota exceeded`と表示され、失敗に終わりました。
TensorFlowはインストール時にnumpy等の必要ライブラリも同時インストールするみたいなので、必要ライブラリを全部インストールしてから、最後にTensorFlowをインストールしてみましたが、容量不足。
Virtualenvで仮想環境を新しく作ってインストールしてもやっぱり容量不足。

無課金者には厳しいPythonAnywhere。

もう諦めて、2.0.0仕様にコードを書き換える事にしました。
幸い、だいたいは

「tf.xxx」
↓
「tf.compat.v1.xxx」


と書き換えるだけで動きました。

##ページ遷移
ページ遷移は、
![遷移画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579498/446698cf-f296-eee3-c0a0-33cf8699995e.png)

という流れで作りました。

「マスク画像作成画面」では、
・canvasで画像の描画とクリック位置を取得
　　　　　　　　　↓
・除去開始ボタンでクリック位置の配列をpythonに渡す
　　　　　　　　　↓
・配列からopencvでマスク画像の作成
　　　　　　　　　↓
・入力画像とマスク画像を(サイズは最大800pixにして)CNNへ入力

を行っています。
CNNの実行が終了次第、「除去の結果画面」に遷移します。

「除去の結果画面」では、
さらに影or映り込みを除去したいという場合の為に、
画面上部の除去ボタンから、さらに除去出来ます。

（1度で除去できなくても、何度かやると除去できることがあります。）


#実装した後の感想（言い訳）

除去開始ボタンを押してから、表示までは10～20[s]くらい。
CPUで動いてるから遅いのはしょうがない。

学習時は224×224pixの小さい画像サイズで学習していたためか、
大きなサイズの画像を入力すると、不自然なモヤがでてきたり、除去精度が悪くなったりした。
もっといいGPUがあれば、大きな画像サイズで学習し直したい。

このweb実装を見て、CNN応用の一例としてこんなのがあるんだ、と知ってもらえたらいいです。

除去結果が気に入らなければ[googleのPhotoScan](https://www.google.com/intl/ja/photos/scan/)という素晴らしい、スマートフォンアプリがあるのでそっちを使ってください。