OpenCV – Javascript で画像処理・OpenCV.js の使い方

目次

概要

OpenCV.js を使用して Javascript で画像処理を行う方法について解説します。

OpenCV.js

OpenCV.js とは、OpenCV をブラウザ上で利用可能にした JavaScript バインディングです。この OpenCV.js を使うことで、JavaScript で直接 OpenCV の機能を使用し、ブラウザでリアルタイムな画像処理やコンピュータビジョンのアプリケーションを作成することが可能になります。 OpenCV.js は Emscripten を用いて、OpenCV の C++ コードを WebAssembly に変換することでブラウザ上で動作します。これにより、ブラウザ環境での高速な実行と、ネイティブに近い性能を得ることができます。

OpenCV と OpenCV.js の違い

  • imread() で読み込んだ画像は OpenCV では BGR の 3 チャンネルに対して、OpenCV.js では RGBA の 4 チャンネルになります。チャンネル順が異なるので注意してください。
  • 作成した cv.Mat オブジェクトは、使用後に cv.Mat.delete() を呼び出して明示的にリソースを解放する必要があります。

ブラウザから使用する方法

  1. Releases · opencv/opencv から最新版の opencv-{バージョン}-docs.zip をダウンロードし、解凍します (例: opencv-4.10.0-docs)
  2. opencv-{バージョン}-docs/{バージョン}/opencv.js にそのバージョンの OpenCV.js の本体が存在するので、ディレクトリを作成し、以下のような構造で配置します
Project
├── sample.html
└── opencv.js
  1. sample.html には、以下のコードを記載します
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>OpenCV.js Example</title>
  </head>
  <body>
    <div>
      <input type="file" id="fileInput" />
      <div>
        <img id="input_img" />
        <canvas id="output_img"></canvas>
      </div>
    </div>

    <script async src="opencv.js" type="text/javascript"></script>
    <script type="text/javascript">
      const imgElement = document.getElementById("input_img");
      const inputElement = document.getElementById("fileInput");
      inputElement.addEventListener(
        "change",
        (e) => {
          imgElement.src = URL.createObjectURL(e.target.files[0]);
        },
        false
      );

      imgElement.onload = function () {
        const src = cv.imread(imgElement);

        // グレースケール画像に変更する。
        const dst = new cv.Mat();
        cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY);

        // キャンバスに描画する。
        cv.imshow("output_img", dst);

        src.delete();
        dst.delete();
      };
    </script>
  </body>
</html>

HTML ファイルをブラウザから開き、「ファイルを選択」から画像ファイルを選択すると、以下のような画面が表示されます。このサンプルでは、選択した画像を OpenCV.js で開き、グレースケールに変換して表示しています。

処理について解説します。 まず、入力ボタンをクリックして画像を選択したとき、ユーザーが選択した画像ファイルを URL に変換して <img> 要素の src 属性に設定するイベントハンドラを登録します。

const imgElement = document.getElementById("input_img");
const inputElement = document.getElementById("fileInput");
inputElement.addEventListener(
  "change",
  (e) => {
    imgElement.src = URL.createObjectURL(e.target.files[0]);
  },
  false
);

画像が読み込まれたときの処理を記述します。

  1. cv.imread() を使用して <img> 要素から画像を読み込み、OpenCV.js の cv.Mat 型のオブジェクトを生成します。
  2. cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY) を使用して画像をグレースケールに変換します。出力結果を格納する空の行列を const dst = new cv.Mat() により事前に作成しておく必要があります。
  3. cv.imshow("output_img", dst) で出力結果を表示する <canvas> 要素の id を指定して、結果画像を表示します。
imgElement.onload = function () {
  const src = cv.imread(imgElement);

  // グレースケール画像に変更する。
  const dst = new cv.Mat();
  cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY);

  // キャンバスに描画する。
  cv.imshow("output_img", dst);

  src.delete();
  dst.delete();
};

React で使用する方法

vite を使用して React の雛形を作成します。(Vite は Vue など他のフレームワークも対応しています)

npm create vite@latest
  • Project name: react-opencvjs
  • Select a framework: React
  • Select a variant: TypeScript + SWC

プロジェクトのディレクトリに移動し、@techstark/opencv-js をインストールします。

cd react-opencvjs
npm install @techstark/opencv-js

src/App.tsx を以下のように編集します。

import React, { useRef } from "react";
import cv from "@techstark/opencv-js";

function App() {
  const imgElementRef = useRef<HTMLImageElement>(null!);
  const canvasElementRef = useRef<HTMLCanvasElement>(null!);
  console.log(cv);

  function fileSelected(event: React.ChangeEvent<HTMLInputElement>) {
    const imgElement = imgElementRef.current;

    const file = event.target.files?.[0];
    if (!file) {
      return;
    }

    const reader = new FileReader();
    reader.onload = (event) => {
      const dataUrl = event.target?.result as string;
      imgElement.src = dataUrl;
    };
    reader.readAsDataURL(file);
  }

  function imgLoaded() {
    const imgElement = imgElementRef.current;
    const canvasElement = canvasElementRef.current;

    if (!imgElement.complete) {
      return; // 画像の読み込みに失敗した場合
    }

    const src = cv.imread(imgElement);
    const dst = new cv.Mat();
    cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY);
    cv.imshow(canvasElement, dst);

    src.delete();
    dst.delete();
  }

  return (
    <div>
      <input type="file" id="fileInput" onChange={fileSelected} />
      <div>
        <img id="input_img" ref={imgElementRef} onLoad={imgLoaded} />
        <canvas id="output_img" ref={canvasElementRef} />
      </div>
    </div>
  );
}

export default App;

コメント

コメントする

目次