みかづきブログ・カスタム

基本的にはちょちょいのほいです。

OpenCV.jsを使ってカメラで撮影した映像をモノクロにする 📷

opencv.org

カメラで撮影した映像をモノクロにするだけであれば、ピクセルデータを編集したり、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で取得したカメラの映像をモノクロに加工してみようと思います。

docs.opencv.org


OpenCV.jsのダウンロード

ビルド方法もチュートリアルにまとまっているのですが、ビルド済みの3.4.0のリンクもチュートリアルに記載されているので、サクッとビルド済みのファイルを使いました。

docs.opencv.org
docs.opencv.org


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を定義して読み込みます。

docs.opencv.org

実装

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);
};



DEMO

kimizuka.github.io

スマートフォン(iPhone 12miniで確認)でもサクサク動作しました。