如何利用React实现图片识别App


Posted in Javascript onFebruary 18, 2022

先把效果图给大家放上来

如何利用React实现图片识别App

如何利用React实现图片识别App

如何利用React实现图片识别App

个人觉得效果还行。识别不太准确是因为这个 app学习图片的时间太短(电脑太卡)。

(笔者是 window10) 安装运行环境:

  • npm install --global windows-build-tools(这个时间很漫长。。。)
  • npm install @tensorflow/tfjs-node(这个时间很漫长。。。)

项目目录如下 如何利用React实现图片识别App

train文件夹 index.js(入口文件)

const tf = require('@tensorflow/tfjs-node')
const getData = require('./data')

const TRAIN_DIR = '../垃圾分类/train'
const OUTPUT_DIR = '../outputDir'
const MOBILENET_URL = 'http://ai-sample.oss-cn-hangzhou.aliyuncs.com/pipcook/models/mobilenet/web_model/model.json'

const main = async () => {
  // 加载数据
  const { ds, classes} = await getData(TRAIN_DIR, OUTPUT_DIR)
  // 定义模型
  const mobilenet = await tf.loadLayersModel(MOBILENET_URL)
  mobilenet.summary()
  // console.log(mobilenet.layers.map((l, i) => [l.name, i]))
  const model = tf.sequential()
  for (let i = 0; i <= 86; i += 1) {
    const layer = mobilenet.layers[i]
    layer.trainable = false
    model.add(layer)
  }
  model.add(tf.layers.flatten())
  model.add(tf.layers.dense({
    units: 10,
    activation: 'relu'
  }))
  model.add(tf.layers.dense({
    units: classes.length,
    activation: 'softmax'
  }))
  // 训练模型
  model.compile({
    loss: 'sparseCategoricalCrossentropy',
    optimizer: tf.train.adam(),
    metrics: ['acc']
  })
  await model.fitDataset(ds, { epochs: 20 })
  await model.save(`file://${process.cwd()}/${OUTPUT_DIR}`)
}
main()

data.js(处理数据)

const fs = require('fs')
const tf = require('@tensorflow/tfjs-node')

const img2x = (imgPath) => {
  const buffer = fs.readFileSync(imgPath)
  return tf.tidy(() => {
    const imgTs = tf.node.decodeImage(new Uint8Array(buffer))
    const imgTsResized = tf.image.resizeBilinear(imgTs, [224, 224])
    return imgTsResized.toFloat().sub(255/2).div(255/2).reshape([1, 224, 224, 3])
  })
}

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

  const data = []
  classes.forEach((dir, dirIndex) => {
    fs.readdirSync(`${trainDir}/${dir}`)
      .filter(n => n.match(/jpg$/))
      .slice(0, 10)
      .forEach(filename => {
        console.log('读取', dir, filename)
        const imgPath = `${trainDir}/${dir}/${filename}`
        data.push({ imgPath, dirIndex })
      })
  })

  tf.util.shuffle(data)

  const ds = tf.data.generator(function* () {
    const count = data.length
    const batchSize = 32
    for (let start = 0; start < count; start += batchSize) {
      const end = Math.min(start + batchSize, count)
      yield tf.tidy(() => {
        const inputs = []
        const labels = []
        for (let j = start; j < end; j += 1) {
          const { imgPath, dirIndex } = data[j]
          const x = img2x(imgPath)
          inputs.push(x)
          labels.push(dirIndex)
        }
        const xs = tf.concat(inputs)
        const ys = tf.tensor(labels)
        return { xs, ys }
      })
    }
  })

  return {
    ds,
    classes
  }
}

module.exports = getData

安装一些运行项目需要的插件 如何利用React实现图片识别App

app 文件夹

import React, { PureComponent } from 'react'
import { Button, Progress, Spin, Empty } from 'antd'
import 'antd/dist/antd.css'
import * as tf from '@tensorflow/tfjs'
import { file2img, img2x } from './utils'
import intro from './intro'

const DATA_URL = 'http://127.0.0.1:8080/'
class App extends PureComponent {
  state = {}
  async componentDidMount() {
    this.model = await tf.loadLayersModel(DATA_URL + '/model.json')
    // this.model.summary()
    this.CLASSES = await fetch(DATA_URL + '/classes.json').then(res => res.json())
  }
  predict = async (file) => {
    const img = await file2img(file)

    this.setState({
      imgSrc: img.src,
      isLoading: true
    })
    setTimeout(() => {
      const pred = tf.tidy(() => {
        const x = img2x(img)
        return this.model.predict(x)
      })

      const results = pred.arraySync()[0]
        .map((score, i) => ({score, label: this.CLASSES[i]}))
        .sort((a, b) => b.score - a.score)
      this.setState({
        results,
        isLoading: false
      })
    }, 0)
  }

  renderResult = (item) => {
    const finalScore = Math.round(item.score * 100)
    return (
      <tr key={item.label}>
        <td style={{ width: 80, padding: '5px 0' }}>{item.label}</td>
        <td>
          <Progress percent={finalScore} status={finalScore === 100 ? 'success' : 'normal'} />
        </td>
      </tr>
    )
  }

  render() {
    const { imgSrc, results, isLoading } = this.state
    const finalItem = results && {...results[0], ...intro[results[0].label]}

    return (
      <div style={{padding: 20}}>
        <span
          style={{ color: '#cccccc', textAlign: 'center', fontSize: 12, display: 'block' }}
        >识别可能不准确</span>
        <Button
          type="primary"
          size="large"
          style={{width: '100%'}}
          onClick={() => this.upload.click()}
        >
          选择图片识别
        </Button>
        <input
          type="file"
          onChange={e => this.predict(e.target.files[0])}
          ref={el => {this.upload = el}}
          style={{ display: 'none' }}
        />
        {
          !results && !imgSrc && <Empty style={{ marginTop: 40 }} />
        }
        {imgSrc && <div style={{ marginTop: 20, textAlign: 'center' }}>
          <img src={imgSrc} style={{ maxWidth: '100%' }} />
        </div>}
        {finalItem && <div style={{marginTop: 20}}>识别结果: </div>}
        {finalItem && <div style={{display: 'flex', alignItems: 'flex-start', marginTop: 20}}>
          <img
            src={finalItem.icon}
            width={120}
          />
          <div>
            <h2 style={{color: finalItem.color}}>
              {finalItem.label}
            </h2>
            <div style={{color: finalItem.color}}>
              {finalItem.intro}
            </div>
          </div>
        </div>}
        {
          isLoading && <Spin size="large" style={{display: 'flex', justifyContent: 'center', alignItems: 'center', marginTop: 40 }} />
        }
        {results && <div style={{ marginTop: 20 }}>
          <table style={{width: '100%'}}>
            <tbody>
              <tr>
                <td>类别</td>
                <td>匹配度</td>
              </tr>
              {results.map(this.renderResult)}
            </tbody>
          </table>
        </div>}
      </div>
    )
  }
}

export default App

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>垃圾分类</title>
    <meta name="viewport" content="width=device-width, inital-scale=1">
  </head>
  <body>
    <div id="app"></div>
    <script src="./index.js"></script>
  </body>
</html>

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

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

intro.js

export default {
  '可回收物': {
    icon: 'https://lajifenleiapp.com/static/svg/1_3F6BA8.svg',
    color: '#3f6ba8',
    intro: '是指在日常生活中或者为日常生活提供服务的活动中产生的,已经失去原有全部或者部分使用价值,回收后经过再加工可以成为生产原料或者经过整理可以再利用的物品,包括废纸类、塑料类、玻璃类、金属类、织物类等。'
  },
  '有害垃圾': {
    icon: 'https://lajifenleiapp.com/static/svg/2v_B43953.svg',
    color: '#b43953',
    intro: '是指生活垃圾中对人体健康或者自然环境造成直接或者潜在危害的物质,包括废充电电池、废扣式电池、废灯管、弃置药品、废杀虫剂(容器)、废油漆(容器)、废日用化学品、废水银产品、废旧电器以及电子产品等。'
  },
  '厨余垃圾': {
    icon: 'https://lajifenleiapp.com/static/svg/3v_48925B.svg',
    color: '#48925b',
    intro: '是指居民日常生活中产生的有机易腐垃圾,包括菜叶、剩菜、剩饭、果皮、蛋壳、茶渣、骨头等。'
  },
  '其他垃圾': {
    icon: 'https://lajifenleiapp.com/static/svg/4_89918B.svg',
    color: '#89918b',
    intro: '是指除可回收物、有害垃圾和厨余垃圾之外的,混杂、污染、难分类的其他生活垃圾。'
  }
}

utils.js

import * as tf from '@tensorflow/tfjs'

export const file2img = async (f) => {
  return new Promise(reslove => {
    const reader = new FileReader()
    reader.readAsDataURL(f)
    reader.onload = (e) => {
      const img = document.createElement('img')
      img.src = e.target.result
      img.width = 224
      img.height = 224
      img.onload = () => { reslove(img) }
    }
  })
}

export function img2x(imgEl) {
  return tf.tidy(() => {
    return 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实现图片识别App的文章就介绍到这了,更多相关React图片识别App内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
基于Jquery插件开发之图片放大镜效果(仿淘宝)
Nov 19 Javascript
jQuery(非HTML5)可编辑表格实现代码
Dec 11 Javascript
Jquery实现搜索框提示功能示例代码
Aug 13 Javascript
javascript中的this详解
Dec 08 Javascript
javascript字符串函数汇总
Dec 06 Javascript
JavaScript Promise 用法
Jun 14 Javascript
浅谈javascript运算符——条件,逗号,赋值,()和void运算符
Jul 15 Javascript
41个Web开发者必须收藏的JavaScript实用技巧
Jul 22 Javascript
浅谈JavaScript 数据属性和访问器属性
Sep 01 Javascript
使用JQuery选择HTML遍历函数的方法
Sep 17 Javascript
Angularjs使用ng-repeat中$even和$odd属性的注意事项
Dec 31 Javascript
Electron + vue 打包桌面操作流程详解
Jun 24 Javascript
JavaScript展开运算符和剩余运算符的区别详解
Feb 18 #Javascript
微信小程序中使用vant框架的具体步骤
Vue elementUI表单嵌套表格并对每行进行校验详解
Feb 18 #Vue.js
微信小程序中wxs文件的一些妙用分享
Feb 18 #Javascript
vue项目支付功能代码详解
Feb 18 #Vue.js
JavaScript的Set数据结构详解
Feb 18 #Javascript
JS封装cavans多种滤镜组件
You might like
一篇入门的php Class 文章
2007/04/04 PHP
关于zend studio 出现乱码问题的总结
2013/06/23 PHP
php强制下载文件函数
2016/08/24 PHP
jquery text,radio,checkbox,select操作实现代码
2009/07/09 Javascript
JQery jstree 大数据量问题解决方法
2010/03/09 Javascript
qq悬浮代码(兼容各个浏览器)
2014/01/29 Javascript
JavaScript fontsize方法入门实例(按照指定的尺寸来显示字符串)
2014/10/17 Javascript
JavaScript实现Flash炫光波动特效
2015/05/14 Javascript
JS处理json日期格式化问题
2015/10/01 Javascript
Angular使用动态加载组件方法实现Dialog的示例
2018/05/11 Javascript
Vue源码解析之Template转化为AST的实现方法
2018/12/14 Javascript
解决mui框架中switch开关通过js控制开或者关状态时小圆点不动的问题
2019/09/03 Javascript
layui对工具条进行选择性的显示方法
2019/09/19 Javascript
vue跳转同一个组件,参数不同,页面接收值只接收一次的解决方法
2019/11/05 Javascript
js Math数学简单使用操作示例
2020/03/13 Javascript
微信小程序实现上拉加载功能示例【加载更多数据/触底加载/点击加载更多数据】
2020/05/29 Javascript
[05:15]DOTA2英雄梦之声_第16期_灰烬之灵
2014/06/21 DOTA
[03:08]Ti4观战指南上
2014/07/07 DOTA
[01:11:48]Fnatic vs IG 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/18 DOTA
python 简易计算器程序,代码就几行
2009/08/29 Python
python通过pil为png图片填充上背景颜色的方法
2015/03/17 Python
Python连接SQLServer2000的方法详解
2017/04/19 Python
Python检测网络延迟的代码
2018/05/15 Python
浅谈Django的缓存机制
2018/08/23 Python
基于Django的乐观锁与悲观锁解决订单并发问题详解
2019/07/31 Python
python批量处理txt文件的实例代码
2020/01/13 Python
Jupyter notebook运行Spark+Scala教程
2020/04/10 Python
python print 格式化输出,动态指定长度的实现
2020/04/12 Python
python如何保存文本文件
2020/06/07 Python
印度最大的旅游网站:MakeMyTrip
2016/10/05 全球购物
澳大利亚Mocha官方网站:包、钱包、珠宝和配饰
2019/07/18 全球购物
英国玛莎百货新西兰:Marks & Spencer New Zealand
2019/07/21 全球购物
意大利领先的奢侈品在线时装零售商:MCLABELS
2020/10/13 全球购物
2016暑期社会实践新闻稿
2015/11/25 职场文书
56句经典英文座右铭
2019/08/09 职场文书
WinServer2012搭建DNS服务器的方法步骤
2022/06/10 Servers