Skip to content

Commit a3c96e9

Browse files
committed
Merge pull request #109 from GoogleCloudPlatform/vision
Add Cloud Vision face detection sample.
2 parents 4fbaf10 + 346a13e commit a3c96e9

File tree

8 files changed

+244
-2
lines changed

8 files changed

+244
-2
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This repository holds Node.js samples used throughout [cloud.google.com]().
1414
* [Google Cloud Logging](#google-cloud-logging)
1515
* [Google Cloud Pub/Sub](#google-cloud-pubsub)
1616
* [Google Cloud Storage](#google-cloud-storage)
17+
* [Google Cloud Vision](#google-cloud-vision)
1718
* [Google Prediction API](#google-prediction-api)
1819
* [Other Example Apps](#other-example-apps)
1920
* [More Information](#more-information)
@@ -106,6 +107,10 @@ __Other Examples__
106107

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

110+
## Google Cloud Vision
111+
112+
- Face detection - [Source code][vision_1] | [Documentation][vision_2]
113+
109114
## Google Prediction API
110115

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

315+
[vision_1]: https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/master/vision/faceDetection.js
316+
[vision_2]: https://cloud.google.com/vision/docs/face-tutorial
317+
310318
[predictionapi_1]: https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/master/prediction/hostedmodels.js
311319
[predictionapi_2]: https://cloud.google.com/prediction/docs/developer-guide#predictionfromappengine
312320

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,15 @@
3939
"deps_storage": "cd storage; npm i; cd ../",
4040
"deps_prediction": "cd prediction; npm i; cd ../",
4141
"deps_logging": "cd logging; npm i; cd ../",
42+
"deps_vision": "cd vision; npm i; cd ../",
4243
"deps_functions": "cd functions/uuid; npm i; cd ../..",
4344
"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 ../..;",
44-
"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",
45+
"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",
4546
"test": "npm run jshint && npm run cover"
4647
},
4748
"ava": {
4849
"files": [
49-
"test/appengine/**/*.test.js"
50+
"test/**/*.test.js"
5051
]
5152
},
5253
"devDependencies": {

test/vision/faceDetection.test.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2016, Google, Inc.
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
'use strict';
15+
16+
var test = require('ava');
17+
var fs = require('fs');
18+
var path = require('path');
19+
20+
function MockCanvas () {
21+
this.getContext = function () {
22+
return {
23+
drawImage: function () {},
24+
beginPath: function () {},
25+
lineTo: function () {},
26+
stroke: function () {}
27+
};
28+
};
29+
this.pngStream = function () {
30+
return {
31+
on: function (event, cb) {
32+
if (event === 'end') {
33+
setTimeout(function () {
34+
cb();
35+
}, 1000);
36+
} else if (event === 'data') {
37+
cb('test');
38+
cb('foo');
39+
cb('bar');
40+
}
41+
}
42+
};
43+
};
44+
}
45+
46+
MockCanvas.Image = function () {};
47+
48+
var faceDetectionExample = require('../../vision/faceDetection');
49+
var inputFile = path.resolve(path.join('../../vision', 'face.png'));
50+
var outputFile = path.resolve(path.join('../../vision', 'out.png'));
51+
52+
test.cb('should detect faces', function (t) {
53+
faceDetectionExample.main(
54+
inputFile,
55+
outputFile,
56+
MockCanvas,
57+
function (err, faces) {
58+
t.ifError(err);
59+
t.is(faces.length, 1);
60+
var image = fs.readFileSync(outputFile);
61+
t.is(image.toString('utf8'), 'testfoobar');
62+
t.end();
63+
}
64+
);
65+
});

vision/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
out.*

vision/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
## Cloud Vision API samples
2+
3+
These samples require two environment variables to be set:
4+
5+
- `GOOGLE_APPLICATION_CREDENTIALS` - Path to a service account file. You can
6+
download one from your Google project's "credentials" page.
7+
- `GCLOUD_PROJECT` - ID of your Google project.
8+
9+
See [gcloud-node authentication][auth] for more details.
10+
11+
[auth]: https://googlecloudplatform.github.io/gcloud-node/#/docs/guides/authentication
12+
13+
## Run a sample
14+
15+
Install dependencies first:
16+
17+
npm install
18+
19+
### Face detection sample
20+
21+
This sample uses [node-canvas](https://github.com/Automattic/node-canvas) to
22+
draw an output image. node-canvas depends on Cairo, which may require separate
23+
installation. See the node-canvas [installation section][canvas-install] for
24+
details.
25+
26+
[canvas-install]: https://github.com/Automattic/node-canvas#installation
27+
28+
Execute the sample:
29+
30+
node faceDetection "/path/to/image.jpg"

vision/face.png

458 KB
Loading

vision/faceDetection.js

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright 2016, Google, Inc.
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
'use strict';
15+
16+
// [START auth]
17+
// You must set the GOOGLE_APPLICATION_CREDENTIALS and GCLOUD_PROJECT
18+
// environment variables to run this sample. See:
19+
// https://github.com/GoogleCloudPlatform/gcloud-node/blob/master/docs/authentication.md
20+
var projectId = process.env.GCLOUD_PROJECT;
21+
22+
// Initialize gcloud
23+
var gcloud = require('gcloud')({
24+
projectId: projectId
25+
});
26+
27+
// Get a reference to the vision component
28+
var vision = gcloud.vision();
29+
// [END auth]
30+
31+
var fs = require('fs');
32+
33+
/**
34+
* Uses the Vision API to detect faces in the given file.
35+
*/
36+
function detectFaces(inputFile, callback) {
37+
// Make a call to the Vision API to detect the faces
38+
vision.detectFaces(inputFile, function (err, faces) {
39+
if (err) {
40+
return callback(err);
41+
}
42+
var numFaces = faces.length;
43+
console.log('Found ' + numFaces + (numFaces === 1 ? ' face' : ' faces'));
44+
callback(null, faces);
45+
});
46+
}
47+
48+
/**
49+
* Draws a polygon around the faces, then saves to outputFile.
50+
*/
51+
function highlightFaces(inputFile, faces, outputFile, Canvas, callback) {
52+
fs.readFile(inputFile, function (err, image) {
53+
if (err) {
54+
return callback(err);
55+
}
56+
57+
var Image = Canvas.Image;
58+
// Open the original image into a canvas
59+
var img = new Image();
60+
img.src = image;
61+
var canvas = new Canvas(img.width, img.height);
62+
var context = canvas.getContext('2d');
63+
context.drawImage(img, 0, 0, img.width, img.height);
64+
65+
// Now draw boxes around all the faces
66+
context.strokeStyle = 'rgba(0,255,0,0.8)';
67+
context.lineWidth = '5';
68+
69+
faces.forEach(function (face) {
70+
context.beginPath();
71+
face.bounds.face.forEach(function (bounds) {
72+
context.lineTo(bounds.x, bounds.y);
73+
});
74+
context.lineTo(face.bounds.face[0].x, face.bounds.face[0].y);
75+
context.stroke();
76+
});
77+
78+
// Write the result to a file
79+
console.log('Writing to file ' + outputFile);
80+
var writeStream = fs.createWriteStream(outputFile);
81+
var pngStream = canvas.pngStream();
82+
83+
pngStream.on('data', function (chunk) {
84+
writeStream.write(chunk);
85+
});
86+
pngStream.on('error', console.log);
87+
pngStream.on('end', callback);
88+
});
89+
}
90+
91+
// Run the example
92+
function main(inputFile, outputFile, Canvas, callback) {
93+
outputFile = outputFile || 'out.png';
94+
detectFaces(inputFile, function (err, faces) {
95+
if (err) {
96+
return callback(err);
97+
}
98+
99+
console.log('Highlighting...');
100+
highlightFaces(inputFile, faces, outputFile, Canvas, function (err) {
101+
if (err) {
102+
return callback(err);
103+
}
104+
console.log('Finished!');
105+
callback(null, faces);
106+
});
107+
});
108+
}
109+
110+
exports.main = main;
111+
112+
if (module === require.main) {
113+
if (process.argv.length < 3) {
114+
console.log('Usage: node faceDetection <inputFile> [outputFile]');
115+
process.exit(1);
116+
}
117+
var inputFile = process.argv[2];
118+
var outputFile = process.argv[3];
119+
exports.main(inputFile, outputFile, require('canvas'), console.log);
120+
}

vision/package.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "cloud-vision-samples",
3+
"description": "Node.js samples for Google Cloud Vision.",
4+
"version": "0.0.1",
5+
"private": true,
6+
"license": "Apache Version 2.0",
7+
"engines": {
8+
"node": ">=0.10.x"
9+
},
10+
"scripts": {
11+
"faceDetection": "node faceDetection.js"
12+
},
13+
"dependencies": {
14+
"gcloud": "^0.32.0",
15+
"canvas": "^1.3.15"
16+
}
17+
}

0 commit comments

Comments
 (0)