目標
カメラからビデオを取り込む
ライブストリームをカメラで取り込まなければならないことはよくある。OpenCV.jsでは、これを実現するために WebRTC とHTMLのcanvas要素を使う。カメラ(内蔵またはUSB)からビデオを取り込み、グレースケールのビデオに変換して表示してみよう。
ビデオを取り込むには、WebページにいくつかのHTML要素を追加する必要がある。
- カメラからのビデオを直接表示するための <video>
- ビデオを1フレームずつcanvasのImageDataに転送するための <canvas>
- OpenCV.jsが取得したビデオを表示するためのもう1つの <canvas>
まず、WebRTCのnavigator.mediaDevices.getUserMediaを使ってメディアストリームを取得する。
let video = document.getElementById("videoInput"); // video is the id of video tag
navigator.mediaDevices.getUserMedia({ video: true, audio: false })
.then(function(stream) {
video.srcObject = stream;
video.play();
})
.catch(function(err) {
console.log("An error occurred! " + err);
});
- 覚え書き
- この関数は、ビデオファイルからビデオを取り込む場合は不要である。ただし、HTMLのvideo要素はOgg(Theora)、WebM(VP8/VP9)、MP4(H.264)のビデオ形式のみをサポートする点に注意すること。
ビデオの再生
これでブラウザがカメラのストリームを取得した。次に、Canvas 2D APIのCanvasRenderingContext2D.drawImage()メソッドを使ってビデオをcanvasに描画する。最後に、画像のはじめ方 のメソッドを使って画像をcanvasに読み込んで表示できる。ビデオを再生するには、cv.imshow() をdelayミリ秒ごとに実行する必要がある。setTimeout()メソッドの利用を推奨する。ビデオが30fpsの場合、delayミリ秒は (1000/30 - processing_time) とすべきである。
let canvasFrame = document.getElementById("canvasFrame"); // canvasFrame is the id of <canvas>
let context = canvasFrame.getContext("2d");
let src = new cv.Mat(height, width, cv.CV_8UC4);
let dst = new cv.Mat(height, width, cv.CV_8UC1);
const FPS = 30;
function processVideo() {
let begin = Date.now();
context.drawImage(video, 0, 0, width, height);
src.data.set(context.getImageData(0, 0, width, height).data);
cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY);
cv.imshow("canvasOutput", dst); // canvasOutput is the id of another <canvas>;
// schedule next one.
let delay = 1000/FPS - (Date.now() - begin);
setTimeout(processVideo, delay);
}
// schedule first one.
setTimeout(processVideo, 0);
OpenCV.jsは、上記の方法を用いて cv.VideoCapture (videoSource) を実装している。隠しcanvas要素を手動で追加する必要はない。
- 引数
-
- 戻り値
- cv.VideoCapture インスタンス
ビデオの1フレームを取得するには read (image) を使う。パフォーマンス上の理由から、imageはcv.CV_8UC4型で、ビデオと同じサイズで構築すべきである。
- 引数
-
| image | cv.CV_8UC4型で、ビデオと同じサイズの画像。 |
上記のビデオ再生のコードは、以下のように簡略化できる。
let src = new cv.Mat(height, width, cv.CV_8UC4);
let dst = new cv.Mat(height, width, cv.CV_8UC1);
let cap = new cv.VideoCapture(videoSource);
const FPS = 30;
function processVideo() {
let begin = Date.now();
cap.read(src);
cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY);
cv.imshow("canvasOutput", dst);
// schedule next one.
let delay = 1000/FPS - (Date.now() - begin);
setTimeout(processVideo, delay);
}
// schedule first one.
setTimeout(processVideo, 0);
- 覚え書き
- 停止後はsrcとdstを忘れずに削除すること。
試してみよう