Help us understand the problem. What is going on with this article?

openCV.js を使ってスマホ上で画像処理をしてみた

はじめまして。たろうマンです。
普段はWebサービスの開発とかしてます。

もはや最近ではよく聞く単語となった「画像処理」をJavaScriptでやってみました。

openCV.jsとは

画像処理でよく使われるライブラリであるOpenCVのJavaScript版(opencvjs)。
これにより、jsファイルとブラウザさえあれば画像処理を実現できるので
面倒な環境設定をせずとも画像処理を行なえるようになりました。

そのOpenCV.jsを用いてスマホ上で画像処理を行う手順を備忘録として残しておきます。

やったこと

以下の手順でスマホ上の画像処理を実現しました。

  1. OpenCV.jsの作成
  2. htmlでOpenCV.jsを読み込む
  3. PythonでWebサーバを立てる
  4. 3で立てたサーバにスマホでアクセスする

環境

MacOS 10.13.1
Python 2.7.11

本記事はMacOS環境を想定して書いていますが、
Ubuntuでも同じ手順でopencv.jsを作成出来ました。

パッケージマネージャーコマンドは
Linux, Ubuntuの場合は brew → apt-get に
CentOS, Fedoraの場合は brew → yum に適宜読み替えてください。

※Windows環境だと「ビルドしてopenCV.jsを作る」の部分が大変かも知れません
※Windows環境でもOpenCV.jsの作成を試みたのですが、色々とやった挙げ句、断念しました
※Windowsで試したい方は他記事をご参考にされるか、
※どこかから作成済みOpenCV.jsを持ってきて、2から試される方が良い気がします...

1. openCV.jsの作成(opencvjs)

手順は以下の通り

  1. Emscriptenのインストール
  2. OpenCVリポジトリのクローン
  3. OpenCVリポジトリをEmscriptenでコンパイル

1. Emscriptenのインストール

・準備

Emscriptenのインストールに必要なものをインストールする
既にインストールしている場合は不要です

# gitのインストール
sudo brew install git-core

# Python2.7のインストール
sudo brew install python2.7

# node.jsのインストール
sudo brew install nodejs

# CMakeのインストール
sudo brew install cmake

・Emscripten のインストール

任意のフォルダで、以下のコマンドを実行する

# emsdkのリポジトリをclone
git clone https://github.com/juj/emsdk.git

# リポジトリに移動
cd emsdk

# 使用するツールの最新化
git pull

# 最新verをインストール
./emsdk install latest

# active
./emsdk activate latest

# 環境変数の設定
source ./emsdk_env.sh

2. OpenCVリポジトリのクローン

任意のフォルダ(※1)で以下のコマンドを実行する

# OpenCVのリポジトリをクローン
git clone https://github.com/opencv/opencv.git

3. OpenCVリポジトリをEmscriptenでコンパイル

※1のフォルダで以下のコマンドを実行

# リポジトリに移動
cd opencv

# コンパイルの実行
python ./platforms/js/build_js.py build_js --emscripten /XXX/emsdk/emscripten/1.38.4

注意点:--emscripten

このオプションをつけないとbuild_js.pyの中で
emccの場所を見つけることが出来ずにエラーが発生する

--emscripten XXX
の XXX の部分は emcc が格納されているフォルダの絶対PATH
基本的には 1. で「emsdkのリポジトリをclone」したフォルダPATH

コンパイルが成功すると
以下のパスにopencv.jsが作られる(※コマンドの実行に3分ほどかかりました)

OpenCV.js location: ~/ws_openCV/opencv/build_js/bin/opencv.js



以下のようにtestが実行され
スクリーンショット 2018-06-02 12.56.01.png



以下のようにビルドが実行される
スクリーンショット 2018-06-02 12.54.18.png

2. openCV.jsをhtml中でloadし、cv関数を使用する

~/ws_openCV/opencv/build_js/bin/にある
opencv.js と opencv_js.wasm を htmlファイルと同じ階層に置いて
次のように書くと、openCV.jsをloadできる

<script src="opencv.jsのpath" type="text/javascript"></script>

基本的にはOpenCVの関数をそのまま使える

例えば、画像の読み込み、グレースケール変換する処理であれば次のように記述する

グレースケール変換
let src= cv.imread(画像);
let dst = new cv.Mat();
cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY, 0);

サンプルコード(html)

以下のように書くと、opencv.jsをloadして画像処理ができるようになる

sample.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello OpenCV.js</title>
</head>
<body>
<h2>OpenCV sample</h2>
<p id="status">OpenCV.js is loading...</p>
<div>
  <div class="inputoutput">
    <img id="imageSrc" alt="No Image" />
    <div class="caption">imageSrc <input type="file" id="fileInput" name="file" /></div>
  </div>
  <br>
  <form name="test">
    <input type="button" value="grayscale" onClick="grayscale()">
    <br>
  </form>
  <br>
  <div class="inputoutput">
    <canvas id="canvasOutput" ></canvas>
    <div class="caption">canvasOutput</div>
  </div>
</div>
<script type="text/javascript">
let imgElement = document.getElementById('imageSrc');
let inputElement = document.getElementById('fileInput');
inputElement.addEventListener('change', (e) => {
  imgElement.src = URL.createObjectURL(e.target.files[0]);
}, false);
function grayscale(){
  let mat = cv.imread(imgElement);
  var dst = new cv.Mat();
  cv.cvtColor(mat, dst, cv.COLOR_RGBA2GRAY, 0);
  cv.imshow('canvasOutput', dst);
  mat.delete();
  dst.delete();
}
function onOpenCvReady() {
  document.getElementById('status').innerHTML = 'OpenCV.js is ready.';
}
</script>
<script async src=".\opencv.js" onload="onOpenCvReady();" type="text/javascript"></script>
</body>
</html>

注意点:cv.Mat()

openCVの処理を行うときは、Mat形式で扱う必要がある

例えば、グレースケール変換の処理の場合、
処理の前に変換先の変数をMatクラスで定義する

// 画像の読み込み
let mat = cv.imread(imgElement);

// 変換先(グレースケール処理をかけた画像)の定義
let dst = new cv.Mat();

// グレースケール処理
cv.cvtColor(mat, dst, cv.COLOR_RGBA2GRAY, 0);

注意点:mat.delete()

EmscriptenがC++オブジェクトのdestructorを自動で呼び出せないので、
利用したMatオブジェクトは以下のように手動で削除する必要がある

mat.delete();
dst.delete(); 

3.サーバの起動

ターミナルでhtmlファイルを置いている階層まで移動し、
以下のコマンドを実行するとサーバが立ち上がる

python -m SimpleHTTPServer

この状態でPCのブラウザで次のURLにアクセス

http://localhost:8000

作成したhtml名のリンクをクリックするとhtmlが表示される

4.スマホからPCで立ち上げたサーバにアクセスする

PCとスマホを同じwifiに接続し、
ターミナルでifconfigコマンド(Windowsならipconfig)を実行してIPアドレスを調べる

3.と同じようにhtmlを置いている階層まで移動して以下のコマンドを入力

python -m SimpleHTTPServer



スマホのブラウザで次のURLにアクセスすると同じようにhtmlが表示される

http://XXX.XXX.XXX.XXX/ファイル名
# XXXX は先に調べたIPアドレス

まとめ

私はOpenCV.jsの作成の部分で少しハマったのですが、
一度、OpenCV.jsを作ってしまえば、jsを使うのは簡単でした。
これで画像処理のハードルが一段下がったような気がしますね。

Taro_man
▷ Djangoが好きです。 ▷ Pythonはもっと好きです。 ▷ Webサービスを運営してます。 ▷ https://siru-trend.com/ ▷ お仕事依頼はこちらまで ▷ taro.man.qiita@gmail.com
https://siru-trend.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away