0
0

More than 3 years have passed since last update.

SemanticSegmentationを行うnpmパッケージを作ったので使い方を説明してみる

Last updated at Posted at 2020-06-23

はじめに

先日、大きな画像を分割してsemantic segmentationを行うnpm パッケージを作成したので、使い方の説明を兼ねてデモの作り方を説明してみます。

このパッケージは、スマホなどの性能の限られたデバイス上で精度と応答速度のトレードオフを調整しながらSemanticSegmentationするためのものです。
今回のデモとしては、このようなものを作ります。バーコードを検出してセグメンテーションを行います。

https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_365991_425fef2a-7eef-9bc4-21e0-3960a4c8154e.gif

前回のnpmパッケージを作成した際の投稿はこちらです。
https://qiita.com/wok/items/a6445d17724ed700e448

前準備

今回はReactでデモを作成します。
まずは環境構築をしましょう

$ create-react-app demo --typescript

パッケージをインストール

それではvirtual背景のパッケージをインストールします。

$ npm install scalable-semantic-segmentation-js
$ node node_modules/scalable-semantic-segmentation-js/bin/install_worker.js public
file is copied

使用するモデルの準備

次に使用するSemantic Segmentationのモデルを用意します。
このモデルは、[batch, height, width, channels]のshapeのテンソルを入力として想定しています。

$ ls public/WEB_MODEL/300x300_0.10/
group1-shard1of1.bin  model.json

デモのコード

準備ができたら、ソースコードを作成します。
ここでは、重要と思われる部分のみ解説します。ソース全体は下記のリポジトリに置いてあります。

本デモでは、Reactコンポーネントのメンバー変数としてモジュールのクラスのインスタンスを作っておきます。

  scalableSS:ScalableSemanticSegmentation = new ScalableSemanticSegmentation()

では、componentDidMoutからみて行きます。


componentDidMount() {
      console.log('Initializing')

      const initWorkerPromise = this.initWorker()                          // <-- (1)

      if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { // <-- (2)
          const webCamPromise = navigator.mediaDevices
              .getUserMedia({
                  audio: false,
                  video: DisplayConstraintOptions[this.state.videoResolution]
              })
              .then(stream => {
                  console.log(this.videoRef)
                  this.videoRef.current!.srcObject = stream;               // <-- (3)
                  return new Promise((resolve, reject) => {
                      this.videoRef.current!.onloadedmetadata = () => {
                          resolve();
                      };
                  });
              });

          Promise.all([initWorkerPromise, webCamPromise])
              .then((res) => {
                  console.log('Camera and model ready!')
              })
              .catch(error => {
                  console.error(error);
              });
      }           
  }

(1)で今回SemanticSegmentationを行うインスタンスをイニシャライズします。このメソッドの内部は後述します。
(2)でビデオデバイスを取得し、(3)でHTMLVideoElementのソースに設定しています。

次に、initWorkerの中身を見ていきます。

async initWorker() {
      // SemanticSegmentation
      this.scalableSS.addInitializedListener(()=>{ // <-- (1-1)
          const props = this.props as any
          this.setState({initialized:true})
          this.requestScanBarcode()                // <-- (1-2)
      })
      this.scalableSS.addMaskPredictedListeners((maskBitmap:ImageBitmap)=>{// <-- (2-1)
          // 再キャプチャ
          this.requestScanBarcode()                                        // <-- (2-2)

      })

      this.scalableSS.init(
            AIConfig.SS_MODEL_PATH, 
            AIConfig.SPLIT_WIDTH, 
            AIConfig.SPLIT_HEIGHT, 
            AIConfig.SPLIT_MARGIN)                                         // <-- (3)
      return
  }

本メソッドでは、SemanticSegmentationを行うインスタンスをイニシャライズしています。
まず(1-1)で、インスタンス内部で使用するモデルのロードなどの初期化が完了したときのコールバック関数を設定します。
コールバック関数の中では(1-2)バーコードスキャンを行う関数を呼び出しています。
(2-1)は、セグメンテーションが完了したときに呼び出されるコールバック関数を設定しています。
このとき受け取るパラメータがセグメンテーションの結果のビットマップイメージになります。
コールバック関数の中でも(2-2)バーコードスキャンを行う関数を呼び出しています。これにより処理をループさせています。
(3)でインスタンスに使用するモデルの情報と、画像を分割する際に使用するマージン(分割後の隣り合う画像間でオーバラップする領域の割合)を指定します。第1引数がモデルのパス、第2、3引数がモデルで使用する幅と高さ、第4引数がマージンです。

最後に、requestScanBarcodeです。

  requestScanBarcode = async () => {
      console.log('requestScanBarcode')
      const video = this.videoRef.current!
      const controller = this.controllerCanvasRef.current!
      controller.width = this.overlayWidth
      controller.height = this.overlayHeight

      const captureCanvas = captureVideoImageToCanvas(video) <--(1)
      if(captureCanvas.width === 0){
          captureCanvas.remove()
          window.requestAnimationFrame(this.requestScanBarcode);
          return
      }
      this.scalableSS.predict(captureCanvas, 
                              this.state.colnum,
                              this.state.rownum) <--(2)
      captureCanvas.remove()
  }


ここでは、SemanticSegmentationを行う対象となる画像を取得し、SemanticSegmentionを実行しています。
(1)で、SemanticSegmentationの対象となる画像をHTMLVideoElementから取得しています。この画像を(2)の引数としてモジュールのインスタンスに与え、SemanticSegmentationを実行させています。第2,3引数は分割する行数と列数です。

以上で、セグメンテーションを行う処理は完了です。

デバッグ用に、セグメンテーションの様子や、グリッドの情報を表示することもできます。


                  <Label basic size="tiny" color={this.state.showSS?"red":"grey"} onClick={()=>{
                      const newValue = !this.state.showSS
                      this.scalableSS.previewCanvas = newValue ? this.workerSSMaskMonitorCanvasRef.current! : null
                      this.setState({showSS:newValue})
                  }}>ss</Label>
                  <Label basic size="tiny" color={this.state.showGrid?"red":"grey"} onClick={()=>{
                      const newValue = !this.state.showGrid
                      this.scalableSS.girdDrawCanvas = newValue ? this.controllerCanvasRef.current! : null
                      this.setState({showGrid:!this.state.showGrid})
                  }}>grid</Label>

this.scalableSS.previewCanvasとthis.scalableSS.girdDrawCanvasにそれぞれ描画するHTMLCanvasElementを設定してください。

デモ

ソースコードとnpmパッケージ

本ソースコードは下記のリポジトリに格納してあります。
https://github.com/FLECT-DEV-TEAM/ScalableSemanticSegmentationjs_demo

npmパッケージのページは次のURLになります。
https://www.npmjs.com/package/scalable-semantic-segmentation-js

0
0
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
0
0