最近触る機会があったので、画像処理 (画像を白黒にしたり、ぼかしたり) するためのオープンソースライブラリ「OpenCV.js」をラズパイで動かす方法を紹介したいと思います。検証環境は以下の通りです。
| モデル | Raspberry Pi 4B 4GB |
| OS | Raspberry Pi OS August 2020 |
| 使用ブラウザ | Chromium 78.0.3904.108 |
| OpenCV.js | 3.4.0 |
諸事情でラズパイを使っていますが、特にOSは関係なく動作すると思います。ブラウザで画像処理をしたい方の参考になれば幸いです。
OpenCV.jsって何?
OpenCV.jsは、画像処理ライブラリとして有名なOpenCVをJavaScriptから利用できる、というものです。JavaScriptで使えることによりブラウザ上で画像処理ができます。やったね。
OpenCV: Introduction to OpenCV.js and Tutorials
さっそく使ってみる
さっそく試してみましょう。ビルド済みのJSファイルが https://docs.opencv.org/{VERISON_NUMBER}/opencv.js にポンっと置かれていますので、scriptタグで読み込んで使います。
余談ですが、最近のARMサポートによってラズパイでもVSCodeが使えるようになりましたね。HTML書くときのショートカットが便利なので今回はじめてラズパイ4で使ってみましたが、使用感は問題なかったです。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello OpenCV.js</title>
</head>
<body>
<input type="file" id="input" name="file" />
<canvas id="output"></canvas>
<script src="https://docs.opencv.org/3.4.0/opencv.js"></script>
<script>
const image = new Image();
const input = document.getElementById('input');
input.addEventListener('change', (e) => {
image.src = URL.createObjectURL(e.target.files[0]);
}, false);
image.onload = function() {
const mat = cv.imread(image);
cv.imshow('output', mat);
mat.delete();
}
</script>
</body>
</html>
スクリプトは画像ファイルをOpenCV.jsで読み込み、cv.imshow()というAPIを使ってCanvasに描画するという流れです。
ファイルを保存したら、ブラウザでHTMLファイルを開いてみます。「ファイルを選択」をクリックして読み込む画像を選択します。とりあえず自分のGitHubアイコンを入れてみました。

お! 表示されました。結構簡単ですね。
デベロッパーコンソールを見ると、公式サイト (docs.opencv.org) からのダウンロードは1.74sでファイルサイズは10MB程度でした。所感ですがページロードが終わるまでに2 ~ 3秒かかります。

白黒画像に変換してみよう
せっかくなので読み込んだ画像を操作しましょうか。たとえば白黒画像に変換するため、img.onload の処理を少し変更してみます。
image.onload = function() {
const src = cv.imread(image);
const dst = new cv.Mat();
cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY, 0);
cv.imshow('output', dst);
src.delete(); dst.delete();
}
API名は他のOpenCVライブラリと同様です。書き方はPythonよりもC++に似ていて、画像処理したデータの受け皿となるcv.Matをあらかじめ用意しておく必要があります (サンプルコードではdstのこと)。あとは、色情報がOpenCVでお馴染みのBGRではなく、RGBAになっているのも特徴でしょうか。
では、ブラウザをリロードしてもう一度画像を読み込ませてみましょう。

しっかりグレースケールに変換されていますね。良き。
おわりに
OpenCV.jsを使う場合、画像の読み込みから描画までの大まかな流れは下図のようなかたちになりそうです。

HTMLImageElementを通さずに、画像データをそのままcv.Matに読み込めたらなあと思ったのですが、他のAPIを使っても上手くいきませんでした。方法をご存知の方、ぜひ教えていただきたいです…。
何はともあれ、これでOpenCV.jsの基本的な使い方を確認することができました。次回はPicameraからリアルタイムに映像を取得し、画像処理をかけられるか検証したいと思います。
あ、今回使ったサンプルコードはこちらのGistに上げておきました! それでは!
https://gist.github.com/uosotm/ed0abb918d4764a046566a5f76504a53

