OpenCV.jsでのWebカメラの取り扱いはOpenCVのサイトにも記載されているが、メモとしてこちらにも記載。OpenCV.jsの場合はWebカメラを直接扱ってくれるわけではなく、自分でgetUserMediaを扱う必要がある。
getUserMediaを使ったWebカメラ画像の表示については、GoogleのサイトWeb Fundamentalsがわかりやすい。
カメラのアクセスにはlocalhostもしくは、https接続が必要となる。
2021/09/10: iOS対応のためにはvideoタグに playsinline muted が必要だったため追記。
サンプルコード1(単純にWebカメラ画像を表示)
GoogleのサイトWeb Fundamentalsのコードそのまま。
<video id="player" controls playsinline muted autoplay></video>
<script>
const player = document.getElementById('player');
const constraints = {
video: true,
};
navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
player.srcObject = stream;
});
</script>
上記(とほぼ同じコード)はここにホストしてある。
サンプルコード2(canvasから画像を取得・canvasに表示)
src = cv.imread('canvas')
でcanvasから画像を取得して、cv.imshow("canvas2",dst)
でcanvasに画像を表示している部分がJavaScriptらしいところ。
ここではOpenCV.jsを持ってきて利用している。ロードは同期的に行った。
<!DOCTYPE html>
<html>
<body>
<video id="player" controls playsinline muted autoplay></video>
<button id="capture">Capture</button>
<canvas id="canvas" width=320 height=240></canvas>
<canvas id="canvas2" width=320 height=240></canvas>
<script src=https://docs.opencv.org/4.5.1/opencv.js></script>
</body>
</html>
<script>
const player = document.getElementById('player');
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const captureButton = document.getElementById('capture');
const constraints = {
video: true,
};
captureButton.addEventListener('click', () => {
// Draw the video frame to the canvas.
context.drawImage(player, 0, 0, canvas.width, canvas.height);
// OpenCVでグレーに変換、表示
let src = cv.imread('canvas');
let dst = new cv.Mat();
cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY, 0);
cv.imshow("canvas2",dst)
src.delete()
dst.delete()
});
navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
player.srcObject = stream;
});
</script>
上記(とほぼ同じコード)はここにホストしてある。
サンプルコード3(cv.VideoCaptureの例)
cv.VideoCaptureを使うとvideo要素から画像を取得できるため、サンプルコード2で
context.drawImage(player, 0, 0, canvas.width, canvas.height);
のようにいったんcanvasに書き込んで、src = cv.imread('canvas')
で読み込んでいた部分が不要になる。
setTimeoutで定期的にprocessVideoを呼び出してOpenCVでフレームの処理を行っている。
ここではOpenCV.jsのロードは非同期的に行った。
OpenCV.jsの読み込みが完了したこと(isCvLoaded==true)と、getUserMediaのvideoの取り込みの準備が終わったこと(onVideoCanPlay呼び出し)を確認してからcap = new cv.VideoCapture(player)
を行わないと、cap.read(src)
で正しく画像が得られず、画像処理が行えない(時々canvasが黒画面になる問題に遭遇した)。
<!DOCTYPE html>
<html>
<body>
<video id="videoInput" controls playsinline muted autoplay></video>
<canvas id="canvasOutput"></canvas>
<script async src=https://docs.opencv.org/4.5.1/opencv.js onload="onOpenCvReady()"></script>
</body>
</html>
<script>
const player = document.getElementById('videoInput');
let src = null;
let dst = null;
let cap = null;
let isCvLoaded = false
function onOpenCvReady() {
// OpenCV.jsのロードが終わったら呼ばれる
if (cv.getBuildInformation)
{
console.log(cv.getBuildInformation());
onloadCallback();
}
else
{
// WASM
cv['onRuntimeInitialized']=()=>{
console.log(cv.getBuildInformation());
onloadCallback();
}
}
};
function onloadCallback() {
// OpenCV.jsのロード完了
isCvLoaded = true;
};
const constraints = {
video: true,
};
// Attach the video stream to the video element and autoplay.
navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
player.srcObject = stream;
player.addEventListener('canplay', onVideoCanPlay, false);
});
function onVideoCanPlay() {
// ビデオ再生が可能になった
player.width = player.videoWidth // width, heightを設定しないとcap.read(src)で失敗する。
player.height = player.videoHeight
setTimeout(processVideo, 100);
};
const FPS = 30;
function processVideo() {
try {
if(!isCvLoaded){
setTimeout(processVideo, 100);
return;
}else if(cap==null){
// OpenCVのロードが終わり、Videoのフレームがくるのを待つ
cap = new cv.VideoCapture(player);
}
let begin = Date.now();
// start processing.
src = new cv.Mat(player.height, player.width, cv.CV_8UC4);
dst = new cv.Mat();
cap.read(src);
cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY);
cv.imshow('canvasOutput', dst);
src.delete();
dst.delete();
// schedule the next one.
let delay = 1000/FPS - (Date.now() - begin);
setTimeout(processVideo, delay);
} catch (err) {
console.error(err.message);
}
return;
};
</script>
上記(とほぼ同じコード)はここにホストしてある。
nodeで動作させるにはopencv4nodejsもあるが、手元の環境(macOS)ではうまくセットアップできず、OpenCV.jsを使って試した。