こんにちは、CX事業本部 IoT事業部の若槻です。
今までOpenCVはPythonで使うものというイメージが強かったのですが、OpenCVのJavaScript実装であるOpenCV.jsなるものもあるみたいです。
今回は、OpenCV.jsをJavaScriptおよびNode.jsで使ってみました。
やってみた
OpenCV.jsの導入
まず準備としてOpenCV.jsの導入を行います。
下記よりOpenCVのソース(opencv-{VERSION_NUMBER}-docs.zip
)の最新版をダウンロードします。
解凍したソース内に含まれるopencv.js
を作業パスにコピーします。
JavaScriptで使ってみる
こちらのチュートリアルを参考に、OpenCV.jsをJavaScriptで使ってみます。
opencv.js
ファイルと同じパスに次のindex.html
を作成します。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello OpenCV.js</title>
</head>
<body>
<h2>Hello OpenCV.js</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>
<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);
imgElement.onload = function() {
let mat = cv.imread(imgElement);
cv.imshow('canvasOutput', mat);
mat.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>
ブラウザでindex.html
を開きます。[ファイルを選択]をクリックして適当な画像ファイルをアップロードします。
すると画像を表示できました。上の画像は<img>
、下の画像は<canvas>
による表示です。
ポイントは下記の部分の記述です。
index.html
imgElement.onload = function() {
let mat = cv.imread(imgElement);
cv.imshow('canvasOutput', mat);
mat.delete();
};
cv.imread()
で<img id="imageSrc" alt="No Image" />
から画像を取得しMat化しています。またcv.imshow()
によりMatを<canvas id="canvasOutput" ></canvas>
に出力することによりブラウザに表示しています。
Node.jsで使ってみる
続いて、こちらのチュートリアルを参考に、OpenCV.jsをNode.jsで使ってみます。
Minimal example
まず最小構成で動作を確認してみます。
opencv.js
ファイルと同じパスに次のexample1.js
を作成します。
example1.js
// Define a global variable 'Module' with a method 'onRuntimeInitialized':
Module = {
onRuntimeInitialized() {
// this is our application:
console.log(cv.getBuildInformation())
}
}
// Load 'opencv.js' assigning the value to the global variable 'cv'
cv = require('./opencv.js')
実行するとビルド情報が取得できます。
$ node example1.js
cv = require('./opencv.js')
でopencv.js
をロードし、ライブラリがreadyとなったらonRuntimeInitialized()
が実行されます。
Working with images
前節を踏まえ、実際に画像を処理してみます。
project1
ディレクトリ配下にnpmプロジェクトを作成します。
mkdir project1
cd project1
npm init -y
npm install jimp
jimp
は画像の操作を簡単に行えるライブラリです。
また同パス内に、先程のopencv.js
および画像ファイルlena.jpg
を配置します。
今回配置した画像ファイルは下記です。
そして同パス内に下記のexampleNodeJimp.js
を作成します。
exampleNodeJimp.js
const Jimp = require('jimp');
async function onRuntimeInitialized(){
// load local image file with jimp. It supports jpg, png, bmp, tiff and gif:
var jimpSrc = await Jimp.read('./lena.jpg');
// `jimpImage.bitmap` property has the decoded ImageData that we can use to create a cv:Mat
var src = cv.matFromImageData(jimpSrc.bitmap);
// following lines is copy&paste of opencv.js dilate tutorial:
let dst = new cv.Mat();
let M = cv.Mat.ones(5, 5, cv.CV_8U);
let anchor = new cv.Point(-1, -1);
cv.dilate(src, dst, M, anchor, 1, cv.BORDER_CONSTANT, cv.morphologyDefaultBorderValue());
// Now that we are finish, we want to write `dst` to file `output.png`. For this we create a `Jimp`
// image which accepts the image data as a [`Buffer`](https://nodejs.org/docs/latest-v10.x/api/buffer.html).
// `write('output.png')` will write it to disk and Jimp infers the output format from given file name:
new Jimp({
width: dst.cols,
height: dst.rows,
data: Buffer.from(dst.data)
})
.write('output.png');
src.delete();
dst.delete();
}
// Finally, load the open.js as before. The function `onRuntimeInitialized` contains our program.
Module = {
onRuntimeInitialized
};
cv = require('./opencv.js');
実行するとoutput.png
ファイルが作成されます。
$ node example1.js
cv.dilate()
により境界をぼやけさせる画像変換を行えました。
おわりに
OpenCV.jsをJavaScriptおよびNode.jsで使ってみました。
今までOpenCVを使うときは当たり前のようにPythonを使っていたのですが、Webアプリやjs系プロジェクトでもOpenCVを利用できることが確認できてよかったです。これにより、例えばAWS Lambda(Node.jsランタイム)上などでも簡単な画像処理であればマネージドサービスを使わなくても出来そうですね。
以上