Обнаружение лица с помощью IBM Watson - PullRequest
0 голосов
/ 03 июня 2018

Я пытаюсь создать простой загрузчик изображений с 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;

Я уже пробовал некоторые учебные пособия и примеры из Интернета, но безуспешно.Вопрос в том, как применить Watson, чтобы нарисовать квадрат вокруг лица загруженного изображения?

1 Ответ

0 голосов
/ 04 июня 2018

1) Я не знаю, что вы пытались сделать с const steps, но это не имеет никакого смысла.Вам не нужна команда npm install внутри вашего приложения React.Я также не вижу никакой цели включения связки JavaScript внутри строки.

2) Внутри вашего фактического App класса внизу, где вы используете компонент ImageUploader,Вы не следовали своему собственному совету из steps выше и включили метод onChange.Из того, что я вижу из документации ImageUploader, это то, что вы будете использовать для выполнения определенного действия после того, как пользователь загрузит изображение.

3) Вы не предприняли никаких попыток фактически интегрироватьAPI IBM Watson в этот код.Очевидно, что это будет критически важным шагом в достижении вашей заявленной цели.Вы должны сделать искреннюю попытку самостоятельно, прежде чем публиковать здесь вопрос.

В любом случае, основная идея того, что вам нужно сделать, заключается в том, что после того, как пользователь загрузит изображение, вы отправляете запрос API в API распознавания изображений Watson:https://www.ibm.com/watson/developercloud/visual-recognition/api/v3/node.html?node#detect-faces

Вам нужно будет создать для них учетную запись и получить ключ разработчика (он должен быть бесплатным для очень небольшого числа запросов).Затем вы захотите установить их API, используя npm install --save watson-developer-cloud (примечание: как я уже упоминал выше, он не принадлежит вашему коду, как вы сейчас; он предназначен для запуска из вашего терминала / оболочки в каталоге проекта.

В верхней части файла вы включите оператор require для SDK:
const VisualRecognitionV3 = require('watson-developer-cloud/visual-recognition/v3');

и создадите экземпляр SDK с помощью своего ключа API:

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 Developer Console, и он распечатает размеры и координаты квадрата вокруг лица (лиц) на изображении, но этот код не будет рисовать его для вас.Это еще одна задача, и есть множество способов сделать это, и вы можете спросить об этом в другом месте.Но здесь вы получите координаты, форму и размер граней, а затем их просто нужно нарисовать.

...