如何利用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 相关文章推荐
js电信网通双线自动选择技巧
Nov 18 Javascript
JavaScript Event学习第四章 传统的事件注册模型
Feb 07 Javascript
jQuery获取节点和子节点文本的方法
Jul 22 Javascript
JavaScript笔记之数据属性和存储器属性
Mar 31 Javascript
jQuery+ajax实现滚动到页面底部自动加载图文列表效果(类似图片懒加载)
Jun 07 Javascript
Javascript 跨域知识详细介绍
Oct 30 Javascript
vue2.0实战之基础入门(1)
Mar 27 Javascript
js获取地址栏参数的两种方法
Jun 27 Javascript
浅析java线程中断的办法
Jul 29 Javascript
JS中Promise函数then的奥秘探究
Jul 30 Javascript
vue axios 简单封装以及思考
Oct 09 Javascript
react国际化react-intl的使用
May 06 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
一个基于PDO的数据库操作类
2011/03/24 PHP
PHP 图片上传代码
2011/09/13 PHP
php找出指定范围内回文数且平方根也是回文数的方法
2015/03/23 PHP
PHP 文件上传后端处理实用技巧方法
2017/01/06 PHP
for 循环性能比较 提高for循环的效率
2009/03/19 Javascript
Jquery 弹出层插件实现代码
2009/10/24 Javascript
jquery 实现两级导航菜单附效果图
2014/03/07 Javascript
javascript 自定义回调函数示例代码
2014/09/26 Javascript
webapp框架AngularUI的demo改造之路
2014/12/21 Javascript
JavaScript判断一个字符串是否包含指定子字符串的方法
2015/03/18 Javascript
理解javascript异步编程
2016/01/27 Javascript
JavaScript截屏功能的实现代码
2017/07/28 Javascript
解决vue 格式化银行卡(信用卡)每4位一个符号隔断的问题
2018/09/14 Javascript
微信小程序一周时间表功能实现
2019/10/17 Javascript
浅析js实现网页截图的两种方式
2019/11/01 Javascript
JavaScript进阶(一)变量声明提升实例分析
2020/05/09 Javascript
详解JavaScript作用域、作用域链和闭包的用法
2020/09/03 Javascript
vue 使用 v-model 双向绑定父子组件的值遇见的问题及解决方案
2021/03/01 Vue.js
python获取Linux下文件版本信息、公司名和产品名的方法
2014/10/05 Python
在Python中执行系统命令的方法示例详解
2017/09/14 Python
python读取文本中数据并转化为DataFrame的实例
2018/04/10 Python
Django 忘记管理员或忘记管理员密码 重设登录密码的方法
2018/05/30 Python
替换python字典中的key值方法
2018/07/06 Python
Python 循环终止语句的三种方法小结
2019/06/24 Python
Python终端输出彩色字符方法详解
2020/02/11 Python
python mock测试的示例
2020/10/19 Python
Fresh馥蕾诗英国官网:法国LVMH集团旗下高端天然护肤品牌
2018/11/01 全球购物
英国女鞋购物网站:Moda in Pelle
2019/02/18 全球购物
会计找工作求职信范文
2013/12/09 职场文书
网络维护中文求职信
2014/01/03 职场文书
致百米运动员广播稿
2014/01/29 职场文书
思想品德自我评价
2014/02/04 职场文书
书香校园活动方案
2014/02/28 职场文书
大学生违纪检讨书300字
2014/10/25 职场文书
档案工作个人总结
2015/03/03 职场文书
Java中的继承、多态以及封装
2022/04/11 Java/Android