Face Detection Tutorial


In this sample, you'll use the Google Cloud Vision API to detect faces in an image. To prove to yourself that the faces were detected correctly, you'll then use that data to draw a box around each face.


This tutorial uses billable components of Cloud Platform, including:

  • Google Cloud Vision API

Use the Pricing Calculator to generate a cost estimate based on your projected usage. New Cloud Platform users might be eligible for a free trial.

Before you begin

  1. Sign in to your Google Account.

    If you don't already have one, sign up for a new account.

  2. Select or create a GCP project.

    Go to the Manage resources page

  3. Make sure that billing is enabled for your project.

    Learn how to enable billing

  4. Enable the Google Cloud Vision API.

    Enable the API

  5. Set up your environment for using Application Default Credentials.
  6. Set up language-specific tasks and tools:



    • Install the Google Client Library
    • Install node.js.
    • API reference.
    • Install npm and node-canvas. The sample code includes a package.json to install all dependencies using the command: npm install. Note that node-canvas has additional dependencies you may need to install - see the node-canvas installation doc for more information.

        "name": "nodejs-docs-samples-vision",
        "version": "0.0.1",
        "private": true,
        "license": "Apache-2.0",
        "author": "Google Inc.",
        "engines": {
          "node": ">=8"
        "scripts": {
          "test": "ava -T 1m --verbose system-test/*.test.js"
        "dependencies": {
          "@google-cloud/automl": "^0.1.1",
          "@google-cloud/vision": "^0.23.0",
          "async": "^2.6.1",
          "mathjs": "^5.0.4",
          "natural": "^0.6.1",
          "redis": "^2.8.0",
          "yargs": "^12.0.0"
        "devDependencies": {
          "@google-cloud/nodejs-repo-tools": "^3.0.0",
          "@google-cloud/storage": "^2.0.0",
          "ava": "^0.25.0",
          "proxyquire": "^2.0.1",
          "sinon": "^7.0.0",
          "uuid": "^3.2.1"
        "optionalDependencies": {
          "canvas": "^2.0.0"




Create the service object

To access Google APIs using the official client SDKs, you create a service object based on the API's discovery document, which describes the API to the SDK. You'll need to fetch it from the Vision API's discovery service, using your credentials:


using Google.Cloud.Vision.V1;
using System;
using System.Linq;
var client = ImageAnnotatorClient.Create();


// By default, the client will authenticate using the service account file
// specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use
// the project specified by the GCLOUD_PROJECT environment variable. See
// https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/guides/authentication
const vision = require('@google-cloud/vision');
// Creates a client
const client = new vision.ImageAnnotatorClient();

const fs = require('fs');


use Google\Cloud\Vision\V1\ImageAnnotatorClient;
$imageAnnotator = new ImageAnnotatorClient();


from google.cloud import vision
from google.cloud.vision import types
from PIL import Image, ImageDraw
client = vision.ImageAnnotatorClient()


require "google/cloud/vision"
vision = Google::Cloud::Vision.new project: project_id

Send a face detection request

To construct a request to the Vision API, first consult the API documentation. In this case, you'll be asking the images resource to annotate your image. A request to this API takes the form of an object with a requests list. Each item in this list contains two bits of information:

  • The base64-encoded image data
  • A list of features you'd like annotated about that image.

For this example, you'll simply request FACE_DETECTION annotation on one image, and return the relevant portion of the response:


var response = client.DetectFaces(Image.FromFile(args[0]));


function detectFaces(inputFile, callback) {
  // Make a call to the Vision API to detect the faces
  const request = {image: {source: {filename: inputFile}}};
    .then(results => {
      const faces = results[0].faceAnnotations;
      const numFaces = faces.length;
      console.log('Found ' + numFaces + (numFaces === 1 ? ' face' : ' faces'));
      callback(null, faces);
    .catch(err => {
      console.error('ERROR:', err);


# annotate the image
// $path = 'path/to/your/image.jpg'
$image = file_get_contents($path);
$response = $imageAnnotator->faceDetection($image);
$faces = $response->getFaceAnnotations();


def detect_face(face_file, max_results=4):
    """Uses the Vision API to detect faces in the given file.

        face_file: A file-like object containing an image with faces.

        An array of Face objects with information about the picture.
    client = vision.ImageAnnotatorClient()

    content = face_file.read()
    image = types.Image(content=content)

    return client.face_detection(image=image).face_annotations


image = vision.image path_to_image_file
faces = image.faces

Process the response

Congratulations - you've detected the faces in your image! The response to our face annotation request includes a bunch of metadata about the detected faces, which include coordinates of a polygon encompassing the face. At this point, though, this is only a list of numbers. Let's use them to confirm that you have, in fact, found the faces in your image. We'll draw polygons onto a copy of the image, using the coordinates returned by the Vision API:


using (var image = System.Drawing.Image.FromFile(args[0]))
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(image))
    var cyanPen = new System.Drawing.Pen(System.Drawing.Color.Cyan, 3);
    foreach (var annotation in response)
        g.DrawPolygon(cyanPen, annotation.BoundingPoly.Vertices.Select(
            (vertex) => new System.Drawing.Point(vertex.X, vertex.Y)).ToArray());
        // ...
    // ...


We use the node-canvas library to draw onto images.

function highlightFaces(inputFile, faces, outputFile, Canvas, callback) {
  fs.readFile(inputFile, (err, image) => {
    if (err) {
      return callback(err);

    const Image = Canvas.Image;
    // Open the original image into a canvas
    const img = new Image();
    img.src = image;
    const canvas = new Canvas(img.width, img.height);
    const 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(face => {
      let origX = 0;
      let origY = 0;
      face.boundingPoly.vertices.forEach((bounds, i) => {
        if (i === 0) {
          origX = bounds.x;
          origY = bounds.y;
        context.lineTo(bounds.x, bounds.y);
      context.lineTo(origX, origY);

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

    pngStream.on('data', chunk => {
    pngStream.on('error', console.log);
    pngStream.on('end', callback);


We use the GD extension to draw onto images.

# draw box around faces
if ($faces && $outFile) {
    $imageCreateFunc = [
        'png' => 'imagecreatefrompng',
        'gd' => 'imagecreatefromgd',
        'gif' => 'imagecreatefromgif',
        'jpg' => 'imagecreatefromjpeg',
        'jpeg' => 'imagecreatefromjpeg',
    $imageWriteFunc = [
        'png' => 'imagepng',
        'gd' => 'imagegd',
        'gif' => 'imagegif',
        'jpg' => 'imagejpeg',
        'jpeg' => 'imagejpeg',

    copy($path, $outFile);
    $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
    if (!array_key_exists($ext, $imageCreateFunc)) {
        throw new \Exception('Unsupported image extension');
    $outputImage = call_user_func($imageCreateFunc[$ext], $outFile);

    foreach ($faces as $face) {
        $vertices = $face->getBoundingPoly()->getVertices();
        if ($vertices) {
            $x1 = $vertices[0]->getX();
            $y1 = $vertices[0]->getY();
            $x2 = $vertices[2]->getX();
            $y2 = $vertices[2]->getY();
            imagerectangle($outputImage, $x1, $y1, $x2, $y2, 0x00ff00);


def highlight_faces(image, faces, output_filename):
    """Draws a polygon around the faces, then saves to output_filename.

      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 = [(vertex.x, vertex.y)
               for vertex in face.bounding_poly.vertices]
        draw.line(box + [box[0]], width=5, fill='#00ff00')



We use the rmagick gem to draw onto images.

require "rmagick"
  image = Magick::Image.read(path_to_image_file).first

  faces.each do |face|
    puts "Face bounds:"
    face.bounds.face.each do |vector|
      puts "(#{vector.x}, #{vector.y})"

    draw = Magick::Draw.new
    draw.stroke = "green"
    draw.stroke_width 5
    draw.fill_opacity 0

    x1 = face.bounds.face[0].x.to_i
    y1 = face.bounds.face[0].y.to_i
    x2 = face.bounds.face[2].x.to_i
    y2 = face.bounds.face[2].y.to_i

    draw.rectangle x1, y1, x2, y2
    draw.draw image

  image.write path_to_output_file

  puts "Output file: #{path_to_output_file}"

Put it all together


static readonly string s_usage = @"dotnet run image-file

Use the Google Cloud Vision API to detect faces in the image.
Writes an output file called image-file.faces.
public static void Main(string[] args)
    if (args.Length < 1)

    var client = ImageAnnotatorClient.Create();
    var response = client.DetectFaces(Image.FromFile(args[0]));

    int numberOfFacesFound = 0;
    using (var image = System.Drawing.Image.FromFile(args[0]))
    using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(image))
        var cyanPen = new System.Drawing.Pen(System.Drawing.Color.Cyan, 3);
        foreach (var annotation in response)
            g.DrawPolygon(cyanPen, annotation.BoundingPoly.Vertices.Select(
                (vertex) => new System.Drawing.Point(vertex.X, vertex.Y)).ToArray());
            // ...
        // ...
    // ...

To build the sample, open the Solution file dotnet-doc-samples/vision/api/Vision.sln in Visual Studio and build the solution.

To run the sample:

C:\...\> cd dotnet-docs-samples\vision\api\DetectFaces\bin\Debug
C:\...\bin\Debug> DetectFaces ..\..\..\VisionTest\data\face.png


function main(inputFile, outputFile, Canvas, callback) {
  outputFile = outputFile || 'out.png';
  detectFaces(inputFile, (err, faces) => {
    if (err) {
      return callback(err);

    highlightFaces(inputFile, faces, outputFile, Canvas, err => {
      if (err) {
        return callback(err);
      callback(null, faces);

To run the sample, run the following command from the sample code directory:

node faceDetection face.png


call_user_func($imageWriteFunc[$ext], $outputImage, $outFile);
printf('Output image written to %s' . PHP_EOL, $outFile);

To run the sample, run the following command from the sample code directory:

composer install
php vision.php face images/face.png output-image.png


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
        highlight_faces(image, faces, output_filename)


  project_id = ENV["GOOGLE_CLOUD_PROJECT"]

  if ARGV.size == 2
    draw_box_around_faces path_to_image_file:  ARGV.shift,
                          path_to_output_file: ARGV.shift,
                          project_id:          project_id
    puts <<-usage
Usage: ruby draw_box_around_faces.rb [input-file] [output-file]

  ruby draw_box_around_faces.rb images/face.png output-image.png

To run the sample, run the following command from the sample code directory:

bundle install
bundle exec ruby draw_box_around_faces.rb images/face.png output-image.png

Input image Output image

Cleaning up

To avoid incurring charges to your Google Cloud Platform account for the resources used in this tutorial:

  1. In the GCP Console, go to the Projects page.

    Go to the Projects page

  2. In the project list, select the project you want to delete and click Delete project. After selecting the checkbox next to the project name, click
      Delete project
  3. In the dialog, type the project ID, and then click Shut down to delete the project.
Was this page helpful? Let us know how we did:

Send feedback about...

Cloud Vision API Documentation
Need help? Visit our support page.