Reactを使用して画像認識アプリを実装する方法

Reactを使用して画像認識アプリを実装する方法

まずは効果の写真をお見せしましょう。

ここに画像の説明を挿入

ここに画像の説明を挿入

ここに画像の説明を挿入

個人的には効果は問題ないと思います。アプリが写真を学習する時間が短すぎるため(コンピューターが遅すぎるため)、認識はあまり正確ではありません。

(筆者はWindows 10を使用しています)インストール・動作環境:

  • npm install --global windows-build-tools (これには長い時間がかかります...)
  • npm install @tensorflow/tfjs-node (これにはかなり時間がかかります...)

プロジェクトディレクトリは次のとおりですここに画像の説明を挿入

トレインフォルダindex.js(エントリファイル)

 tf は '@tensorflow/tfjs-node' を必要とします。
const getData = require('./data')

const TRAIN_DIR = '../ガベージ分類/トレイン'
定数 OUTPUT_DIR = '../outputDir'
定数 MOBILENET_URL = 'http://ai-sample.oss-cn-hangzhou.aliyuncs.com/pipcook/models/mobilenet/web_model/model.json'

定数main = 非同期() => {
  // データをロード const { ds, classes} = await getData(TRAIN_DIR, OUTPUT_DIR)
  // モデルを定義する const mobilenet = await tf.loadLayersModel(MOBILENET_URL)
  モバイルネット.サマリー()
  // console.log(mobilenet.layers.map((l, i) => [l.name, i]))
  定数モデル = tf.sequential()
  (i = 0、i <= 86、i += 1 とします) {
    定数レイヤー = mobilenet.layers[i]
    レイヤー.trainable = false
    モデル.追加(レイヤー)
  }
  モデルを追加します(tf.layers.flatten())
  モデル.add(tf.layers.dense({
    ユニット: 10,
    アクティベーション: 'relu'
  }))
  モデル.add(tf.layers.dense({
    単位: クラス.長さ、
    アクティベーション: 'softmax'
  }))
  // トレーニングモデル model.compile({
    損失: 'sparseCategoricalCrossentropy',
    オプティマイザー: tf.train.adam(),
    メトリクス: ['acc']
  })
  model.fitDataset(ds, { エポック: 20 }) を待機します。
  model.save(`file://${process.cwd()}/${OUTPUT_DIR}`) を待機します。
}
主要()

data.js (データ処理)

定数 fs = require('fs')
tf は '@tensorflow/tfjs-node' を必要とします。

定数img2x = (画像パス) => {
  定数バッファ = fs.readFileSync(imgPath)
  tf.tidy(() => { を返す
    const imgTs = tf.node.decodeImage(新しいUint8Array(バッファ))
    定数 imgTsResized = tf.image.resizeBilinear(imgTs, [224, 224])
    imgTsResized.toFloat().sub(255/2).div(255/2).reshape([1, 224, 224, 3]) を返します
  })
}

const getData = async (trainDir, outputDir) => {
  定数クラス = fs.readdirSync(trainDir)
  fs.writeFileSync(`${outputDir}/classes.json`, JSON.stringify(classes))

  定数データ = []
  クラス.forEach((dir, dirIndex) => {
    fs.readdirSync(`${trainDir}/${dir}`)
      .filter(n => n.match(/jpg$/))
      .スライス(0, 10)
      .forEach(ファイル名 => {
        console.log('read', ディレクトリ, ファイル名)
        const imgPath = `${trainDir}/${dir}/${filename}`
        data.push({imgPath, dirIndex}) を実行します。
      })
  })

  tf.util.shuffle(データ)

  const ds = tf.data.generator(関数* () {
    定数カウント = データ.長さ
    定数バッチサイズ = 32
    (開始 = 0、開始 < カウント、開始 += バッチサイズ) {
      const end = Math.min(開始 + バッチサイズ、カウント)
      tf.tidy(() => {を生成します
        定数入力 = []
        定数ラベル = []
        (j = 開始; j < 終了; j += 1 とする) {
          const { imgPath, dirIndex } = データ[j]
          定数 x = img2x(imgPath)
          入力.push(x)
          ラベルをプッシュ(dirIndex)
        }
        const xs = tf.concat(入力)
        const ys = tf.tensor(ラベル)
        {xs,ys}を返す
      })
    }
  })

  戻る {
    ds、
    クラス
  }
}

モジュール.エクスポート = getData

プロジェクトの実行に必要なプラグインをインストールするここに画像の説明を挿入

アプリフォルダ

React をインポートします。{ PureComponent } から 'react' をインポートします。
'antd' から { Button, Progress, Spin, Empty } をインポートします。
'antd/dist/antd.css' をインポートします
'@tensorflow/tfjs' から * を tf としてインポートします。
'./utils' から { file2img, img2x } をインポートします。
'./intro' から intro をインポートします

定数DATA_URL = 'http://127.0.0.1:8080/'
クラスAppはPureComponentを拡張します{
  状態 = {}
  非同期コンポーネントDidMount() {
    this.model = tf.loadLayersModel(DATA_URL + '/model.json') を待機します。
    // this.model.summary()
    this.CLASSES = フェッチ(DATA_URL + '/classes.json').then(res => res.json()) を待機します。
  }
  予測 = 非同期 (ファイル) => {
    const img = file2img(ファイル)を待つ

    this.setState({
      画像ソース: 画像.src,
      読み込み中: true
    })
    タイムアウトを設定する(() => {
      定数 pred = tf.tidy(() => {
        定数 x = img2x(画像)
        this.model.predict(x) を返す
      })

      定数結果 = pred.arraySync()[0]
        .map((スコア, i) => ({スコア, ラベル: this.CLASSES[i]}))
        .sort((a, b) => b.スコア - a.スコア)
      this.setState({
        結果、
        読み込み中: false
      })
    }, 0)
  }

  レンダリング結果 = (アイテム) => {
    定数 finalScore = Math.round(item.score * 100)
    戻る (
      <tr キー = {item.label}>
        <td style={{ width: 80, padding: '5px 0' }}>{item.label}</td>
        <td>
          <進捗率={finalScore} ステータス={finalScore === 100 ? '成功' : '正常'} />
        </td>
      </tr>
    )
  }

  与える() {
    const { imgSrc, 結果, isLoading } = this.state
    const finalItem = 結果 && {...結果[0]、...イントロ[結果[0].ラベル]}

    戻る (
      <div スタイル={{パディング: 20}}>
        <span
          スタイル={{ 色: '#cccccc', テキスト配置: 'center', フォントサイズ: 12, 表示: 'block' }}
        >認識が正確でない可能性があります</span>
        <ボタン
          タイプ="プライマリ"
          サイズ="大"
          スタイル={{幅: '100%'}}
          onClick={() => this.upload.click()}
        >
          画像認識を選択</Button>
        <入力
          タイプ="ファイル"
          onChange={e => this.predict(e.target.files[0])}
          ref={el => {this.upload = el}}
          スタイル={{ 表示: 'なし' }}
        />
        {
          !results && !imgSrc && <空のスタイル={{ marginTop: 40 }} />
        }
        {imgSrc && <div style={{ marginTop: 20, textAlign: 'center' }}>
          <img src={imgSrc} スタイル={{ maxWidth: '100%' }} />
        </div>}
        {finalItem && <div style={{marginTop: 20}}>認識結果: </div>}
        {finalItem && <div style={{display: 'flex', alignItems: 'flex-start', marginTop: 20}}>
          <画像
            src={finalItem.icon}
            幅={120}
          />
          <div>
            <h2 スタイル = {{color: finalItem.color}}>
              {最終アイテム.ラベル}
            </h2>
            <div スタイル = {{color: finalItem.color}}>
              {最終項目.intro}
            </div>
          </div>
        </div>}
        {
          isLoading && <Spin size="large" style={{display: 'flex', justifyContent: 'center', alignItems: 'center', marginTop: 40 }} />
        }
        {結果 && <div style={{ marginTop: 20 }}>
          <テーブルスタイル={{幅: '100%'}}>
            <t本文>
              <tr>
                <td>カテゴリー</td>
                <td>マッチング度</td>
              </tr>
              {results.map(this.renderResult)}
            </tbody>
          </テーブル>
        </div>}
      </div>
    )
  }
}

デフォルトアプリをエクスポート

インデックス.html

 <!DOCTYPE html>
<html>
  <ヘッド>
    <title>ゴミの分別</title>
    <meta name="viewport" content="width=デバイス幅、初期スケール=1">
  </head>
  <本文>
    <div id="アプリ"></div>
    <script src="./index.js"></script>
  </本文>
</html>

インデックス

'react' から React をインポートします
'react-dom' から ReactDOM をインポートします。
'./App' から App をインポートします

ReactDOM.render(<App />, document.querySelector('#app'))

イントロ

エクスポートデフォルト{
  「リサイクル可能品」: {
    アイコン: 'https://lajifenleiapp.com/static/svg/1_3F6BA8.svg',
    色: '#3f6ba8',
    はじめに:「日常生活や日常生活に資するサービスを提供する活動で発生し、本来の使用価値の全部または一部を失い、リサイクルして生産原材料に加工したり、分別して再利用したりできるもの(廃紙、プラスチック、ガラス、金属、布地など)を指します。」 '
  },
  「有害廃棄物」: {
    アイコン: 'https://lajifenleiapp.com/static/svg/2v_B43953.svg',
    色: '#b43953',
    はじめに: 家庭ごみに含まれる物質のうち、人の健康や自然環境に直接的または潜在的に危害を及ぼすものを指します。これには、廃棄充電式電池、廃棄ボタン電池、廃棄電球、廃棄医薬品、廃棄農薬(容器)、廃棄塗料(容器)、廃棄日用化学薬品、廃棄水銀製品、廃棄電気機器および電子製品などが含まれます。 '
  },
  「キッチン廃棄物」: {
    アイコン: 'https://lajifenleiapp.com/static/svg/3v_48925B.svg',
    色: '#48925b',
    はじめに:「野菜の葉、残り物、果物の皮、卵の殻、お茶のかす、骨など、住民の日常生活で発生する有機廃棄物や腐敗しやすい廃棄物を指します。」 '
  },
  「その他のゴミ」: {
    アイコン: 'https://lajifenleiapp.com/static/svg/4_89918B.svg',
    色: '#89918b',
    はじめに: リサイクル可能物、有害廃棄物、厨房廃棄物を除く、混合され、汚染され、分類が困難なその他の家庭廃棄物を指します。 '
  }
}

ユーティリティ

'@tensorflow/tfjs' から * を tf としてインポートします。

エクスポートconst file2img = async(f) => {
  新しい Promise(reslove => { を返します。
    const リーダー = 新しい FileReader()
    リーダー.readAsDataURL(f)
    リーダー.onload = (e) => {
      定数img = document.createElement('img')
      img.src = e.target.result
      画像の幅 = 224
      画像の高さ = 224
      img.onload = () => { reslove(img) }
    }
  })
}

エクスポート関数img2x(imgEl) {
  tf.tidy(() => { を返す
    tf.browser.fromPixels(imgEl) を返します
        .toFloat().sub(255/2).div(255/2)
        .reshape([1, 224, 224, 3])
  })
}

プロジェクト コードを実行する前に、train ディレクトリで node index.js を実行して、認識システムが使用する model.json を生成する必要があります。その後、ルート ディレクトリで hs outputDir --cors を実行して、生成された model.json を http 環境で実行する必要があります。その後でのみ npm start を実行できます。そうしないと、プロジェクトでエラーが報告されます。

主なコードは上記です。著者も以前にそう言っていました。これについては何も知らないので、コードを説明することはできません。興味があれば、ぜひ自分で調べてみてください。コードアドレスが提供されます。

gitee.com/suiboyu/gar…

要約する

React を使って画像認識アプリを実装する方法についての記事はこれで終わりです。React 画像認識アプリに関するより関連性の高いコンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き閲覧してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • React でページ上のコードをハイライト表示するために highlight.js を使用する方法
  • Reactの再レンダリング問題を解決する

<<:  相対幅と絶対幅が競合する場合の HTML+CSS div ソリューション

>>:  LinuxとGNUシステムの関係の詳細な説明

推薦する

CSS でハートを描く 3 つの方法

以下では、CSS を使用してハートの形を描く 3 つの方法を紹介します。実装プロセスは非常にシンプル...

Vueは小さな検索機能を実装する

この記事の例では、検索機能を実装するためのVueの具体的なコードを参考までに共有しています。具体的な...

MySQL インデックス プッシュダウンを 5 分で理解する

目次インデックス プッシュダウンとは何ですか?インデックスプッシュダウン最適化の原理インデックスプッ...

ウェブサイトのパフォーマンス: 画像とCookieの最適化、モバイルアプリケーションの最適化

前のセクションでは、コンテンツ、サーバー、JavaScript、CSS など、Web サイトのパフォ...

Vue+swiperでタイムライン効果を実現

この記事では、タイムライン効果を実現するためのvue+swiperの具体的なコードを参考までに共有し...

デスクトップ仮想化を実現するために Hyper-V を展開する手順 (グラフィック チュートリアル)

Hyper-V を展開するためのハードウェア要件は次のとおりです。 64 ビット プロセッサ、具体...

Alibaba Cloud ECSインスタンスのユーザールートパスワードとリモート接続方法を設定する方法

Alibaba Cloud サーバーを購入した後、新しいインスタンスが正常に動作できるようにするには...

MySQL における識別子の大文字と小文字の区別の問題の詳細な分析

MySQL では、テーブル名の大文字と小文字の区別の問題が発生する可能性があります。実際、これはプラ...

Linux デュアル ネットワーク カード バインディング スクリプト メソッドの例

Linux の操作と構成作業では、デュアル ネットワーク カードのバインディングがよく使用されます。...

すべてのブラウザに対応したデータURIとMHTMLの完全なソリューション

データURI Data URI は、小さなファイルをドキュメントに直接埋め込むために RFC 239...

Vue + OpenLayers クイックスタートチュートリアル

Openlayers は、WebGIS クライアント向けのモジュール式で高性能かつ機能豊富な Jav...

Webサービスのリモートデバッグとタイムアウト動作原理の分析

Webサービスのリモートデバッグ.NET では、WEBSERVICE のリモート デバッグ機能はデフ...

CentOS 6 または CentOS 7 でディスク領域をクリアする方法

以下は、CentOS 6 または CentOS 7 サーバーのディスク領域をクリアするための簡単なコ...

LinuxでLVMディスクを拡張する詳細な手順

1.ハードディスクを追加する2. パーティションの状態を確認します: fdisk -l 3. パーテ...

MYSQL における char と varchar の違い

CHAR 型と VARCHAR 型は似ていますが、主に格納場所、末尾のスペース、取得方法が異なります...