Skip to content

Commit 4767150

Browse files
committed
Merge pull request #346 from GoogleCloudPlatform/vision-face
Move in face detection sample + test
2 parents 2f0a79e + 7829732 commit 4767150

File tree

5 files changed

+155
-0
lines changed

5 files changed

+155
-0
lines changed

vision/api/face_detection/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Python face detection [Vision API](https://cloud.google.com/vision/) example.
2+
See the [tutorial](https://cloud.google.com/vision/docs/face-tutorial).

vision/api/face_detection/faces.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2015 Google, Inc
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
"""Draws squares around faces in the given image."""
18+
19+
import argparse
20+
import base64
21+
22+
from googleapiclient import discovery
23+
from oauth2client.client import GoogleCredentials
24+
from PIL import Image
25+
from PIL import ImageDraw
26+
27+
28+
# [START get_vision_service]
29+
DISCOVERY_URL = ('https://{api}.googleapis.com/$discovery/rest?'
30+
'version={apiVersion}')
31+
32+
33+
def get_vision_service():
34+
credentials = GoogleCredentials.get_application_default()
35+
return discovery.build('vision', 'v1', credentials=credentials,
36+
discoveryServiceUrl=DISCOVERY_URL)
37+
# [END get_vision_service]
38+
39+
40+
def detect_face(face_file, max_results=4):
41+
"""Uses the Vision API to detect faces in the given file.
42+
43+
Args:
44+
face_file: A file-like object containing an image with faces.
45+
46+
Returns:
47+
An array of dicts with information about the faces in the picture.
48+
"""
49+
image_content = face_file.read()
50+
batch_request = [{
51+
'image': {
52+
'content': base64.b64encode(image_content).decode('utf-8')
53+
},
54+
'features': [{
55+
'type': 'FACE_DETECTION',
56+
'maxResults': max_results,
57+
}]
58+
}]
59+
60+
service = get_vision_service()
61+
request = service.images().annotate(body={
62+
'requests': batch_request,
63+
})
64+
response = request.execute()
65+
66+
return response['responses'][0]['faceAnnotations']
67+
68+
69+
def highlight_faces(image, faces, output_filename):
70+
"""Draws a polygon around the faces, then saves to output_filename.
71+
72+
Args:
73+
image: a file containing the image with the faces.
74+
faces: a list of faces found in the file. This should be in the format
75+
returned by the Vision API.
76+
output_filename: the name of the image file to be created, where the
77+
faces have polygons drawn around them.
78+
"""
79+
im = Image.open(image)
80+
draw = ImageDraw.Draw(im)
81+
82+
for face in faces:
83+
box = [(v.get('x', 0.0), v.get('y', 0.0))
84+
for v in face['fdBoundingPoly']['vertices']]
85+
draw.line(box + [box[0]], width=5, fill='#00ff00')
86+
87+
im.save(output_filename)
88+
89+
90+
def main(input_filename, output_filename, max_results):
91+
with open(input_filename, 'rb') as image:
92+
faces = detect_face(image, max_results)
93+
print('Found {} face{}'.format(
94+
len(faces), '' if len(faces) == 1 else 's'))
95+
96+
print('Writing to file {}'.format(output_filename))
97+
# Reset the file pointer, so we can read the file again
98+
image.seek(0)
99+
highlight_faces(image, faces, output_filename)
100+
101+
102+
if __name__ == '__main__':
103+
parser = argparse.ArgumentParser(
104+
description='Detects faces in the given image.')
105+
parser.add_argument(
106+
'input_image', help='the image you\'d like to detect faces in.')
107+
parser.add_argument(
108+
'--out', dest='output', default='out.jpg',
109+
help='the name of the output file.')
110+
parser.add_argument(
111+
'--max-results', dest='max_results', default=4,
112+
help='the max results of face detection.')
113+
args = parser.parse_args()
114+
115+
main(args.input_image, args.output, args.max_results)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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+
import os
15+
16+
from faces import main
17+
from PIL import Image
18+
19+
20+
def test_main(resource, tmpdir):
21+
out_file = os.path.join(tmpdir.dirname, 'face-output.jpg')
22+
in_file = resource('face-input.jpg')
23+
24+
# Make sure there isn't already a green box
25+
im = Image.open(in_file)
26+
pixels = im.getdata()
27+
greens = sum(1 for (r, g, b) in pixels if r == 0 and g == 255 and b == 0)
28+
assert greens < 1
29+
30+
main(in_file, out_file, 10)
31+
32+
# Make sure there now is some green drawn
33+
im = Image.open(out_file)
34+
pixels = im.getdata()
35+
greens = sum(1 for (r, g, b) in pixels if r == 0 and g == 255 and b == 0)
36+
assert greens > 10
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
google-api-python-client==1.5.0
2+
Pillow==3.1.1
Loading

0 commit comments

Comments
 (0)