Skip to content

Commit

Permalink
Add Cloud Vision face detection sample.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmdobry committed May 12, 2016
1 parent 4fbaf10 commit 346a13e
Show file tree
Hide file tree
Showing 8 changed files with 244 additions and 2 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ This repository holds Node.js samples used throughout [cloud.google.com]().
* [Google Cloud Logging](#google-cloud-logging)
* [Google Cloud Pub/Sub](#google-cloud-pubsub)
* [Google Cloud Storage](#google-cloud-storage)
* [Google Cloud Vision](#google-cloud-vision)
* [Google Prediction API](#google-prediction-api)
* [Other Example Apps](#other-example-apps)
* [More Information](#more-information)
Expand Down Expand Up @@ -106,6 +107,10 @@ __Other Examples__

- Auth sample - [Source code][storage_1] | [Documentation][storage_2]

## Google Cloud Vision

- Face detection - [Source code][vision_1] | [Documentation][vision_2]

## Google Prediction API

- Hosted Models sample - [Source code][predictionapi_1] | [Documentation][predictionapi_2]
Expand Down Expand Up @@ -307,6 +312,9 @@ See [LICENSE](https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/ma
[storage_1]: https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/master/storage/authSample.js
[storage_2]: https://cloud.google.com/storage/docs/authentication#acd-examples

[vision_1]: https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/master/vision/faceDetection.js
[vision_2]: https://cloud.google.com/vision/docs/face-tutorial

[predictionapi_1]: https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/master/prediction/hostedmodels.js
[predictionapi_2]: https://cloud.google.com/prediction/docs/developer-guide#predictionfromappengine

Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,15 @@
"deps_storage": "cd storage; npm i; cd ../",
"deps_prediction": "cd prediction; npm i; cd ../",
"deps_logging": "cd logging; npm i; cd ../",
"deps_vision": "cd vision; npm i; cd ../",
"deps_functions": "cd functions/uuid; npm i; cd ../..",
"pretest_geddy": "cd appengine/geddy; npm i geddy; GEDDY_SECRET=config/secrets.json; [[ -f $GEDDY_SECRET ]] || echo '{}' > $GEDDY_SECRET && node node_modules/.bin/geddy gen secret; cd ../..;",
"pretest": "npm run deps_gce; npm run deps_bigquery; npm run deps_datastore; npm run deps_monitoring; npm run deps_storage; npm run deps_pubsub; npm run deps_prediction; npm run deps_logging; npm run deps_functions; npm run pretest_geddy",
"pretest": "npm run deps_vision; npm run deps_gce; npm run deps_bigquery; npm run deps_datastore; npm run deps_monitoring; npm run deps_storage; npm run deps_pubsub; npm run deps_prediction; npm run deps_logging; npm run deps_functions; npm run pretest_geddy",
"test": "npm run jshint && npm run cover"
},
"ava": {
"files": [
"test/appengine/**/*.test.js"
"test/**/*.test.js"
]
},
"devDependencies": {
Expand Down
65 changes: 65 additions & 0 deletions test/vision/faceDetection.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2016, Google, Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

var test = require('ava');
var fs = require('fs');
var path = require('path');

function MockCanvas () {
this.getContext = function () {
return {
drawImage: function () {},
beginPath: function () {},
lineTo: function () {},
stroke: function () {}
};
};
this.pngStream = function () {
return {
on: function (event, cb) {
if (event === 'end') {
setTimeout(function () {
cb();
}, 1000);
} else if (event === 'data') {
cb('test');
cb('foo');
cb('bar');
}
}
};
};
}

MockCanvas.Image = function () {};

var faceDetectionExample = require('../../vision/faceDetection');
var inputFile = path.resolve(path.join('../../vision', 'face.png'));
var outputFile = path.resolve(path.join('../../vision', 'out.png'));

test.cb('should detect faces', function (t) {
faceDetectionExample.main(
inputFile,
outputFile,
MockCanvas,
function (err, faces) {
t.ifError(err);
t.is(faces.length, 1);
var image = fs.readFileSync(outputFile);
t.is(image.toString('utf8'), 'testfoobar');
t.end();
}
);
});
1 change: 1 addition & 0 deletions vision/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
out.*
30 changes: 30 additions & 0 deletions vision/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## Cloud Vision API samples

These samples require two environment variables to be set:

- `GOOGLE_APPLICATION_CREDENTIALS` - Path to a service account file. You can
download one from your Google project's "credentials" page.
- `GCLOUD_PROJECT` - ID of your Google project.

See [gcloud-node authentication][auth] for more details.

[auth]: https://googlecloudplatform.github.io/gcloud-node/#/docs/guides/authentication

## Run a sample

Install dependencies first:

npm install

### Face detection sample

This sample uses [node-canvas](https://github.com/Automattic/node-canvas) to
draw an output image. node-canvas depends on Cairo, which may require separate
installation. See the node-canvas [installation section][canvas-install] for
details.

[canvas-install]: https://github.com/Automattic/node-canvas#installation

Execute the sample:

node faceDetection "/path/to/image.jpg"
Binary file added vision/face.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
120 changes: 120 additions & 0 deletions vision/faceDetection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright 2016, Google, Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

// [START auth]
// You must set the GOOGLE_APPLICATION_CREDENTIALS and GCLOUD_PROJECT
// environment variables to run this sample. See:
// https://github.com/GoogleCloudPlatform/gcloud-node/blob/master/docs/authentication.md
var projectId = process.env.GCLOUD_PROJECT;

// Initialize gcloud
var gcloud = require('gcloud')({
projectId: projectId
});

// Get a reference to the vision component
var vision = gcloud.vision();
// [END auth]

var fs = require('fs');

/**
* Uses the Vision API to detect faces in the given file.
*/
function detectFaces(inputFile, callback) {
// Make a call to the Vision API to detect the faces
vision.detectFaces(inputFile, function (err, faces) {
if (err) {
return callback(err);
}
var numFaces = faces.length;
console.log('Found ' + numFaces + (numFaces === 1 ? ' face' : ' faces'));
callback(null, faces);
});
}

/**
* Draws a polygon around the faces, then saves to outputFile.
*/
function highlightFaces(inputFile, faces, outputFile, Canvas, callback) {
fs.readFile(inputFile, function (err, image) {
if (err) {
return callback(err);
}

var Image = Canvas.Image;
// Open the original image into a canvas
var img = new Image();
img.src = image;
var canvas = new Canvas(img.width, img.height);
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0, img.width, img.height);

// Now draw boxes around all the faces
context.strokeStyle = 'rgba(0,255,0,0.8)';
context.lineWidth = '5';

faces.forEach(function (face) {
context.beginPath();
face.bounds.face.forEach(function (bounds) {
context.lineTo(bounds.x, bounds.y);
});
context.lineTo(face.bounds.face[0].x, face.bounds.face[0].y);
context.stroke();
});

// Write the result to a file
console.log('Writing to file ' + outputFile);
var writeStream = fs.createWriteStream(outputFile);
var pngStream = canvas.pngStream();

pngStream.on('data', function (chunk) {
writeStream.write(chunk);
});
pngStream.on('error', console.log);
pngStream.on('end', callback);
});
}

// Run the example
function main(inputFile, outputFile, Canvas, callback) {
outputFile = outputFile || 'out.png';
detectFaces(inputFile, function (err, faces) {
if (err) {
return callback(err);
}

console.log('Highlighting...');
highlightFaces(inputFile, faces, outputFile, Canvas, function (err) {
if (err) {
return callback(err);
}
console.log('Finished!');
callback(null, faces);
});
});
}

exports.main = main;

if (module === require.main) {
if (process.argv.length < 3) {
console.log('Usage: node faceDetection <inputFile> [outputFile]');
process.exit(1);
}
var inputFile = process.argv[2];
var outputFile = process.argv[3];
exports.main(inputFile, outputFile, require('canvas'), console.log);
}
17 changes: 17 additions & 0 deletions vision/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "cloud-vision-samples",
"description": "Node.js samples for Google Cloud Vision.",
"version": "0.0.1",
"private": true,
"license": "Apache Version 2.0",
"engines": {
"node": ">=0.10.x"
},
"scripts": {
"faceDetection": "node faceDetection.js"
},
"dependencies": {
"gcloud": "^0.32.0",
"canvas": "^1.3.15"
}
}

0 comments on commit 346a13e

Please sign in to comment.