diff --git a/vision/api/face_detection/README.md b/vision/api/face_detection/README.md new file mode 100644 index 00000000000..5a94beb2162 --- /dev/null +++ b/vision/api/face_detection/README.md @@ -0,0 +1,2 @@ +Python face detection [Vision API](https://cloud.google.com/vision/) example. +See the [tutorial](https://cloud.google.com/vision/docs/face-tutorial). diff --git a/vision/api/face_detection/faces.py b/vision/api/face_detection/faces.py new file mode 100755 index 00000000000..d45c2a27b01 --- /dev/null +++ b/vision/api/face_detection/faces.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python + +# Copyright 2015 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. + +"""Draws squares around faces in the given image.""" + +import argparse +import base64 + +from googleapiclient import discovery +from oauth2client.client import GoogleCredentials +from PIL import Image +from PIL import ImageDraw + + +# [START get_vision_service] +DISCOVERY_URL = ('https://{api}.googleapis.com/$discovery/rest?' + 'version={apiVersion}') + + +def get_vision_service(): + credentials = GoogleCredentials.get_application_default() + return discovery.build('vision', 'v1', credentials=credentials, + discoveryServiceUrl=DISCOVERY_URL) +# [END get_vision_service] + + +def detect_face(face_file, max_results=4): + """Uses the Vision API to detect faces in the given file. + + Args: + face_file: A file-like object containing an image with faces. + + Returns: + An array of dicts with information about the faces in the picture. + """ + image_content = face_file.read() + batch_request = [{ + 'image': { + 'content': base64.b64encode(image_content).decode('utf-8') + }, + 'features': [{ + 'type': 'FACE_DETECTION', + 'maxResults': max_results, + }] + }] + + service = get_vision_service() + request = service.images().annotate(body={ + 'requests': batch_request, + }) + response = request.execute() + + return response['responses'][0]['faceAnnotations'] + + +def highlight_faces(image, faces, output_filename): + """Draws a polygon around the faces, then saves to output_filename. + + Args: + image: a file containing the image with the faces. + faces: a list of faces found in the file. This should be in the format + returned by the Vision API. + output_filename: the name of the image file to be created, where the + faces have polygons drawn around them. + """ + im = Image.open(image) + draw = ImageDraw.Draw(im) + + for face in faces: + box = [(v.get('x', 0.0), v.get('y', 0.0)) + for v in face['fdBoundingPoly']['vertices']] + draw.line(box + [box[0]], width=5, fill='#00ff00') + + im.save(output_filename) + + +def main(input_filename, output_filename, max_results): + with open(input_filename, 'rb') as image: + faces = detect_face(image, max_results) + print('Found {} face{}'.format( + len(faces), '' if len(faces) == 1 else 's')) + + print('Writing to file {}'.format(output_filename)) + # Reset the file pointer, so we can read the file again + image.seek(0) + highlight_faces(image, faces, output_filename) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description='Detects faces in the given image.') + parser.add_argument( + 'input_image', help='the image you\'d like to detect faces in.') + parser.add_argument( + '--out', dest='output', default='out.jpg', + help='the name of the output file.') + parser.add_argument( + '--max-results', dest='max_results', default=4, + help='the max results of face detection.') + args = parser.parse_args() + + main(args.input_image, args.output, args.max_results) diff --git a/vision/api/face_detection/faces_test.py b/vision/api/face_detection/faces_test.py new file mode 100644 index 00000000000..43a0075856d --- /dev/null +++ b/vision/api/face_detection/faces_test.py @@ -0,0 +1,36 @@ +# 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. + +import os + +from faces import main +from PIL import Image + + +def test_main(resource, tmpdir): + out_file = os.path.join(tmpdir.dirname, 'face-output.jpg') + in_file = resource('face-input.jpg') + + # Make sure there isn't already a green box + im = Image.open(in_file) + pixels = im.getdata() + greens = sum(1 for (r, g, b) in pixels if r == 0 and g == 255 and b == 0) + assert greens < 1 + + main(in_file, out_file, 10) + + # Make sure there now is some green drawn + im = Image.open(out_file) + pixels = im.getdata() + greens = sum(1 for (r, g, b) in pixels if r == 0 and g == 255 and b == 0) + assert greens > 10 diff --git a/vision/api/face_detection/requirements.txt b/vision/api/face_detection/requirements.txt new file mode 100644 index 00000000000..488b681c713 --- /dev/null +++ b/vision/api/face_detection/requirements.txt @@ -0,0 +1,2 @@ +google-api-python-client==1.5.0 +Pillow==3.1.1 diff --git a/vision/api/face_detection/resources/face-input.jpg b/vision/api/face_detection/resources/face-input.jpg new file mode 100644 index 00000000000..c0ee5580b37 Binary files /dev/null and b/vision/api/face_detection/resources/face-input.jpg differ