写真からマインクラフトのドット絵に変換するwebアプリを作った話


![mona.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/982de649-b42a-b1a5-ebfa-34c025dce6ca.png)
タイトルの通り，写真からマインクラフトのブロックドット絵に変換するwebアプリを作成しました．
こちのらリンクから飛べますので遊んでみてください！
[minecraft-dot.pictures](https://minecraft-dot.pictures/ "Qiita")

(20/06/08 16:47追記）
要望がありましたので，使用ブロックの表示を日本語にしました．

# 使っている技術
このwebアプリはフロントエンドのみで動いてます．なので画像処理を含めた全ての処理はローカルマシンで動かしています．画像処理の部分はJavascript(OpenCV.js)で書きました．ホスティングサーバはFirebaseを利用しています．

## OpenCV.jsとは
OpenCV.jsとはJavascript用のOpenCVライブラリです．

### OpenCV.js導入
[公式ドキュメント](https://docs.opencv.org/3.4.1/df/df7/tutorial_js_table_of_contents_setup.html)によると，ビルドが必要だそうです.色々試したのですが，うまくいきませんでした。
仕方がないのでビルド済みのコードを直接とってくることにしました．
[こちら](https://docs.opencv.org/3.4.1/opencv.js)からビルド済みのコードが手に入りますのでcurlでとってきました．

```bash
 curl https://docs.opencv.org/3.4.1/opencv.js -o opencv.js
```
別に直接とってこなくてもHTMLに

```HTML
<script src="https://docs.opencv.org/3.4.1/opencv.js"></script>
```
と記述すれば使うことができます．

## ホスティング
ホスティングにはFirebaseを用いています．FirebaseはGoogleアカウントがあれば簡単にデプロイできます．今回のアプリのようにサーバーを必要としないアーキテクチャとも相性がいいですね！

[Firebaseで初めてのデプロイ](https://qiita.com/Watakatsu/items/667f45081a6dfbc11074)

# 変換アルゴリズム
では実際にどのようなアルゴリズムで変換しているかについて紹介していきます。

1. 画像をブロック数の画素数になるようにリサイズする
2. 元画像とマインクラフトブロックのLab値を計算
3. 元画像のLabとマインクラフトのブロックそれぞれとのLabのユークリド距離を計算
4. 差が最も小さいブロックを生成画像に配置

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/74c872f9-73e1-a4f0-b610-794660d2e204.png)

変換アルゴリズムはシンプルなんですが，RGBでなくLabで色差を計算しているところがキモです．RGBで色差を計算すると人が感じる色の違いとは少しずれたものになってしまいます．対してLabでは，人の見えに近い色差を計算できます．これはLabが人の錐体細胞の反応を元に設計された色空間だからです．

色差を求めるアルゴリズムによる違いは以下の記事に分かりやすくまとめられています．分かりやすく可視化されていてとても面白いので是非ご覧ください。
[色差アルゴリズムの違いをビジュアル化してみた](https://qiita.com/hachisukansw/items/98c218bc5616eaaba9a0)

このアプリのソースコードはGitHubに公開しています．
変換アルゴリズムの詳細はこちらから確認してください.
https://github.com/kult0922/minecraftDot

## 色差の計算に使う色空間の違いによる生成結果
ここではRGBとLabで色差の計算を行った場合の結果について比較していきます．

| 元画像 | RGB | Lab |
|:-:|:-:|:-:|
| ![https___qiita-image-store.s3.amazonaws.com_0_128670_3e29cc44-62e3-8dec-ab14-3b6476c233b7.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/f92fae3c-af55-998b-2ae9-dfc73548e042.jpeg) | ![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/e481f2f2-dfd7-09b8-3cae-a4b522ca23e5.png)  | ![minecraft_dot (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/a3fa187c-26ca-1087-7504-97261f9b5ea3.png)|
|  ![ocean.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/07fe5d95-6b8a-dd80-ef0c-12967fa90a83.jpeg)| ![ダウンロード (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/a79e0eb2-c5d5-edcb-8e73-f29e8d901b38.png)  | ![minecraft_dot (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/c8f97d81-489f-5581-b302-d208f3a7ebd5.png)  |
|  ![monsan.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/61c9d9c2-fed0-69cb-7cf5-50117b33970d.jpeg) | ![ダウンロード (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/8af070e8-1540-ab31-0971-40751494da5b.png)  | ![minecraft_dot (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/a66e7565-2a6a-2afc-c9bc-3a4657427afc.png)  |
|  ![fuji.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/1e5e0602-a5c3-90d3-e906-0a42ef70374a.jpeg) |  ![ダウンロード (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/cd4c83fb-b892-025a-2141-530ebf925067.png) | ![minecraft_dot (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/f2e994a9-b50e-aa8c-1cbc-75b203e20db7.png) |

あまり違いがないように見えますが，1段目のカラー帯の画像を注意深く見ると，RGBよりもLabの方が元画像に忠実であることが分かります．また，最下段のRGBの結果は桜のピンク色を再現できていません．

# オプション機能
ガラス，石，木のブロックのみを使ってで変換する機能もあります．もちろん画像によっては全く再現できないものもあります．モナリザの画像では石ブロックのみでは全く再現できていないのが分かります．灰色の多い画像ならそれなりにうまくいくと思いますが．．．ガラスは実際にマインクラフトで作ると背景が透けて見えるので面白そうだなーと感じています（実際に作ってはない） 木ブロックは意外と再現できていますね．

| 元画像 | ガラス | 石 | 木 |
|:-:|:-:|:-:|:-:|
| <img width="768" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/bb8d6378-1beb-005d-7aca-89e3ffc5b657.jpeg"> | <img width="768" alt="minecraft_dot (2).png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/3b15f8db-1b78-3aad-a895-fbe2303e5ff2.png">  |<img width="768" alt="minecraft_dot (1).png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/048d6937-dfb6-7e0c-ba78-548df9f1fb30.png"> | <img width="768" alt="minecraft_dot (3).png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/719881b8-588e-8a67-d76d-32c277d69d63.png">  |

使用するブロック数を変えた例です．数字は長辺のブロック数を表しています．流石に16ブロックだと何のドット絵か分かりません．

| 元画像 | 128 | 64 | 32 | 16 |
|:-:|:-:|:-:|:-:|:-:|
| <img width="768" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/bb8d6378-1beb-005d-7aca-89e3ffc5b657.jpeg">  | <img width="768" alt="minecraft_dot (4).png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/1217c921-066d-d1ba-3f35-7c2712d408aa.png">  |    ![minecraft_dot (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/0ffd799b-f580-bae1-6346-f2bc3f30d6ed.png)| <img width="768" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/fa1e1935-cd61-6f1e-b9f1-8e6faa83a375.png">| <img width="768" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/49a8c20b-8b8a-09a2-1652-6f6810733819.png">  |

使用したブロックは使用個数が表示されます．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268281/a6c6140b-c88b-3925-f0df-d616328bf8e2.png)


# まとめ
ちゃんと変換できるアプリができたので個人的には満足です．今後，使うブロックなどを選択できるようにする機能などもつけていきたいと思っています．OpenCV.js便利ですね．フロントで画像処理をするときは重宝することになる気がします．
以上写真からマインクラフトドット絵に変換するアプリの話でした．是非ドット絵を作成する際はご活用ください！！

# 参考
[Firebaseで初めてのデプロイ](https://qiita.com/Watakatsu/items/667f45081a6dfbc11074)
[OpenCV.jsをサクッと試す](https://qiita.com/puku0x/items/8b71efa61fce72e22188)
[色差アルゴリズムの違いをビジュアル化してみた](https://qiita.com/hachisukansw/items/98c218bc5616eaaba9a0)