使用IBM Watson进行人脸检测

时间:2018-06-03 20:48:30

标签: reactjs watson

我试图使用React制作一个简单的图像上传器并将其与IBM Watson集成以进行面部检测,只需在图像的面上绘制一个正方形。

所以,这是我的Index.js。



    import React from 'react';
import PropTypes from 'prop-types';
import './index.css';
import FlipMove from 'react-flip-move';
import UploadIcon from './UploadIcon.svg';

const VisualRecognitionV3 = require('watson-deve`enter code here`loper-cloud/visual-recognition/v3');
const visualRecognition = new VisualRecognitionV3({
  version: '2018-03-19',
  iam_apikey: '{j3YBm86Ep4cNupisk1a7xhcokOMpPO5LYHwdTJcjfw9k}'
});

const styles = {
	display: "flex",
	alignItems: "center",
	justifyContent: "center",
	flexWrap: "wrap",
	width: "100%"
};

class ReactImageUploadComponent extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			pictures: [],
            files: [],
            notAcceptedFileType: [],
			notAcceptedFileSize: []
		};
		this.inputElement = '';
		this.onDropFile = this.onDropFile.bi`enter code here`nd(this);
		this.triggerFileUpload = this.triggerFileUpload.bind(this);
	}

	/*
	 On button click, trigger input file to open
	 */
	triggerFileUpload() {
		this.inputElement.click();
	}

	/*
	 Handle file validation
	 */
	onDropFile(e, pictureFiles, pictureDataURLs) {
		const files = e.target.files;
		const _this = this;
		visualRecognition.detectFaces({image_file: pictureFiles[0]}, function(err, response){
            if (err){
                console.log(err);
            } else {
                console.log(JSON.stringify(response, null, 2));
            }
        });

		// Iterate over all uploaded files
		for (let i = 0; i < files.length; i++) {
      let f = files[i];
			// Check for file extension
			if (!this.hasExtension(f.name)) {
				const newArray = _this.state.notAcceptedFileType.slice();
				newArray.push(f.name);
				_this.setState({notAcceptedFileType: newArray});
				continue;
			}
			// Check for file size
			if(f.size > this.props.maxFileSize) {
				const newArray = _this.state.notAcceptedFileSize.slice();
				newArray.push(f.name);
				_this.setState({notAcceptedFileSize: newArray});
				continue;
			}

			const reader = new FileReader();
			// Read the image via FileReader API and save image result in state.
			reader.onload = (function () {
				return function (e) {
                    // Add the file name to the data URL
                    let dataURL = e.target.result;
                    dataURL = dataURL.replace(";base64", `;name=${f.name};base64`);

                    if (_this.props.singleImage === true) {
                        _this.setState({pictures: [dataURL], files: [f]}, () => {
                            _this.props.onChange(_this.state.files, _this.state.pictures);
                        });
                    } else if (_this.state.pictures.indexOf(dataURL) === -1) {
                        const newArray = _this.state.pictures.slice();
                        newArray.push(dataURL);

                        const newFiles = _this.state.files.slice();
                        newFiles.push(f);

                        _this.setState({pictures: newArray, files: newFiles}, () => {
                            _this.props.onChange(_this.state.files, _this.state.pictures);
                        });
                    }
				};
			})(f);
			reader.readAsDataURL(f);
		}
	}

  /*
   Render the upload icon
   */
  renderIcon() {
		if (this.props.withIcon) {
      return <img src={UploadIcon} className="uploadIcon"	alt="Upload Icon" />;
		}
	}

	/*
	 Render label
	 */
	renderLabel() {
		if (this.props.withLabel) {
		  return <p className={this.props.labelClass} style={this.props.labelStyles}>{this.props.label}</p>
		}
	}

  /*
	 Check file extension (onDropFile)
	 */
	hasExtension(fileName) {
        const pattern = '(' + this.props.imgExtension.join('|').replace(/\./g, '\\.') + ')$';
        return new RegExp(pattern, 'i').test(fileName);
	}

	/*
	 Remove the image from state
	 */
	removeImage(picture) {
        const removeIndex = this.state.pictures.findIndex(e => e === picture);
        const filteredPictures = this.state.pictures.filter((e, index) => index !== removeIndex);
        const filteredFiles = this.state.files.filter((e, index) => index !== removeIndex);

        this.setState({pictures: filteredPictures, files: filteredFiles}, () => {
            this.props.onChange(this.state.files, this.state.pictures);
        });
	}

	/*
	 Check if any errors && render
	 */
	renderErrors() {
		let notAccepted = '';
		if (this.state.notAcceptedFileType.length > 0) {
			notAccepted = this.state.notAcceptedFileType.map((error, index) => {
				return (
					<div className={'errorMessage ' + this.props.errorClass} key={index} style={this.props.errorStyle}>
						* {error} {this.props.fileTypeError}
					</div>
				)
			});
		}
		if (this.state.notAcceptedFileSize.length > 0) {
			notAccepted = this.state.notAcceptedFileSize.map((error, index) => {
				return (
					<div className={'errorMessage ' + this.props.errorClass} key={index} style={this.props.errorStyle}>
						* {error} {this.props.fileSizeError}
					</div>
				)
			});
		}
		return notAccepted;
	}

	/*
	 Render preview images
	 */
	renderPreview() {
		return (
			<div className="uploadPicturesWrapper">
				<FlipMove enterAnimation="fade" leaveAnimation="fade" style={styles}>
					{this.renderPreviewPictures()}
				</FlipMove>
			</div>
		);
	}

	renderPreviewPictures() {
		return this.state.pictures.map((picture, index) => {
			return (
				<div key={index} className="uploadPictureContainer">
					<div className="deleteImage" onClick={() => this.removeImage(picture)}>X</div>
					<img src={picture} className="uploadPicture" alt="preview"/>
				</div>
			);
		});
	}

	render() {
		return (
			<div className={"fileUploader " + this.props.className} style={this.props.style}>
				<div className="fileContainer">
					{this.renderIcon()}
					{this.renderLabel()}
					<div className="errorsContainer">
						{this.renderErrors()}
					</div>
					<button
                        type={this.props.buttonType}
						className={"chooseFileButton " + this.props.buttonClassName}
						style={this.props.buttonStyles}
						onClick={this.triggerFileUpload}
					>
                        {this.props.buttonText}
					</button>
					<input
						type="file"
						ref={input => this.inputElement = input}
						name={this.props.name}
						multiple="multiple"
						onChange={this.onDropFile}
						accept={this.props.accept}
					/>
					{ this.props.withPreview ? this.renderPreview() : null }
				</div>
			</div>
		)
	}
}

ReactImageUploadComponent.defaultProps = {
	className: '',
	buttonClassName: "",
	buttonStyles: {},
	withPreview: false,
	accept: "image/*",
	name: "",
	withIcon: true,
	buttonText: "Escolher Imagem",
    buttonType: "submit",
	withLabel: true,
	label: "Tamanho máximo de arquivo: 5mb, formatos aceitos: jpg,gif,png",
	labelStyles: {},
	labelClass: "",
	imgExtension: ['.jpg', '.gif', '.png'],
	maxFileSize: 5242880,
	fileSizeError: " arquivo muito grande",
	fileTypeError: " extenção de arquivo não suportada",
	errorClass: "",
	style: {},
	errorStyle: {},
	singleImage: false,
    onChange: () => {}
};

ReactImageUploadComponent.propTypes = {
	style: PropTypes.object,
	className: PropTypes.string,
	onChange: PropTypes.func,
  onDelete: PropTypes.func,
	buttonClassName: PropTypes.string,
	buttonStyles: PropTypes.object,
    buttonType: PropTypes.string,
	withPreview: PropTypes.bool,
	accept: PropTypes.string,
	name: PropTypes.string,
	withIcon: PropTypes.bool,
	buttonText: PropTypes.string,
	withLabel: PropTypes.bool,
	label: PropTypes.string,
	labelStyles: PropTypes.object,
	labelClass: PropTypes.string,
	imgExtension: PropTypes.array,
	maxFileSize: PropTypes.number,
	fileSizeError: PropTypes.string,
	fileTypeError: PropTypes.string,
	errorClass: PropTypes.string,
	errorStyle: PropTypes.object,
  singleImage: PropTypes.bool
};

export default ReactImageUploadComponent;
&#13;
&#13;
&#13;

我已经尝试过一些来自网络的教程和示例,但没有成功。 问题是,我如何应用Watson在上传图像的表面周围画一个正方形?

1 个答案:

答案 0 :(得分:0)

1)我不知道你试图用const steps做什么,但它没有任何意义。您的React应用程序中不需要npm install命令。我也没有看到在字符串中包含一堆JavaScript的任何目的。

2)在您使用App组件底部的实际ImageUploader课程内部,您没有按照上面steps的建议进行操作,并且包括onChange方法。从我在ImageUploader组件文档中可以看到的内容,就是您在用户上传图像后用于执行某个操作的内容。

3)您尚未尝试将IBM Watson API实际集成到此代码中。显然,这将是实现既定目标的关键一步。在发布问题之前,你应该自己做一个真诚的尝试。

无论如何,您需要做的基本想法是,在用户上传图片后,您向Watson的图片识别API发出API请求:https://www.ibm.com/watson/developercloud/visual-recognition/api/v3/node.html?node#detect-faces

您需要与他们建立一个帐户并获取开发人员密钥(对于极少数的请求,它应该是免费的)。然后,您将要使用npm install --save watson-developer-cloud安装他们的API(注意:正如我上面提到的,这不属于您的代码,就像您现在所拥有的;这意味着要从您的终端/ shell运行项目目录。

在文件的顶部,您将包含SDK的require语句:
const VisualRecognitionV3 = require('watson-developer-cloud/visual-recognition/v3');

使用您的API密钥创建SDK的实例:

const visualRecognition = new VisualRecognitionV3({
  version: '2018-03-19',
  iam_apikey: '{iam_api_key}'
});

最后,一旦用户上传图像,您可以使用图像文件作为参数调用相应的函数:

visualRecognition.detectFaces({image_file: file}, function(err, response) {
  if (err)
    console.log(err);
  else
    console.log(JSON.stringify(response, null, 2))
});

将所有内容放在一起,您的应用可能看起来像这样:

import React from 'react';
import ImageUploader from 'react-images-upload';
const VisualRecognitionV3 = require('watson-developer-cloud/visual-recognition/v3'); 

const visualRecognition = new VisualRecognitionV3({
  version: '2018-03-19',
  iam_apikey: '{iam_api_key}'
});

class App extends React.Component {

    constructor(props) {
        super(props);
        this.onDrop = this.onDrop.bind(this);
    }

    onDrop(pictureFiles, pictureDataURLs) {
        visualRecognition.detectFaces({image_file: pictureFiles[0]}, function(err, response) {
            if (err) {
                console.log(err);
            } else
                console.log(JSON.stringify(response, null, 2));
            }
       });
    }

    render() {
        return (
            <ImageUploader
                withIcon={true}
                buttonText='Escolher Imagens'
                onChange={this.onDrop}
                imgExtension={['.jpg', '.gif', '.png', '.gif']}
                maxFileSize={5242880}
            />
        );
    }
}

我没有测试过这段代码,所以IBM Watson SDK可能会遇到pictureFile [0]格式的问题(而且我也不确定pictureFiles是否是一个数组,但是你应该很容易检查一下React- Images-Uploader组件,以查看是什么数据结构)。但是,无论如何,这是基本的想法。

顺便说一句,此代码的输出将在JavaScript开发人员控制台中,它将打印出图像中面部周围方形的尺寸和坐标,但此代码不会绘制它为了你。这是另一项任务,有很多方法可以做,你可以在别处问。但是在这里你将获得面部的坐标,形状和大小,然后它们只需要绘制。