ブラウザ上で画像処理
Android, iOS, Windowsなどのデバイスに依存せずにウェブブラウザ上で画像処理をやってみたいなと思って、少しやってみた。
画像処理はやっぱり慣れ親しんでいるOpenCVを使いたいので、OpenCVを利用する。実現するためには、OpenCV.jsというOpenCVのJavascript版を利用すると良いよう。ただ、OpenCV.jsのビルドは色々と面倒なようなので、今回は以下のような感じでダウンロードしたものを利用した。
今回は、動画ファイルを読み込んでグレースケールに変換する処理を試してみた。
ソースは以下の通り。このhtmlフィアルとその他の必要なファイル(utils.js, cup.mp4(入力動画), opencv.js, js_example_style.css)をサーバ上にアップするとスマホのウェブブラウザ上で入力の動画ファイルがグレースケールに変換されて出力されるのが確認できた。
画像処理はやっぱり慣れ親しんでいるOpenCVを使いたいので、OpenCVを利用する。実現するためには、OpenCV.jsというOpenCVのJavascript版を利用すると良いよう。ただ、OpenCV.jsのビルドは色々と面倒なようなので、今回は以下のような感じでダウンロードしたものを利用した。
curl https://docs.opencv.org/4.3.0/opencv.js -o opencv.jsOpenCV.jsのサンプルについては、OpenCVの以下のディレクトリにいくつかあるので、これを参考にすればよさそう。
\opencv\doc\js_tutorials
今回は、動画ファイルを読み込んでグレースケールに変換する処理を試してみた。
ソースは以下の通り。このhtmlフィアルとその他の必要なファイル(utils.js, cup.mp4(入力動画), opencv.js, js_example_style.css)をサーバ上にアップするとスマホのウェブブラウザ上で入力の動画ファイルがグレースケールに変換されて出力されるのが確認できた。
<!DOCTYPE html>
<html>
<html>
<head>
<meta charset="utf-8">
<title>Gray Scale</title>
<link href="js_example_style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<h2>Gray Scale</h2>
<div>
<div class="control"><button id="startAndStop" disabled>Start</button></div>
</textarea>
</div>
<p class="err" id="errorMessage"></p>
<div>
<table cellpadding="0" cellspacing="0" width="0" border="0">
<tr>
<td>
<video id="Color Video" width="320" height="240" muted></video>
</td>
<td>
<canvas id="Gray Video" width="320" height="240" ></canvas>
</td>
<td></td>
<td></td>
</tr>
<tr>
<td>
<div class="caption">videoInput</div>
</td>
<td>
<div class="caption">canvasOutput</div>
</td>
<td></td>
<td></td>
</tr>
</table>
</div>
<script src="https://webrtc.github.io/adapter/adapter-5.0.4.js" type="text/javascript"></script>
<script src="utils.js" type="text/javascript"></script>
<script type="text/javascript">
let utils = new Utils('errorMessage');
function executeProcess() {
let video = document.getElementById('Color Video');
let cap = new cv.VideoCapture(video);
let frame = new cv.Mat(video.height, video.width, cv.CV_8UC4);
let frameGray = new cv.Mat(video.height, video.width, cv.CV_8UC4);
const FPS = 30;
function processVideo() {
try {
if (!streaming) {
// clean and stop.
return;
}
let begin = Date.now();
// start processing.
cap.read(frame);
cv.cvtColor(frame, frameGray, cv.COLOR_RGBA2GRAY);
cv.imshow('Gray Video', frameGray);
// schedule the next one.
let delay = 1000 / FPS - (Date.now() - begin);
setTimeout(processVideo, delay);
} catch (err) {
utils.printError(err);
}
};
// schedule the first one.
setTimeout(processVideo, 0);
}
let streaming = false;
let videoInput = document.getElementById('Color Video');
let startAndStop = document.getElementById('startAndStop');
startAndStop.addEventListener('click', () => {
if (!streaming) {
utils.clearError();
videoInput.play().then(() => {
onVideoStarted();
});
} else {
videoInput.pause();
videoInput.currentTime = 0;
onVideoStopped();
}
});
function onVideoStarted() {
streaming = true;
startAndStop.innerText = 'Stop';
videoInput.height = videoInput.width * (videoInput.videoHeight / videoInput.videoWidth);
executeProcess();
}
function onVideoStopped() {
streaming = false;
startAndStop.innerText = 'Start';
}
videoInput.addEventListener('ended', () => {
onVideoStopped();
});
utils.loadOpenCv(() => {
videoInput.addEventListener('canplay', () => {
startAndStop.removeAttribute('disabled');
});
videoInput.src = 'cup.mp4';
});
</script>
</body>
</html>
コメント
コメントを投稿