OpenCV.jsをJavaScript/Node.jsで使ってみた

2022.03.22

こんにちは、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ランタイム)上などでも簡単な画像処理であればマネージドサービスを使わなくても出来そうですね。

以上