• 售前

  • 售后

热门帖子
入门百科

怎样使用React实现图片辨认App

[复制链接]
我心如烟卸 显示全部楼层 发表于 2022-1-8 06:00:50 |阅读模式 打印 上一主题 下一主题
先把结果图给各人放上来



个人以为结果还行。识别不太准确是因为这个 app学习图片的时间太短(电脑太卡)。
(笔者是 window10) 安装运行环境:

    1. npm install --global windows-build-tools
    复制代码
    (这个时间很漫长。。。)
    1. npm install @tensorflow/tfjs-node
    复制代码
    (这个时间很漫长。。。)
项目目次如下
train文件夹 index.js(入口文件)
  1. const tf = require('@tensorflow/tfjs-node')
  2. const getData = require('./data')
  3. const TRAIN_DIR = '../垃圾分类/train'
  4. const OUTPUT_DIR = '../outputDir'
  5. const MOBILENET_URL = 'http://ai-sample.oss-cn-hangzhou.aliyuncs.com/pipcook/models/mobilenet/web_model/model.json'
  6. const main = async () => {
  7.   // 加载数据
  8.   const { ds, classes} = await getData(TRAIN_DIR, OUTPUT_DIR)
  9.   // 定义模型
  10.   const mobilenet = await tf.loadLayersModel(MOBILENET_URL)
  11.   mobilenet.summary()
  12.   // console.log(mobilenet.layers.map((l, i) => [l.name, i]))
  13.   const model = tf.sequential()
  14.   for (let i = 0; i <= 86; i += 1) {
  15.     const layer = mobilenet.layers[i]
  16.     layer.trainable = false
  17.     model.add(layer)
  18.   }
  19.   model.add(tf.layers.flatten())
  20.   model.add(tf.layers.dense({
  21.     units: 10,
  22.     activation: 'relu'
  23.   }))
  24.   model.add(tf.layers.dense({
  25.     units: classes.length,
  26.     activation: 'softmax'
  27.   }))
  28.   // 训练模型
  29.   model.compile({
  30.     loss: 'sparseCategoricalCrossentropy',
  31.     optimizer: tf.train.adam(),
  32.     metrics: ['acc']
  33.   })
  34.   await model.fitDataset(ds, { epochs: 20 })
  35.   await model.save(`file://${process.cwd()}/${OUTPUT_DIR}`)
  36. }
  37. main()
复制代码
data.js(处理数据)
  1. const fs = require('fs')
  2. const tf = require('@tensorflow/tfjs-node')
  3. const img2x = (imgPath) => {
  4.   const buffer = fs.readFileSync(imgPath)
  5.   return tf.tidy(() => {
  6.     const imgTs = tf.node.decodeImage(new Uint8Array(buffer))
  7.     const imgTsResized = tf.image.resizeBilinear(imgTs, [224, 224])
  8.     return imgTsResized.toFloat().sub(255/2).div(255/2).reshape([1, 224, 224, 3])
  9.   })
  10. }
  11. const getData = async (trainDir, outputDir) => {
  12.   const classes = fs.readdirSync(trainDir)
  13.   fs.writeFileSync(`${outputDir}/classes.json`, JSON.stringify(classes))
  14.   const data = []
  15.   classes.forEach((dir, dirIndex) => {
  16.     fs.readdirSync(`${trainDir}/${dir}`)
  17.       .filter(n => n.match(/jpg$/))
  18.       .slice(0, 10)
  19.       .forEach(filename => {
  20.         console.log('读取', dir, filename)
  21.         const imgPath = `${trainDir}/${dir}/${filename}`
  22.         data.push({ imgPath, dirIndex })
  23.       })
  24.   })
  25.   tf.util.shuffle(data)
  26.   const ds = tf.data.generator(function* () {
  27.     const count = data.length
  28.     const batchSize = 32
  29.     for (let start = 0; start < count; start += batchSize) {
  30.       const end = Math.min(start + batchSize, count)
  31.       yield tf.tidy(() => {
  32.         const inputs = []
  33.         const labels = []
  34.         for (let j = start; j < end; j += 1) {
  35.           const { imgPath, dirIndex } = data[j]
  36.           const x = img2x(imgPath)
  37.           inputs.push(x)
  38.           labels.push(dirIndex)
  39.         }
  40.         const xs = tf.concat(inputs)
  41.         const ys = tf.tensor(labels)
  42.         return { xs, ys }
  43.       })
  44.     }
  45.   })
  46.   return {
  47.     ds,
  48.     classes
  49.   }
  50. }
  51. module.exports = getData
复制代码
安装一些运行项目必要的插件
app 文件夹
  1. import React, { PureComponent } from 'react'
  2. import { Button, Progress, Spin, Empty } from 'antd'
  3. import 'antd/dist/antd.css'
  4. import * as tf from '@tensorflow/tfjs'
  5. import { file2img, img2x } from './utils'
  6. import intro from './intro'
  7. const DATA_URL = 'http://127.0.0.1:8080/'
  8. class App extends PureComponent {
  9.   state = {}
  10.   async componentDidMount() {
  11.     this.model = await tf.loadLayersModel(DATA_URL + '/model.json')
  12.     // this.model.summary()
  13.     this.CLASSES = await fetch(DATA_URL + '/classes.json').then(res => res.json())
  14.   }
  15.   predict = async (file) => {
  16.     const img = await file2img(file)
  17.     this.setState({
  18.       imgSrc: img.src,
  19.       isLoading: true
  20.     })
  21.     setTimeout(() => {
  22.       const pred = tf.tidy(() => {
  23.         const x = img2x(img)
  24.         return this.model.predict(x)
  25.       })
  26.       const results = pred.arraySync()[0]
  27.         .map((score, i) => ({score, label: this.CLASSES[i]}))
  28.         .sort((a, b) => b.score - a.score)
  29.       this.setState({
  30.         results,
  31.         isLoading: false
  32.       })
  33.     }, 0)
  34.   }
  35.   renderResult = (item) => {
  36.     const finalScore = Math.round(item.score * 100)
  37.     return (
  38.       <tr key={item.label}>
  39.         <td style={{ width: 80, padding: '5px 0' }}>{item.label}</td>
  40.         <td>
  41.           <Progress percent={finalScore} status={finalScore === 100 ? 'success' : 'normal'} />
  42.         </td>
  43.       </tr>
  44.     )
  45.   }
  46.   render() {
  47.     const { imgSrc, results, isLoading } = this.state
  48.     const finalItem = results && {...results[0], ...intro[results[0].label]}
  49.     return (
  50.       <div style={{padding: 20}}>
  51.         <span
  52.           style={{ color: '#cccccc', textAlign: 'center', fontSize: 12, display: 'block' }}
  53.         >识别可能不准确</span>
  54.         <Button
  55.           type="primary"
  56.           size="large"
  57.           style={{width: '100%'}}
  58.           onClick={() => this.upload.click()}
  59.         >
  60.           选择图片识别
  61.         </Button>
  62.         <input
  63.           type="file"
  64.           onChange={e => this.predict(e.target.files[0])}
  65.           ref={el => {this.upload = el}}
  66.           style={{ display: 'none' }}
  67.         />
  68.         {
  69.           !results && !imgSrc && <Empty style={{ marginTop: 40 }} />
  70.         }
  71.         {imgSrc && <div style={{ marginTop: 20, textAlign: 'center' }}>
  72.           <img src={imgSrc} style={{ maxWidth: '100%' }} />
  73.         </div>}
  74.         {finalItem && <div style={{marginTop: 20}}>识别结果: </div>}
  75.         {finalItem && <div style={{display: 'flex', alignItems: 'flex-start', marginTop: 20}}>
  76.           <img
  77.             src={finalItem.icon}
  78.             width={120}
  79.           />
  80.           <div>
  81.             <h2 style={{color: finalItem.color}}>
  82.               {finalItem.label}
  83.             </h2>
  84.             <div style={{color: finalItem.color}}>
  85.               {finalItem.intro}
  86.             </div>
  87.           </div>
  88.         </div>}
  89.         {
  90.           isLoading && <Spin size="large" style={{display: 'flex', justifyContent: 'center', alignItems: 'center', marginTop: 40 }} />
  91.         }
  92.         {results && <div style={{ marginTop: 20 }}>
  93.           <table style={{width: '100%'}}>
  94.             <tbody>
  95.               <tr>
  96.                 <td>类别</td>
  97.                 <td>匹配度</td>
  98.               </tr>
  99.               {results.map(this.renderResult)}
  100.             </tbody>
  101.           </table>
  102.         </div>}
  103.       </div>
  104.     )
  105.   }
  106. }
  107. export default App
复制代码
index.html
  1. <!DOCTYPE html>
  2. <html>
  3.   <head>
  4.     <title>垃圾分类</title>
  5.     <meta name="viewport" content="width=device-width, inital-scale=1">
  6.   </head>
  7.   <body>
  8.     <div id="app"></div>
  9.     <script src="./index.js"></script>
  10.   </body>
  11. </html>
复制代码
index.js
  1. import React from 'react'
  2. import ReactDOM from 'react-dom'
  3. import App from './App'
  4. ReactDOM.render(<App />, document.querySelector('#app'))
复制代码
intro.js
  1. export default {
  2.   '可回收物': {
  3.     icon: 'https://lajifenleiapp.com/static/svg/1_3F6BA8.svg',
  4.     color: '#3f6ba8',
  5.     intro: '是指在日常生活中或者为日常生活提供服务的活动中产生的,已经失去原有全部或者部分使用价值,回收后经过再加工可以成为生产原料或者经过整理可以再利用的物品,包括废纸类、塑料类、玻璃类、金属类、织物类等。'
  6.   },
  7.   '有害垃圾': {
  8.     icon: 'https://lajifenleiapp.com/static/svg/2v_B43953.svg',
  9.     color: '#b43953',
  10.     intro: '是指生活垃圾中对人体健康或者自然环境造成直接或者潜在危害的物质,包括废充电电池、废扣式电池、废灯管、弃置药品、废杀虫剂(容器)、废油漆(容器)、废日用化学品、废水银产品、废旧电器以及电子产品等。'
  11.   },
  12.   '厨余垃圾': {
  13.     icon: 'https://lajifenleiapp.com/static/svg/3v_48925B.svg',
  14.     color: '#48925b',
  15.     intro: '是指居民日常生活中产生的有机易腐垃圾,包括菜叶、剩菜、剩饭、果皮、蛋壳、茶渣、骨头等。'
  16.   },
  17.   '其他垃圾': {
  18.     icon: 'https://lajifenleiapp.com/static/svg/4_89918B.svg',
  19.     color: '#89918b',
  20.     intro: '是指除可回收物、有害垃圾和厨余垃圾之外的,混杂、污染、难分类的其他生活垃圾。'
  21.   }
  22. }
复制代码
utils.js
  1. import * as tf from '@tensorflow/tfjs'
  2. export const file2img = async (f) => {
  3.   return new Promise(reslove => {
  4.     const reader = new FileReader()
  5.     reader.readAsDataURL(f)
  6.     reader.onload = (e) => {
  7.       const img = document.createElement('img')
  8.       img.src = e.target.result
  9.       img.width = 224
  10.       img.height = 224
  11.       img.onload = () => { reslove(img) }
  12.     }
  13.   })
  14. }
  15. export function img2x(imgEl) {
  16.   return tf.tidy(() => {
  17.     return tf.browser.fromPixels(imgEl)
  18.         .toFloat().sub(255/2).div(255/2)
  19.         .reshape([1, 224, 224, 3])
  20.   })
  21. }
复制代码
运行项目代码之前,我们必要先在 train 目次下运行,node index.js,生成 model.json 以供识别体系利用。之后必要在根目次下运行 hs outputDir --cors, 使得生成的 model.json 运行在 http 环境下,之后才可以运行 npm start ,否则项目是会报错的。
重要的代码就是上面这些。前面笔者也说了。自己对这方面完全不懂,以是也无法讲授其中的代码。各位感兴趣就自己研究一下。代码地点奉上。
gitee.com/suiboyu/gar…

总结
到此这篇关于怎样利用React实现图片识别App的文章就先容到这了,更多相干React图片识别App内容请搜索草根技术分享以前的文章或继承欣赏下面的相干文章希望各人以后多多支持草根技术分享!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作