OpenCV.js をちょっとだけ試してみた。

この記事は[OpenCV Advent Calendar 2017](https://qiita.com/advent-calendar/2017/opencv)の23日目の記事です。他の記事は[目次](https://qiita.com/advent-calendar/2017/opencv)にまとめられています。


# この話のオチ
Web上でアプリケーションを開発するツール・ライブラリもいろいろありますが、**JavaScriptで動作する画像解析ライブラリとしてOpenCVが活用できる**ようになりました！

単純な色変換のみならず、Webカメラからの入力・表示をはじめとして、様々な機能が使えるようになっています。

2018年は、もっと身近に、コンピュータビジョンが使える時代になりそうですね！

# はじめに
OpenCVアプリケーションを作るときの課題の１つに、ポータビリティがあります。GUIとして共通化できるhighguiモジュールがあってもWindows, MacOS, Android, iOS それぞれのプラットフォームで動かすためには、それなりの苦労が必要。**多様なクライアントに対応するには、コンパイルとデプロイは各環境に必要になるので、なかなか面倒**。これはどうにかしたい。

しかし、画像処理部をサーバーに集約させると、**画像データ処理するためだけに大量のアップロードが必要**になってしまう。これも良くない。クラウドの使用料も膨大になり、セキュリティ的にも・・・・。ローカルに画像処理が実行できる必要がありますね！

こういう事を踏まえると、**前処理なら、JavaScriptで組んで全プラットフォーム共通にしたくなりますよね！** むしろ、なってください！ということで、OpenCV 3.3.1で導入された、OpenCV.jsのお話です。

# 実現方法は？
[本家のドキュメント] ( https://docs.opencv.org/3.3.1/df/d0a/tutorial_js_intro.html )にも詳しく書いていますが、図にするとこういうイメージです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89434/f8e21631-6b86-1b4f-3032-69e8e626ed57.png)

従来は、OpenCVのソースコードは、コンパイラ（例えばGCC)でライブラリにコンパイル・リンクされていました。これに対して、LLVMフロントエンドであるclangによってLLVM bitcode(中間コード)に変換し、これをEmscriptenでJavaScriptコードにコンパイルしたのが、OpenCV.jsとなります。なお、実際に動かす場合には、asm.js/WebAssemblyなどを使って高速処理できるようになっている、とのことです。

# OpenCV.jsの入手元は？
公式に配布されていないので、探せば見つかりますが…頑張りましょう！（[Releases](https://opencv.org/releases.html) に欲しいなあ）

## OpenCV.jsの作り方
[本家マニュアル](https://docs.opencv.org/3.3.1/d4/da1/tutorial_js_setup.html) の手順に従って、Ubuntuで作業したらできます。コンフィギュレーションはこんな感じで、core/imgproc/objdetect/video/jsしか対象にならない…。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89434/7ec93c92-6701-2c5f-1947-5cfa41a9b3db.png)

core i7 の4770 8コアでぶん回しで、これくらい。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/89434/170ef6e8-eae4-4459-e1e9-02f03d8acdca.png)


# OpenCV.jsの使い方
OpenCVを使ったことがある人ならば、非常に簡単に始められます！例えば、[画像を2値化する例](https://docs.opencv.org/3.3.1/d7/dd0/tutorial_js_thresholding.html)はこうなります。

>let src = cv.imread('canvasInput');
let dst = new cv.Mat();
// You can try more different parameters
cv.threshold(src, dst, 177, 200, cv.THRESH_BINARY);
cv.imshow('canvasOutput', dst);
src.delete();
dst.delete();

## ポイント
**src.delete()** ってあるけど、勝手に消してくれないの？と感じた方がいるかもしれません。これを補足しますとECMA-262 Edition 5.1では、finalizers/weak references with callbacksがサポートされていないので、EmscriptenはC++オブジェクトのdestructorを自動的に呼び出せない、とのことですね。そのため、利用したMatオブジェクトは手動で削除する必要があります。

[Note 
You have to call delete method of cv.Mat to free memory allocated in Emscripten's heap. Please refer to Memeory management of Emscripten for details.](https://docs.opencv.org/3.3.1/d0/d84/tutorial_js_usage.html)

# どんな機能が使えるの？
## GUI Feature
- HTML5 Canvasからの画像読み込み・書き込み
- カメラからの動画フレームの読み込み（表示はCanvasで)
- トラックバーの追加

## Core Operations
- 基本的なMatオブジェクト操作（構築、複製、フォーマット変換、etc...)
- 算術処理（加法、減法、ビット操作などなど）

## Image Processing
- 色空間変換
- 形状変換
- ２値化
- スムージング
- モーフィング
- エッジ抽出 etc...

## Video Analysis
- Meanshift/Camshift
- Optical Flow
- Background Subtraction

## Object Detection
-　Face Detection

そして、[JavaScript bindings for dnn module](https://github.com/opencv/opencv/pull/10215)と、夢は広がりまくりですね！

# 現状の問題点

## OpenCV.jsが配布されていない。
これが一番大きい問題ですね……。node.jsやらVue.jsやらであれば公式リリースがあるのですが、OpenCV.jsはまだ配布されていないのか、配布場所が分かりにくいのか、見つからないです。

「使いたい」と思ったときに、すぐ使えないことは機会損失にもつながります。やはりここは、OpenCV.jsの公式配布を希望したいですね！

## OpenCV.jsが巨大すぎる
私の手元で作成したものでも6MBあります。初回ダウンロード時のみ必要になるとはいえ、やはりこれでは…。

アプリケーション側が参照していない関数を削除するなどして、OpenCV.jsをシュリンクする機能が必要になるかもしれません。あるいは、OpenCV.jsがメインルーチンをロードした後、機能が呼ばれるたびに必要なサブjsを読みだす仕組み、などなど。

## 重たい処理の進捗不明
重たい処理をしているときに、OpenCV側ががっつりCPU/メモリをもっていってしまうので、やはりこの部分については何かしらシステムにフィードバックできる仕組みが必要になる気がします。

例えば、100ms以上OpenCV側が処理から応答がない場合には、イベントが発行するような仕組み、などなど。

## 特徴量抽出あたりが早くほしい
ほしいです！というのは、画像特徴量だけをやりとりするようにできれば、例えば個人情報なども除去した状態でのやり取りになるので、非常に扱いやすくなります！

明日は、[tomoaki_teshima](https://twitter.com/tomoaki_teshima)  さんの投稿で、執筆時点でのタイトルは **「去年書いた浮動小数点数の精度問題のネタ」** です！組込大好き人間としては気になります（IAとARMで泣かされた……）よろしくお願いいたします。