カメラで撮影した映像をモノクロにするだけであれば、ピクセルデータを編集したり、CanvasRenderingContext2D.filterを使ったりすれば良いのですが、OpenCV.jsを試してみたかったので、今回はOpenCV.jsで実装します。
blog.kimizuka.org
blog.kimizuka.org
OpenCV.jsとは
OpenCV.js は、Web プラットフォーム用の OpenCV 関数の選択されたサブセットの JavaScript バインディングです。これにより、マルチメディア処理を備えた新しい Web アプリケーションが、OpenCV で利用可能なさまざまなビジョン機能の恩恵を受けることができます。
https://docs.opencv.org/3.4/df/d0a/tutorial_js_intro.html より引用
ざっくり言えば、OpenCVの一部機能をJavaScriptで使えるライブラリです。
使い方は公式のチュートリアルにまとまっていますが、今回は導入からgetUserMediaで取得したカメラの映像をモノクロに加工してみようと思います。
OpenCV.jsの読み込み
チュートリアルによると、
<script> function onOpenCvReady() { console.log(cv); } </script> <script src="./opencv.js" onload="onOpenCvReady();"></script>
という感じで、グローバルにonOpenCvReadyを定義するか、
<script> const Module = { onRuntimeInitialized() { console.log(cv); } }; </script> <script src="./opencv.js"></script>
という感じで、グローバルにModuleを定義して読み込みます。
実装
index.html(抜粋)
<video id="video" autoplay playsinline></video> <canvas id="canvas"></canvas> <script src="index.js"></script> <script src="opencv.js"></script>
index.js
const Module = { onRuntimeInitialized() { const medias = { audio: false, video: { facingMode: 'user' } }; const promise = navigator.mediaDevices.getUserMedia(medias); promise.then(successCallback).catch(errorCallback); } }; function successCallback(stream) { const video = document.getElementById('video'); const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); video.oncanplay = () => { const width = video.clientWidth; const height = video.clientHeight; const src = new cv.Mat(height, width, cv.CV_8UC4); const dist = new cv.Mat(height, width, cv.CV_8UC1); canvas.width = width; canvas.height = height; processVideo(); function processVideo() { canvas.width = width; canvas.height = height; ctx.drawImage(video, 0, 0, width, height); src.data.set(ctx.getImageData(0, 0, width, height).data); cv.cvtColor(src, dist, cv.COLOR_RGB2GRAY); // モノクロに変換 cv.imshow('canvas', dist); // #canvasにレンダリング requestAnimationFrame(processVideo); } }; video.srcObject = stream; }; function errorCallback(err) { alert(err); };