Google画像検索を使用してモザイクアートを作成するWebアプリを開発していた話



![mosaica.png](https://qiita-image-store.s3.amazonaws.com/0/23755/9cec2912-32d7-0ca6-dd02-a87516d32005.png "mosaica.png")

# ソースコード
- https://github.com/CloudSpiralC2/MosaicA
- READMEにURL書いてますが、当然現在動いてません。


# モザイクアートとは
モザイクアートとは、多数の写真を素材として、モザイクのように組み合わせて作成した画像のことです。モザイク写真やフォトモザイクと呼ばれることもあります。近くで見ると写真が並んでいるように見えますが、離れて見ると一枚の絵が浮かび上がってきます。

元々、モザイクとは装飾技法の一種で、色ガラス、陶片、石、貝殻やその他の素材を、配置していくことで様々な色が組み合わされることにより、一枚の絵が創りあげられます。この装飾技法は古くから世界的に見られ、歴史的な建造物の室内装飾によく見られます。

最近では、モザイクアートにしたい画像と、素材となる画像を用意することでモザイクアートを作成できるソフトウェア(AndreaMosaicなど)が存在します。また、有償でモザイクアート作成を行っている企業も存在します。

# 開発経緯
大学院生のころ、enPitという組織がやってる教育プログラムに参加していました。その一環として、｢既存WebAPIを使用したWebアプリケーションをチームで遠隔開発を行う｣というものがありました。そこでアイデアとして挙がり、ちょっとネタ寄りで、かつ｢Google画像検索でモザイクアート｣ということが出来るかわからないし挑戦してみようということになり、開発を行いました。発表までの開発期間としては二ヶ月程度だったのですが、せっかくなのでもう少しちゃんと開発しよう、とプラス半年くらいゆるゆると開発を続けていました。

# 仕組み
![architecture.png](https://qiita-image-store.s3.amazonaws.com/0/23755/5343fea7-1877-58f2-c386-1021b90a76a2.png "architecture.png")

## 流れ
1. アップロードされた画像を分割します。縦横の分割数はユーザが指定することができます。
2. 分割された画像のパーツを使用してGoogle画像検索を行います。
このとき使用したいキーワードをユーザーは入力することができます。
3. 結果として返ってきたHTMLを解析して、類似画像を抽出します。
4. 元の画像でパーツがあった部分と検索結果の類似画像を置換します。
5. ②～④を全てのパーツに対して繰り返し行います。
6. モザイクアート完成！
7. 作成したモザイクアートは保存、Twitter投稿が可能です。

## 使用技術
### サーバサイド
- Java8
  - Jersey2.x系でWebAPI化
  - Maven
- tomcat7
- MongoDB
- Amazon EC2
- Squid

### クライアントサイド
- HTML5
- JavaScript
  - Bower


# 使用例
## 真珠の耳飾りの少女
![shinjyu.png](https://qiita-image-store.s3.amazonaws.com/0/23755/dcaaf720-c777-ad89-b51f-dc505ebaf788.png "shinjyu.png")


## 金閣寺
![kinkakuji.png](https://qiita-image-store.s3.amazonaws.com/0/23755/1b0a8c51-418a-9b21-c259-731da45b967c.png "kinkakuji.png")

## 葛飾北斎 富嶽三十六景 神奈川沖浪裏
![fugaku.png](https://qiita-image-store.s3.amazonaws.com/0/23755/23f7a65e-788c-27c9-106f-419d7568a8d8.png "fugaku.png")

# ProblemとTry
開発にあたっては、技術的なものからそれ以外のものまで様々な問題がありました。問題があったからこそ課題としては終了した後も開発を続けたかった、ということもありましたが…

## Google先生に怒られる
Google画像検索はAPIとしては公開されていません。開発当時は
`http://www.google.co.jp/searchbyimage?image_url=[image]&q=[keyword]`
という構造で画像からの類似画像検索が可能だったので、画像をbase64でエンコードし[image]に入れて、検索結果のページからHTML解析で検索結果上位のものを取得する、ということをしていました。
しかし、ある程度モザイクアート生成を回していると、プログラムによる連続アクセスのため｢お前人間か？｣という旨の判定ページに飛ばされてしまう、という問題が発生しました。

### Try
アクセスとアクセスの間にThread.sleep()を挟むことで応急処置を行いました。初めは500msくらいで設定していました。


## モザイクアート生成が遅すぎる
例えば、上の富嶽三十六景のモザイクアートは
- 縦: 70分割
- 横: 100分割
です。つまり、70 x 100 = 7000個の画像から成り立っています。つまり、Google画像検索に7000回アクセスするわけです。そして、怒られないように500msのスリープを入れているため、例のモザイクアートを作成しようとすると、スリープ時間だけとっても 500 x 7000 = 3500000ms = 3500s、つまり約1時間かかります。これに加えてHTTPの通信時間やJava側の処理時間がかかるので、とても使えたものではありませんでした。

### Try
Java8による並列処理を行いました。加えて、EC2のインスタンスを良い物に変えたりしました。これにより処理時間は半分以下になりました。
加えて、EC2のインスタンスをちょっといいものに変更してみました。

## 続･Google先生に怒られる
並列処理により多少は速度上昇しましたが、再びGoogle先生のお怒りが。sleep挟んでなかったときよりアクセス頻度あがってそうなものなので当然でしょうが…

### Try
EC2のインスタンスを複数立てて、それらをproxyサーバとして、怒られたらproxy先を変えるとか、一定時間ごとに変えるとか色々しましたが、解決には至らず。今思うとEC2のインスタンス全体とかVPC単位でNATとかされてたら意味なしでは。加えて、そんなじゃぶじゃぶリソース使って一体いくらお金がかかるんだという感じ。

## 置換される画像が微妙
- 画像の分割を細かくしていくにつれ、ほぼ単色の画像が多く出来上がってきます。
  - 今はわかりませんが、開発当時は例えば｢赤色かつ小さい｣画像で類似画像検索すると、｢他の色で小さい｣画像が引っかかってしまい、元の画像の色味とは程遠い画像で置き換わってしまうことも。
  - さらに分割を細かくしていくと、ほぼ単色の画像が単色の画像で置き換わるだけ、つまり｢ドットが荒くなるだけ｣のような結果になりがちでした。

### Try
同系統の色の画像のみを取得するように画像処理担当が頑張ってくれました。
後者の問題については、｢単色の画像を返さないようにする｣みたいな案があった気がします。

## たまに画像の取得に失敗する
たまに検索結果がなかったりするっぽいです。
### Try
応急処置として灰色の画像を代わりに入れました。｢真珠の耳飾りの少女｣のバンダナの垂れた端とかは結構出ちゃってますね。
案としては、｢隣のブロックの画像を元に画像を生成する｣がありました。

## 開発メンバーのモチベーション維持の失敗
最終的に開発していたメンバーは5→1→2人でした。
就活と重なっていた、というのもあるのですが、おそらく一番の原因は｢明確な目標を定めなかった｣ということだと思っています。2週に一回とかミーティングはしていたのですが、登る山が決まってないのに登山しようぜ！って言われても…って感じでしょうか。
今回の場合は、｢公開はちょっとアレかもしれないけど、スッとモザイクアート作れるようにできたらいいな｣と自分は思っていたのですが、それが伝わっていなかったか、同意できなかったかのどちらかでしょうか。

# 得られたもの
- Google検索を使えばモザイクアートは作れる
- mavenとかJava8とかOAuthの知識
- BowerとかGoogleのPolymerの存在を知れたこと
- チームを動かすには目標設定が必要だということ

# まとめ
Google画像検索を使用してモザイクアート作成するアプリを開発していた話を一年越しにまとめてみました。主に仕組みと直面した問題･解決しようとした話をつらつらと書いてみました。半ば実験的に開発しましたが、正しくAPIが公開されているものを使うべきですね。