Tutorial de reconhecimento facial

Objetivos

Neste exemplo, você usará a API Google Cloud Vision para detectar rostos em uma imagem. Para comprovar que os rostos foram detectados corretamente, você utilizará os dados para desenhar uma caixa em torno deles.

Custos

Este tutorial usa componentes faturáveis do Cloud Platform, incluindo:

  • API Google Cloud Vision

Use a calculadora de preços para gerar uma estimativa de custo com base no uso previsto. Novos usuários do Cloud Platform podem estar qualificados para uma avaliação gratuita.

Antes de começar

  1. Faça login na sua Conta do Google.

    Se você ainda não tiver uma, inscreva-se.

  2. Selecione ou crie um projeto do Google Cloud Platform.

    Acessar a página Gerenciar recursos

  3. Verifique se o faturamento foi ativado no projeto do Google Cloud Platform.

    Saiba como ativar o faturamento

  4. Ativar Google Cloud Vision API.

    Ativar a API

  5. Configure o ambiente para usar o Application Default Credentials.
  6. Configure tarefas e ferramentas específicas por linguagem:

    C#

    Java

    • Instale o Java
    • Referência da API.
    • Faça o download e instale o sistema de versão do Apache Maven. O Maven garantirá que a biblioteca de cliente da API do Google e as bibliotecas de cliente da API Vision sejam instaladas quando o projeto for criado, porque as incluímos no pom.xml.

      <dependency>
        <groupId>com.google.apis</groupId>
        <artifactId>google-api-services-vision</artifactId>
        <version>v1-rev20190125-1.28.0</version>
      </dependency>
      <dependency>
        <groupId>com.google.api-client</groupId>
        <artifactId>google-api-client</artifactId>
        <version>1.28.0</version>
        <exclusions>
          <exclusion> <!-- exclude an old version of Guava -->
            <groupId>com.google.guava</groupId>
            <artifactId>guava-jdk5</artifactId>
          </exclusion>
        </exclusions>
      </dependency>
      <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>25.1-android</version>
      </dependency>
      ...

    Node.js

    • Instale a biblioteca de cliente do Google.
    • Instale o Node.js.
    • Referência da API.
    • Instale o npm e o node-canvas. Um package.json está incluído no código de amostra para instalar todas as dependências usando o comando: npm install. Há outras dependências no node-canvas que talvez você precise instalar. Para mais informações, consulte o documento de instalação do node-canvas.

      {
        "name": "nodejs-docs-samples-vision",
        "private": true,
        "license": "Apache-2.0",
        "author": "Google Inc.",
        "engines": {
          "node": ">=8"
        },
        "files": [
          "*.js"
        ],
        "scripts": {
          "test": "mocha system-test --timeout 600000"
        },
        "dependencies": {
          "@google-cloud/automl": "^0.1.3",
          "@google-cloud/vision": "^0.24.0",
          "mathjs": "^5.0.4",
          "natural": "^0.6.1",
          "redis": "^2.8.0",
          "yargs": "^13.0.0",
          "canvas": "^2.0.0"
        },
        "devDependencies": {
          "@google-cloud/storage": "^2.0.0",
          "chai": "^4.2.0",
          "execa": "^1.0.0",
          "mocha": "^6.0.0",
          "uuid": "^3.2.1"
        }
      }
      

    PHP

    Python

    Ruby

Criar o objeto de serviço

Para acessar as APIs do Google usando os SDKs do cliente oficial, é necessário criar um objeto de serviço baseado no documento de descoberta. Ele descreve a API para o SDK. Você precisará buscar o documento no serviço de descoberta da API Vision usando suas credenciais:

C#


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

Java

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.vision.v1.Vision;
import com.google.api.services.vision.v1.VisionScopes;
import com.google.api.services.vision.v1.model.AnnotateImageRequest;
import com.google.api.services.vision.v1.model.AnnotateImageResponse;
import com.google.api.services.vision.v1.model.BatchAnnotateImagesRequest;
import com.google.api.services.vision.v1.model.BatchAnnotateImagesResponse;
import com.google.api.services.vision.v1.model.FaceAnnotation;
import com.google.api.services.vision.v1.model.Feature;
import com.google.api.services.vision.v1.model.Image;
import com.google.api.services.vision.v1.model.Vertex;
import com.google.common.collect.ImmutableList;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.util.List;
import javax.imageio.ImageIO;
/**
 * Connects to the Vision API using Application Default Credentials.
 */
public static Vision getVisionService() throws IOException, GeneralSecurityException {
  GoogleCredential credential =
      GoogleCredential.getApplicationDefault().createScoped(VisionScopes.all());
  JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
  return new Vision.Builder(GoogleNetHttpTransport.newTrustedTransport(), jsonFactory, credential)
          .setApplicationName(APPLICATION_NAME)
          .build();
}

Node.js

// 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');

PHP

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

Python

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

Ruby

require "google/cloud/vision"
image_annotator = Google::Cloud::Vision::ImageAnnotator.new

Enviar uma solicitação de detecção de rostos

Para construir uma solicitação para a API Vision, primeiro consulte a documentação da API. Nesse caso, você solicitará que o recurso images faça anotações (annotate) na sua imagem. Uma solicitação para essa API tem a forma de um objeto com uma lista de requests. Cada item nela contém duas informações:

  • Os dados de imagem codificados em Base64.
  • Uma lista de recursos que você quer anotar na imagem.

Neste exemplo, você solicitará uma anotação FACE_DETECTION em uma imagem e retornará a parte relevante da resposta:

C#

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

Java

/**
 * Gets up to {@code maxResults} faces for an image stored at {@code path}.
 */
public List<FaceAnnotation> detectFaces(Path path, int maxResults) throws IOException {
  byte[] data = Files.readAllBytes(path);

  AnnotateImageRequest request =
      new AnnotateImageRequest()
          .setImage(new Image().encodeContent(data))
          .setFeatures(ImmutableList.of(
              new Feature()
                  .setType("FACE_DETECTION")
                  .setMaxResults(maxResults)));
  Vision.Images.Annotate annotate =
      vision.images()
          .annotate(new BatchAnnotateImagesRequest().setRequests(ImmutableList.of(request)));
  // Due to a bug: requests to Vision API containing large images fail when GZipped.
  annotate.setDisableGZipContent(true);

  BatchAnnotateImagesResponse batchResponse = annotate.execute();
  assert batchResponse.getResponses().size() == 1;
  AnnotateImageResponse response = batchResponse.getResponses().get(0);
  if (response.getFaceAnnotations() == null) {
    throw new IOException(
        response.getError() != null
            ? response.getError().getMessage()
            : "Unknown error getting image annotations");
  }
  return response.getFaceAnnotations();
}

Node.js

async function detectFaces(inputFile) {
  // Make a call to the Vision API to detect the faces
  const request = {image: {source: {filename: inputFile}}};
  const results = await client.faceDetection(request);
  const faces = results[0].faceAnnotations;
  const numFaces = faces.length;
  console.log(`Found ${numFaces} face${numFaces === 1 ? '' : 's'}.`);
  return faces;
}

PHP

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

Python

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 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, max_results=max_results).face_annotations

Ruby

response = image_annotator.face_detection image: path_to_image_file

Processar a resposta

Parabéns! Você detectou os rostos na sua imagem. A resposta à solicitação de anotação de rosto inclui um grupo de metadados relacionados aos rostos detectados, com as coordenadas de um polígono abrangendo o rosto. No entanto, agora isso é apenas uma lista de números. Vamos usá-la para confirmar que você realmente encontrou os rostos na imagem. Desenharemos polígonos em uma cópia da imagem usando as coordenadas retornadas pela API Vision:

C#

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());
        // ...
    }
    // ...
}

Java

/**
 * Reads image {@code inputPath} and writes {@code outputPath} with {@code faces} outlined.
 */
private static void writeWithFaces(Path inputPath, Path outputPath, List<FaceAnnotation> faces)
    throws IOException {
  BufferedImage img = ImageIO.read(inputPath.toFile());
  annotateWithFaces(img, faces);
  ImageIO.write(img, "jpg", outputPath.toFile());
}

/**
 * Annotates an image {@code img} with a polygon around each face in {@code faces}.
 */
public static void annotateWithFaces(BufferedImage img, List<FaceAnnotation> faces) {
  for (FaceAnnotation face : faces) {
    annotateWithFace(img, face);
  }
}

/**
 * Annotates an image {@code img} with a polygon defined by {@code face}.
 */
private static void annotateWithFace(BufferedImage img, FaceAnnotation face) {
  Graphics2D gfx = img.createGraphics();
  Polygon poly = new Polygon();
  for (Vertex vertex : face.getFdBoundingPoly().getVertices()) {
    poly.addPoint(vertex.getX(), vertex.getY());
  }
  gfx.setStroke(new BasicStroke(5));
  gfx.setColor(new Color(0x00ff00));
  gfx.draw(poly);
}

Node.js

Usamos a biblioteca do node-canvas para desenhar nas imagens.

async function highlightFaces(inputFile, faces, outputFile, Canvas) {
  const {promisify} = require('util');
  const readFile = promisify(fs.readFile);
  const image = await readFile(inputFile);
  const Image = Canvas.Image;
  // Open the original image into a canvas
  const img = new Image();
  img.src = image;
  const canvas = new Canvas.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 => {
    context.beginPath();
    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);
    context.stroke();
  });

  // Write the result to a file
  console.log(`Writing to file ${outputFile}`);
  const writeStream = fs.createWriteStream(outputFile);
  const pngStream = canvas.pngStream();

  await new Promise((resolve, reject) => {
    pngStream
      .on('data', chunk => writeStream.write(chunk))
      .on('error', reject)
      .on('end', resolve);
  });
}

PHP

Usamos a extensão GD para desenhar nas imagens.

# 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);
        }
    }

Python

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)
    # Sepecify the font-family and the font-size
    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')
        # Place the confidence value/score of the detected faces above the
        # detection box in the output image
        draw.text(((face.bounding_poly.vertices)[0].x,
                   (face.bounding_poly.vertices)[0].y - 30),
                  str(format(face.detection_confidence, '.3f')) + '%',
                  fill='#FF0000')
    im.save(output_filename)

Ruby

Usamos a gem da rmagick para desenhar nas imagens.

require "rmagick"
  response.responses.each do |res|
    res.face_annotations.each do |annotation|
      puts "Face bounds:"
      annotation.bounding_poly.vertices.each do |vertex|
        puts "(#{vertex.x}, #{vertex.y})"
      end

      x1 = annotation.bounding_poly.vertices[0].x.to_i
      y1 = annotation.bounding_poly.vertices[0].y.to_i
      x2 = annotation.bounding_poly.vertices[2].x.to_i
      y2 = annotation.bounding_poly.vertices[2].y.to_i

      photo = Magick::Image.read(path_to_image_file).first
      draw = Magick::Draw.new
      draw.stroke = "green"
      draw.stroke_width 5
      draw.fill_opacity 0
      draw.rectangle x1, y1, x2, y2
      draw.draw photo

      photo.write path_to_output_file
    end
  end

  puts "Output file: #{path_to_output_file}"

Funcionamento em conjunto

C#

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)
    {
        Console.WriteLine(s_usage);
        return;
    }

    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());
            // ...
        }
        // ...
    }
    // ...
}

Para criar o exemplo, abra o arquivo de solução dotnet-doc-samples/vision/api/Vision.sln no Visual Studio e a desenvolva.

Para executar a amostra:

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

Java

/**
 * Annotates an image using the Vision API.
 */
public static void main(String[] args) throws IOException, GeneralSecurityException {
  if (args.length != 2) {
    System.err.println("Usage:");
    System.err.printf(
        "\tjava %s inputImagePath outputImagePath\n",
        FaceDetectApp.class.getCanonicalName());
    System.exit(1);
  }
  Path inputPath = Paths.get(args[0]);
  Path outputPath = Paths.get(args[1]);
  if (!outputPath.toString().toLowerCase().endsWith(".jpg")) {
    System.err.println("outputImagePath must have the file extension 'jpg'.");
    System.exit(1);
  }

  FaceDetectApp app = new FaceDetectApp(getVisionService());
  List<FaceAnnotation> faces = app.detectFaces(inputPath, MAX_RESULTS);
  System.out.printf("Found %d face%s\n", faces.size(), faces.size() == 1 ? "" : "s");
  System.out.printf("Writing to file %s\n", outputPath);
  app.writeWithFaces(inputPath, outputPath, faces);
}
...

Para criar e executar a amostra, execute os seguintes comandos no diretório de código de amostra:

mvn clean compile assembly:single
java -cp target/vision-face-detection-1.0-SNAPSHOT-jar-with-dependencies.jar \
    com.google.cloud.vision.samples.facedetect.FaceDetectApp \
    data/face.jpg \
    output.jpg

Node.js

async function main(inputFile, outputFile) {
  const Canvas = require('canvas');
  outputFile = outputFile || 'out.png';
  const faces = await detectFaces(inputFile);
  console.log('Highlighting...');
  await highlightFaces(inputFile, faces, outputFile, Canvas);
  console.log('Finished!');
}

Para ativar o exemplo, execute o seguinte comando a partir do diretório do código de amostra:

node faceDetection face.png

PHP

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

Para ativar o exemplo, execute o seguinte comando a partir do diretório do código de amostra:

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

Python

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)

Ruby

if __FILE__ == $PROGRAM_NAME
  if ARGV.size == 2
    draw_box_around_faces path_to_image_file:  ARGV.shift,
                          path_to_output_file: ARGV.shift
  else
    puts <<~USAGE
    Usage: ruby draw_box_around_faces.rb [input-file] [output-file]

    Example:
      ruby draw_box_around_faces.rb images/face.png output-image.png
    USAGE
  end
end

Para ativar o exemplo, execute o seguinte comando a partir do diretório do código de amostra:

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

Imagem de entrada Imagem de saída

Como limpar

Para evitar cobranças dos recursos usados neste tutorial na conta do Google Cloud Platform:

  1. No Console do GCP, acesse a página Projetos.

    Acessar a página Projetos

  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir delete.
  3. Na caixa de diálogo, digite o código do projeto e clique em Encerrar para excluí-lo.
Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…

Documentação da API Cloud Vision
Precisa de ajuda? Acesse nossa página de suporte.