Im trying to make a simple image uploader with React and integrate it with IBM Watson to do a face detection, just draw a square in the faces of a image.
So, this is my 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;
I have already tried some tutorials and examples from web but no success. The question is, how do i apply Watson to draw a square around the face of the uploaded image?
1) I don't know what you were attempting to do with
const steps, but it doesn't make any sense. You don't need annpm installcommand inside of your React app. I also don't see any purpose of including a bunch of JavaScript inside of a string.2) Inside of your actual
Appclass at the bottom, where you're using theImageUploadercomponent, you have not followed your own advice from thestepsabove and included anonChangemethod. From what I can see from theImageUploadercomponent documentation, that is what you'll use to perform a certain an action after the user uploads an image.3) You have not made any attempt to actually integrate the IBM Watson API into this code. Obviously that is going to be a critical step in achieving your stated goal. You should make a sincere attempt yourself before posting a question here.
Anyway, the basic idea of what you need to do is, after the user uploads an image, you make an API request to Watson's Image Recognition API: https://www.ibm.com/watson/developercloud/visual-recognition/api/v3/node.html?node#detect-faces
You'll need to set up an account with them and get a developer key (it should be free for a very small number of requests). Then, you'll want to install their API using
npm install --save watson-developer-cloud(note: as I mentioned above, this does not belong in your code, like you have now; this is meant to be run from your Terminal/shell in the project directory.At the top of your file you'll include the
requirestatement for the SDK:const VisualRecognitionV3 = require('watson-developer-cloud/visual-recognition/v3');And create an instance of the SDK using your API key:
Finally, once the user uploads an image, you call the appropriate function using the image file as a parameter:
Put it all together and your app might look something like this:
I haven't tested this code so the IBM Watson SDK may have an issue with the format of pictureFile[0] (and also I'm not sure if pictureFiles is even an array, but you should easily check the React-Images-Uploader component to see what data structure that is). But, regardless, this is the basic idea.
By the way, the output of this code will be in the JavaScript developer console, and it will print out the dimensions and coordinates of the square around the face(s) in the image, but this code won't draw it for you. That's another task and there's a bunch of ways to do and you can ask that elsewhere. But here you'll get the coordinates, shape and size of the faces and then they just need to be drawn.