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システムの関係の詳細な説明

推薦する

Vueデータ変更検出の基本的な実装の簡単な分析

目次1. オブジェクトの変更検出2. オブジェクトに関する質問配列変更検出3.1 背景3.2 実装I...

JavaScript と JQuery フレームワークの基本チュートリアル

目次1. JS オブジェクトDOM –1、機能–2、テスト3. jQuery –1. 概要–2、使用...

Javascriptでシンプルなナビゲーションバーを実装

この記事では、参考までに、シンプルなナビゲーションバーを実装するためのJavascriptの具体的な...

Tomcat での jar のロードに関する異常な問題の分析と解決

現象の説明:プロジェクトでは、Springboot を使用して Web プロジェクトを開始します。起...

vue N​​progress のプログレスバー機能を実装する際の一般的な問題

NProgress は、ページがジャンプしたときにブラウザの上部に表示される進行状況バーです。公式ウ...

doctype のマークアップ検証

しかし最近、この方法を使用すると問題が発生することがわかりました。コードを参照してください。コードを...

mysql バックアップ スクリプトを作成し、7 日間保存します。

スクリプトの要件: MySQL データベースを毎日バックアップし、スクリプトを 7 日間保存します。...

MySQLクエリ条件の一般的な使用法の詳細な説明

この記事では、例を使用して、MySQL クエリ条件の一般的な使用方法を説明します。ご参考までに、詳細...

npmとcnpmを混在させる際の落とし穴の詳細な説明

目次原因理由NPM の紹介: CNPM の紹介:より良い方法方法の改善npm と cnpm を一緒に...

MySQL が my.cnf を読み込む順序の詳細

目次MySQLがmy.cnfを読み込む順序1. mysql.server の起動方法2. mysql...

HTML テーブルタグについての簡単な説明

主にその構造といくつかの重要な特性について説明します。少しずつ改善しながら紹介していきます。 1) ...

MySQL を使用した分散ロックの実装

導入分散システムでは、分散ロックは最も基本的なツール クラスです。たとえば、支払い機能を備えた 2 ...

Vue ローカルコンポーネントデータ共有 Vue.observable() の使用

コンポーネントが詳細になるにつれて、複数のコンポーネントが状態を共有する状況に遭遇するでしょう。Vu...

LinuxでHomebrewを使用する正しい方法

多くの人が Linux Homebrew を使用しています。これをより良く使用するための 3 つのヒ...

ReactでuseStateを使用する詳細な例

使用状態useState は、関数コンポーネント内で呼び出すことで、コンポーネントに内部状態を追加し...