如何利用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 相关文章推荐
SUN的《AJAX与J2EE》全文译了
Feb 23 Javascript
Javascript 圆角div的实现代码
Oct 15 Javascript
基于JQuery的数字改变的动画效果--可用来做计数器
Aug 11 Javascript
jquery蒙版控件实现代码
Dec 08 Javascript
javascript (用setTimeout而非setInterval)
Dec 28 Javascript
JS实现超简单的仿QQ折叠菜单效果
Sep 21 Javascript
javascript精确统计网站访问量实例代码
Dec 19 Javascript
Bootstrap实现登录校验表单(带验证码)
Jun 23 Javascript
在Vue.js中使用Mixins的方法
Sep 12 Javascript
jQuery控制input只能输入数字和两位小数的方法
May 16 jQuery
jquery向后台提交数组的代码分析
Feb 20 jQuery
JS co 函数库的含义和用法实例总结
Apr 08 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中通过ADO调用Access数据库的方法测试不通过
2006/12/31 PHP
推荐Discuz!5的PHP代码高亮显示与实现可运行代码
2007/03/15 PHP
PHP设计模式之调解者模式的深入解析
2013/06/13 PHP
ThinkPHP多表联合查询的常用方法
2020/03/24 PHP
PHP读取word文档的方法分析【基于COM组件】
2017/08/01 PHP
laravel5.6中的外键约束示例
2019/10/23 PHP
JS实现图片横向滚动效果示例代码
2013/09/04 Javascript
控制input输入框中提示信息的显示和隐藏的方法
2014/02/12 Javascript
创建js对象和js类的方法汇总
2014/12/24 Javascript
解析javascript中鼠标滚轮事件
2015/05/26 Javascript
jQuery实现文本框输入同步的方法
2015/06/20 Javascript
jquery实现页面虚拟键盘特效
2015/08/08 Javascript
详解JavaScript中的构造器Constructor模式
2016/01/14 Javascript
使用jQuery.form.js/springmvc框架实现文件上传功能
2016/05/12 Javascript
Bootstrap实现导航栏的2种方式
2016/11/28 Javascript
jQuery实现页面滚动时智能浮动定位
2017/01/08 Javascript
取消Bootstrap的dropdown-menu点击默认关闭事件方法
2018/08/10 Javascript
解决vue-cli webpack打包后加载资源的路径问题
2018/09/25 Javascript
[01:13]DOTA2群星解读国服召集令 一起说出回归的理由
2013/07/17 DOTA
从零学Python之入门(三)序列
2014/05/25 Python
Windows中使用wxPython和py2exe开发Python的GUI程序的实例教程
2016/07/11 Python
Python基于递归和非递归算法求两个数最大公约数、最小公倍数示例
2018/05/21 Python
数组保存为txt, npy, csv 文件, 数组遍历enumerate的方法
2018/07/09 Python
python3实现表白神器
2019/04/09 Python
Python实现FM算法解析
2019/06/18 Python
Python爬虫 bilibili视频弹幕提取过程详解
2019/07/31 Python
如何分离django中的媒体、静态文件和网页
2019/11/12 Python
PyTorch中topk函数的用法详解
2020/01/02 Python
使用Keras画神经网络准确性图教程
2020/06/15 Python
Python logging日志库空间不足问题解决
2020/09/14 Python
美国瑜伽品牌:Gaiam
2017/10/31 全球购物
求∏的近似值,直到最后一项的绝对值小于指定的数
2016/02/12 面试题
房产转让协议书
2014/04/11 职场文书
小学音乐课歌曲《堆雪人》教学反思
2016/02/18 职场文书
高中物理教学反思
2016/02/19 职场文书
2019个人工作态度自我评价
2019/04/24 职场文书