6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

WebカメラからJSで画像処理するひな形

Last updated at Posted at 2019-03-21

概要

最近のブラウザだとWebカメラからの映像取得が簡単にできるようになっている。

この映像を毎フレームごとに画像処理したい場合、以下のように処理用の配列に変換する流れが一般的っぽい。

MDNに以下2つの良いサンプルがあったので組み合わせると良さそう。

Webカメラ → <video>

以下はWebカメラからMediaStreamを取得してvideo要素に読ませているサンプル

<video><canvas>ImageData

以下はvideo要素からクロマキー合成とかやってるデモプログラム

ソースコード

以下のソースコードはMDNにあったコードを繋げてアレンジしたもの。
せっかく動画を使うので、数行追加する程度の簡単なデモとして、1フレーム前との差分を取ってみた。
動かす場合、ローカルかHTTPS環境でないとWebカメラにアクセスできないので注意。

HTML部分(クリックで展開)
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Webカメラから画像処理</title>
</head>
<body>
    <video width="160" height="120" autoplay></video>
    <div>
        <canvas id="c1" width="80" height="60"></canvas>
        <canvas id="c2" width="80" height="60"></canvas>
        <canvas id="c3" width="80" height="60"></canvas>
    </div>
      <script src="webcam.js"></script>
</body>
</html>
JavaScript部分(クリックで展開)
webcam.js

const constraints = { audio: false, video: { width: 160, height: 120 } }; 

navigator.mediaDevices.getUserMedia(constraints)
.then(function(mediaStream) {
  const video = document.querySelector('video');
  video.srcObject = mediaStream;
  video.onloadedmetadata = function(e) {
    video.play();
  };
})
.catch(function(err) { console.log(err.name + ": " + err.message); }); // always check for errors at the end.


// https://developer.mozilla.org/ja/docs/Web/API/MediaDevices/getUserMedia



let processor = {
    timerCallback: function() {
      if (this.video.paused || this.video.ended) {
        return;
      }
      this.computeFrame();
      let self = this;
      setTimeout(function () {
          self.timerCallback();
        }, 0);
    },
  
    doLoad: function() {
      this.video = document.querySelector("video");
      this.c1 = document.getElementById("c1");
      this.ctx1 = this.c1.getContext("2d");
      this.c2 = document.getElementById("c2");
      this.ctx2 = this.c2.getContext("2d");
      this.c3 = document.getElementById("c3");
      this.ctx3 = this.c3.getContext("2d");
      let self = this;
      this.video.addEventListener("play", function() {
          self.width = self.video.videoWidth / 2;
          self.height = self.video.videoHeight / 2;
          self.timerCallback();
        }, false);
    },
  
    computeFrame: function() {
      let frame1 = this.ctx1.getImageData(0, 0, this.width, this.height);
      this.ctx2.putImageData(frame1, 0, 0);
      this.ctx1.drawImage(this.video, 0, 0, this.width, this.height);
      
      
      frame1 = this.ctx1.getImageData(0, 0, this.width, this.height);
      let frame2 = this.ctx2.getImageData(0, 0, this.width, this.height);

      let l = frame1.data.length / 4;
  
      diffFrame = this.ctx3.createImageData(this.width, this.height);

      for (let i = 0; i < l; i++) {
        let r = frame1.data[i * 4 + 0] - frame2.data[i * 4 + 0];
        let g = frame1.data[i * 4 + 1] - frame2.data[i * 4 + 1];
        let b = frame1.data[i * 4 + 2] - frame2.data[i * 4 + 2];
        diffFrame.data[i * 4 + 0] = Math.abs(r);
        diffFrame.data[i * 4 + 1] = Math.abs(g);
        diffFrame.data[i * 4 + 2] = Math.abs(b);
        diffFrame.data[i * 4 + 3] = 255;
      }

      this.ctx3.putImageData(diffFrame, 0, 0);

      return;
    }
  };

document.addEventListener("DOMContentLoaded", () => {
  processor.doLoad();
});
  // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Manipulating_video_using_canvas

実用

Webカメラを動かすと3つ目(一番右)のCanvasにフレーム間差分が見える。

image.png

Canvasにしてしまえば、各フレームに対する画像処理したり、適当な瞬間のフレームを保存したりとかができるはず。cv.jsとかにも使えそうなので、とにかく煮たり焼いたりなんでもできそう。

何か面白いことをやってみたいけど現状考え中。

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?