开发者问题收集

响应上传图片并设置新的 ref

2020-10-10
834

我想上传一张图片,显示预览,并将其用于 mobilenet 机器学习模型中,据我了解,这需要我将它作为参考。因此,我希望:

  1. 上传图片
  2. 设置引用
  3. 使用该引用作为预览
  4. 在 ML 模型中使用该引用

我可以像这样上传图片(没有问题):

const UploadButton = ({ handleNewFile, text }) => (
  <label htmlFor='upload-file'>
    <input style={{ display: 'none' }} id='upload-file' name='upload-file' type='file' accept='image/*' onChange={handleNewFile} />
    <Fab variant='extended' color='primary' style={{ marginBottom: '.5rem' }} component='span'>
      <UploadIcon />
      {text}
    </Fab>
  </label>
)

我的句柄更改:

const handleNewFile = e => {
    const [file] = e.target.files

    console.log('file', file)

    // this settting fileRef.current doesn't work, it's not the element like I need
    fileRef.current = file

    // mobile net model
    model.classify(fileRef.current).then(pred => {
      setPrediction(pred[0].className)
    })
  }

我最初为图片设置了 src,但没有上传功能,并且没有问题,但现在我需要允许用户上传,我不知道如何在上传后正确设置此引用。

<img ref={fileRef} />

如何在上传后设置引用?

1个回答

答案: 不要使用 refs,你不需要

我在下面粘贴了整个代码,但总而言之,使用 new FileReader()new Image() 并从 img.onLoad 函数中的 this 对象中访问它。

import React, { useState, useEffect } from 'react'
import { Grid, Typography, Fab } from '@material-ui/core'
import { Loading } from 'Components/QueryHandling'
import UploadIcon from '@material-ui/icons/Publish'

const UploadButton = ({ handleNewFile, text }) => (
  <label htmlFor='upload-file'>
    <input style={{ display: 'none' }} id='upload-file' name='upload-file' type='file' accept='image/*' onChange={handleNewFile} />
    <Fab variant='extended' color='primary' style={{ margin: '1em' }} component='span'>
      <UploadIcon />
      {text}
    </Fab>
  </label>
)

const ImageThumb = ({ image }) => {
  return <img src={URL.createObjectURL(image)} alt={image.name} style={{ margin: '2rem', maxHeight: 300 }} />
}

const Prediction = ({ className, probability }) => (
  <Typography variant='body1'>
    {className} ({Math.round(probability * 100)}%){' '}
  </Typography>
)

export default function Predictor({ content }) {
  const [model, setModel] = useState(null)
  const [img, setImg] = useState(null)
  const [modelLoaded, setModelLoaded] = useState(false)
  const [predictions, setPredictions] = useState(null)
  const headerText = modelLoaded ? (Array.isArray(predictions) ? 'Results' : 'Upload Image') : 'Loading Model'
  const uploadText = Array.isArray(predictions) ? 'Upload New Image' : 'Upload Image'

  useEffect(() => {
    const loadMobileNet = async () => {
      if (window.mobilenet) {
        const net = await window.mobilenet.load()
        setModel(net)
        setModelLoaded(true)
      } else {
        setTimeout(loadMobileNet(), 1000)
      }
    }
    loadMobileNet()
  }, [])

  const classifyImage = async file => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader()

      reader.onload = function(e) {
        const img = new Image()
        img.src = e.target.result

        img.onload = function() {
          const w = this.width
          const h = this.height

          model.classify(this).then(preds => {
            setPredictions(preds)
          })
          // optionally resolve height and width
          resolve([h, w])
        }
      }

      reader.readAsDataURL(file)
    })
  }
  const handleNewFile = e => {
    const [file] = e.target.files
    setImg(file)
    classifyImage(file)
  }

  return (
    <Grid>
      <Typography variant='h3' align='center'>
        {headerText}
      </Typography>
      {img && <ImageThumb image={img} />}
      {Array.isArray(predictions) && predictions.map((p, i) => <Prediction key={i} {...p} />)}
      {modelLoaded ? <UploadButton handleNewFile={handleNewFile} text={uploadText} /> : <Loading />}
    </Grid>
  )
}
Kevin Danikowski
2020-10-12