ReactとOpenCV.jsで画像の加工をしてみよう

はじめに

「ブラウザで何か撮影をする際にフロントサイドのみで画像を加工・解析をしたい」といった需要が一部あると思いますが、公開されている技術記事はあまりないと感じています。
そこで、自分が実際に実装した内容をある程度簡略化し紹介したいと思います。

加工にはOpenCVをJSでラップしたライブラリ「OpenCV.js」を利用します。

前提

OpenCV.jsを利用する前にデモページの実装が必要です。
今回はOpenCv.jsの紹介を中心に行うので撮影機能は省略し、ブラウザで画像をアップロードし表示するデモにします。
ChatGPTで作成したコード例を載せますので参考にしてください。

コード例
import React, { useState } from 'react';
import './App.css'

const App: React.FC = () => {
  const [selectedImage, setSelectedImage] = useState<File | null>(null);
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);

  const handleImageChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (file) {
      setSelectedImage(file);

      // 画像のプレビューURLを作成
      const imageUrl = URL.createObjectURL(file);
      setPreviewUrl(imageUrl);
    }
  };

  return (
    <div style={{ textAlign: 'center', marginTop: '20px' }}>
      <h1>画像アップロード</h1>
      <input
        type="file"
        accept="image/*"
        onChange={handleImageChange}
        style={{ marginBottom: '20px' }}
      />
      {previewUrl && (
        <div>
          <img
            src={previewUrl}
            alt="Uploaded Preview"
            style={{ maxWidth: '100%', maxHeight: '300px', margin: '20px 0' }}
          />
        </div>
      )}
      {!previewUrl && <p>画像を選択してください。</p>}
    </div>
  );
};

export default App;

OpenCV.jsの導入

まず、OpenCVのOpenCV.js関連のリファレンスに遷移し、コンパイル済のOpenCV.jsを取得します。

今回は4.5.0のバージョンを利用します。以下のURLに遷移し内容をコピー。OpenCV.jsというファイルを作成しコピーした内容を保存してください。

https://docs.opencv.org/4.5.0/opencv.js

保存したファイルはpublicフォルダに保存します。

index.htmlで読み込みます。

画像認識処理の実装

今回はアップロードした画像に対して輪郭の取得を行います。
まず画像をOpenCV.jsに読み込ませ、画面に表示してみましょう。

加工後の画像を表示するためのCanvasタグを配置し、cv.imshowで表示します。

  // OpenCV読み込み
  const handleReadOpenCv = () => {
    // OpenCV準備
    const cv = window.cv;

    // 画像の準備
    const img = new Image();
    if (previewUrl) {
      img.src = previewUrl;
    }

    const src = cv.imread(img); // OpenCV読み込み
    cv.imshow('cvCanvas', src); // Canvasに表示

    // メモリを明示的に開放する
    src.delete();
  };

  return (
    <div style={{ textAlign: 'center', marginTop: '20px' }}>
      <h1>画像アップロード</h1>
      <input
        type="file"
        accept="image/*"
        onChange={handleImageChange}
        style={{ marginBottom: '20px' }}
      />
      {previewUrl && (
        <div style={{ display: 'flex' }}>
          <div>
            <img
              src={previewUrl}
              alt="Uploaded Preview"
              style={{ maxWidth: '100%', maxHeight: '300px', margin: '20px 5px' }}
            />
          </div>
          <div>
            <canvas
              id="cvCanvas"
              style={{ maxWidth: '100%', maxHeight: '300px', margin: '20px 5px' }}
            />
            <br />
            <button onClick={handleReadOpenCv}>OpenCvで読み込み</button>
          </div>
        </div>
      )}
      {!previewUrl && <p>画像を選択してください。</p>}
    </div>
  );
};

画像をアップし、読み込んだ結果が以下の画面です。

左がアップロードした画像そのもの。右がOpenCV.jsで読み込み、Canvasに描画した画像です。
アップロードした画像をCanvasで描画できていることが確認できます。

続いて、アップロードした画像を白黒に変換してみましょう。cv.cvtColorを利用し、変換します。
第3引数に設定されている定数の指定で、変換先のフォーマットを指定できます。
変換した結果は第2引数に指定されている変数に格納されます。

cvtColorのリファレンスはこちら(英語)

  // OpenCV読み込み
  const handleReadOpenCv = () => {
    // OpenCV準備
    const cv = window.cv;

    // 画像の準備
    const img = new Image();
    if (previewUrl) {
      img.src = previewUrl;
    }

    const src = cv.imread(img); // OpenCV読み込み
    const dst = new cv.Mat(); // 画像の情報を格納する多次元配列「Mat」の準備
    cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY); // 画像を白黒に変換
    cv.imshow('cvCanvas', dst); // Canvasに表示

    // メモリを明示的に開放する
    src.delete();
    dst.delete();
  };

変換結果は以下です。画像が白黒になっていることを確認できました。

おわりに

以上、OpenCV.jsによる画像の加工でした。
OpenCVは画像に対して台形補正をかけたり、色の判定をしたりと多機能です。
機会があればそういった機能を紹介したいと思います。

一覧へ戻る

PAGE TOP