你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

教程:人脸活体检测

了解如何使用服务器端逻辑和配套前端客户端应用程序将人脸实时检测集成到工作流中。

小提示

有关人脸活体检测的一般信息,请参阅概念指南

本教程介绍如何使用应用服务器运行前端应用程序,以执行实时检测,(可选)跨各种平台和语言添加 人脸验证

重要说明

用于活体的人脸客户端 SDK 是一项门控功能。 你必须填写人脸识别登记表来请求访问活体功能。 当你的 Azure 订阅获得访问权限后,你可以下载人脸活体 SDK。

先决条件

  • Azure 订阅 - 免费创建订阅
  • 你的 Azure 帐户必须分配有“认知服务参与者”角色,你才能同意负责任 AI 条款并创建资源。 若要将此角色分配给你的帐户,请按照分配角色文档中的步骤进行操作,或与管理员联系。
  • 拥有 Azure 订阅后,在 Azure 门户中创建人脸资源,获取密钥和终结点。 部署后,选择“转到资源”
    • 你需要从创建的资源获取密钥和终结点,以便将应用程序连接到人脸服务。
  • 访问面向移动设备(IOS 和 Android)和 Web 的 Azure AI 视觉人脸客户端 SDK 所需的封闭项目。
  • 熟悉人脸活体检测功能。 请参阅概念指南

小提示

完成先决条件后,可以从 iOS App Store 试用 iOS Liveness 体验、 Android Google Play Store 中的 Android Liveness 体验和 Vision Studio 中的 Web liveness 体验。 此外,还可以从示例部分生成并运行完整的前端示例(在 iOS、Android 或 Web 上)。

准备前端应用程序

我们提供多种语言的 SDK,以简化与前端应用程序的集成。 请参阅下面的所选 SDK 的自述文件,以集成 UI 和所需的代码。

重要说明

每个前端 SDK 都需要访问封闭资产才能成功编译。 下面是设置步骤的说明。

对于 Swift iOS:

对于 Kotlin/Java Android:

对于 JavaScript Web:

集成到前端应用程序后,SDK 将启动相机,引导用户调整其位置,撰写实时有效负载,并将其发送到 Azure AI 人脸服务进行处理。

监视存储库的 “发布”部分 以获取新的 SDK 版本更新并启用自动依赖项更新警报,例如 GitHub Dependabot(适用于 GitHub 存储库)或“翻新”(GitHub、GitLab、Bitbucket、Azure Repos)。

执行活体检测

活体编排涉及的大致步骤如下所示:

Azure AI 人脸中的活体检测工作流示意图。

  1. 前端应用程序启动活性检查并通知应用服务器。

  2. 应用服务器使用 Azure AI 人脸服务创建新的活体会话。 该服务创建一个活体会话并使用会话授权令牌进行响应。 有关创建活性会话所涉及的每个请求参数的详细信息,请参阅 Liveness Create Session Operation

    var endpoint = new Uri(System.Environment.GetEnvironmentVariable("FACE_ENDPOINT"));
    var key = new AzureKeyCredential(System.Environment.GetEnvironmentVariable("FACE_APIKEY"));
    
    var body = JsonSerializer.Serialize(new
    {
        livenessOperationMode = "PassiveActive",
        deviceCorrelationId = "723d6d03-ef33-40a8-9682-23a1feb7bccd",
        enableSessionImage = true
    });
    
    using var client = new HttpClient();
    client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
    
    var response = await client.PostAsync(
        $"{endpoint}/face/v1.2/detectLiveness-sessions",
        new StringContent(body, Encoding.UTF8, "application/json"));
    
    response.EnsureSuccessStatusCode();
    
    using var doc  = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
    var root       = doc.RootElement;
    
    Console.WriteLine("Session created");
    Console.WriteLine($"sessionId : {root.GetProperty("sessionId").GetString()}");
    Console.WriteLine($"authToken : {root.GetProperty("authToken").GetString()}");
    

    响应正文的示例:

    {
        "sessionId": "a6e7193e-b638-42e9-903f-eaf60d2b40a5",
        "authToken": "<session-authorization-token>",
        "status": "NotStarted",
        "modelVersion": "2025-05-20",
        "results": {
            "attempts": []
        }
    }
    
  3. 应用服务器将会话授权令牌返回给前端应用程序。

  4. 前端应用程序使用会话授权令牌启动人脸实时检测器,这将启动实时流。

        FaceLivenessDetector(
            sessionAuthorizationToken = FaceSessionToken.sessionToken,
            verifyImageFileContent = FaceSessionToken.sessionSetInClientVerifyImage,
            deviceCorrelationId = "null",
            onSuccess = viewModel::onSuccess,
            onError = viewModel::onError
        )
    
  5. 接着,SDK 会启动相机,指导用户正确调整其姿势,然后准备有效负载以调用活体检测服务终结点。

  6. SDK 调用 Azure AI 视觉人脸服务来执行活体检测。 一旦服务进行响应,SDK 就会通知前端应用程序活体检查已完成。 注意:服务响应将不包含活体决策,这将需要从应用服务器中查询。

  7. 前端应用程序将活性检查的完成情况中继到应用服务器。

  8. 应用服务器现在可以从 Azure AI 视觉人脸服务查询活体检测结果。

    using var client = new HttpClient();
    client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
    
    var response = await client.GetAsync(
        $"{endpoint}/face/v1.2/livenessSessions/{sessionId}/result");
    
    response.EnsureSuccessStatusCode();
    
    using var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
    var root = doc.RootElement;
    var attempts = root.GetProperty("results").GetProperty("attempts");
    var latestAttempt = attempts[attempts.GetArrayLength() - 1];
    var attemptStatus = latestAttempt.GetProperty("attemptStatus").GetString();
    
    Console.WriteLine($"Session id: {root.GetProperty("sessionId").GetString()}");
    Console.WriteLine($"Session status: {root.GetProperty("status").GetString()}");
    Console.WriteLine($"Latest attempt status: {attemptStatus}");
    
    if (attemptStatus == "Succeeded")
        Console.WriteLine($"Liveness detection decision: {latestAttempt.GetProperty("result").GetProperty("livenessDecision").GetString()}");
    else
    {
        var error = latestAttempt.GetProperty("error");
        Console.WriteLine($"Error: {error.GetProperty("code").GetString()} - {error.GetProperty("message").GetString()}");
    }
    

    响应正文的示例:

    {
        "sessionId": "b12e033e-bda7-4b83-a211-e721c661f30e",
        "authToken": "eyJhbGciOiJFUzI1NiIsIm",
        "status": "NotStarted",
        "modelVersion": "2024-11-15",
        "results": {
            "attempts": [
                {
                    "attemptId": 2,
                    "attemptStatus": "Succeeded",
                    "result": {
                    "livenessDecision": "realface",
                    "targets": {
                        "color": {
                        "faceRectangle": {
                                "top": 669,
                                "left": 203,
                                "width": 646,
                                "height": 724
                            }
                        }
                    },
                    "digest": "B0A803BB7B26F3C8F29CD36030F8E63ED3FAF955FEEF8E01C88AB8FD89CCF761",
                    "sessionImageId": "Ae3PVWlXAmVAnXgkAFt1QSjGUWONKzWiSr2iPh9p9G4I"
                    }
                },
                {
                    "attemptId": 1,
                    "attemptStatus": "Failed",
                    "error": {
                    "code": "FaceWithMaskDetected",
                    "message": "Mask detected on face image.",
                    "targets": {
                            "color": {
                            "faceRectangle": {
                                "top": 669,
                                "left": 203,
                                "width": 646,
                                "height": 724
                            }
                            }
                        }
                    }
                }
            ]
        }
    }
    
  9. 查询所有会话结果后,应用服务器就可以删除该会话。

    using var client = new HttpClient();
    client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
    
    await client.DeleteAsync($"{endpoint}/face/v1.2/livenessSessions/{sessionId}");
    Console.WriteLine($"Session deleted: {sessionId}");
    

通过人脸验证执行活体检测

将人脸验证与活体检测相结合,可以对感兴趣的具体人员进行生物特征验证,进一步保证该人实际存在于系统中。

Azure AI 人脸服务提供的附带人脸验证的活体检测工作流的示意图。

将活体与验证相结合的过程分为两个部分:

步骤 1 - 选择参考图像

按照身份验证方案的构成要求中列出的提示操作,确保输入的图像能够提供最准确的识别结果。

步骤 2 - 通过验证设置活体编排。

活体验证编排涉及的大致步骤如下所示:

  1. 通过以下两种方法中的一种提供验证参考图像:

    • 应用服务器在创建活体会话时提供参考图像。 有关创建具有验证的活性会话所涉及的每个请求参数的详细信息,请参阅 Liveness With Verify Create Session Operation

      var endpoint = new Uri(System.Environment.GetEnvironmentVariable("FACE_ENDPOINT"));
      var key      = System.Environment.GetEnvironmentVariable("FACE_APIKEY");
      
      // Create the JSON part
      var jsonPart = new StringContent(
          JsonSerializer.Serialize(new
          {
              livenessOperationMode = "PassiveActive",
              deviceCorrelationId = "723d6d03-ef33-40a8-9682-23a1feb7bcc",
              enableSessionImage = true
          }),
          Encoding.UTF8,
          "application/json"
      );
      jsonPart.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
      {
          Name = "CreateLivenessWithVerifySessionRequest"
      };
      
      // Create the file part
      using var fileStream = File.OpenRead("test.png");
      var filePart = new StreamContent(fileStream);
      filePart.Headers.ContentType = new MediaTypeHeaderValue("image/png");
      filePart.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
      {
          Name = "VerifyImage",
          FileName = "test.png"
      };
      
      // Build multipart form data
      using var formData = new MultipartFormDataContent();
      formData.Add(jsonPart);
      formData.Add(filePart);
      
      using var client = new HttpClient();
      client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
      
      var response = await client.PostAsync($"{endpoint}/face/v1.2/createLivenessWithVerifySession", formData);
      response.EnsureSuccessStatusCode();
      
      using var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
      var root = doc.RootElement;
      
      Console.WriteLine("Session created.");
      Console.WriteLine($"Session id: {root.GetProperty("sessionId").GetString()}");
      Console.WriteLine($"Auth token: {root.GetProperty("authToken").GetString()}");
      

      响应正文的示例:

      {
          "sessionId": "3847ffd3-4657-4e6c-870c-8e20de52f567",
          "authToken": "<session-authorization-token>",
          "status": "NotStarted",
          "modelVersion": "2024-11-15",
          "results": {
              "attempts": [],
              "verifyReferences": [
              {
                  "referenceType": "image",
                  "faceRectangle": {
                  "top": 98,
                  "left": 131,
                  "width": 233,
                  "height": 300
                  },
                  "qualityForRecognition": "high"
              }
              ]
          }
      }
      
    • 前端应用程序在初始化移动 SDK 时提供引用映像。 Web 解决方案不支持此方案。

          FaceLivenessDetector(
              sessionAuthorizationToken = FaceSessionToken.sessionToken,
              verifyImageFileContent = FaceSessionToken.sessionSetInClientVerifyImage,
              deviceCorrelationId = "null",
              onSuccess = viewModel::onSuccess,
              onError = viewModel::onError
          )
      
  2. 除了活体结果之外,应用服务器现在还可以查询验证结果。

    using var client = new HttpClient();
    client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
    
    var response = await client.GetAsync($"{endpoint}/face/v1.2/livenessSessions/{sessionId}/result");
    response.EnsureSuccessStatusCode();
    
    using var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
    var root = doc.RootElement;
    
    var attempts = root.GetProperty("results").GetProperty("attempts");
    var latestAttempt = attempts[attempts.GetArrayLength() - 1];
    var attemptStatus = latestAttempt.GetProperty("attemptStatus").GetString();
    
    Console.WriteLine($"Session id: {root.GetProperty("sessionId").GetString()}");
    Console.WriteLine($"Session status: {root.GetProperty("status").GetString()}");
    Console.WriteLine($"Latest attempt status: {attemptStatus}");
    
    if (attemptStatus == "Succeeded")
    {
        var decision = latestAttempt.GetProperty("result").GetProperty("livenessDecision").GetString();
        var verify   = latestAttempt.GetProperty("verifyResult");
        Console.WriteLine($"Liveness detection decision: {decision}");
        Console.WriteLine($"Verify isIdentical: {verify.GetProperty("isIdentical").GetBoolean()}");
        Console.WriteLine($"Verify matchConfidence: {verify.GetProperty("matchConfidence").GetDouble()}");
    }
    else
    {
        var err = latestAttempt.GetProperty("error");
        Console.WriteLine($"Error: {err.GetProperty("code").GetString()} - {err.GetProperty("message").GetString()}");
    }
    

    响应正文的示例:

    {
        "sessionId": "b12e033e-bda7-4b83-a211-e721c661f30e",
        "authToken": "eyJhbGciOiJFUzI1NiIsIm",
        "status": "NotStarted",
        "modelVersion": "2024-11-15",
        "results": {
            "attempts": [
            {
                "attemptId": 2,
                "attemptStatus": "Succeeded",
                "result": {
                "livenessDecision": "realface",
                "targets": {
                    "color": {
                    "faceRectangle": {
                        "top": 669,
                        "left": 203,
                        "width": 646,
                        "height": 724
                    }
                    }
                },
                "verifyResult": {
                    "matchConfidence": 0.08871888,
                    "isIdentical": false
                },
                "digest": "B0A803BB7B26F3C8F29CD36030F8E63ED3FAF955FEEF8E01C88AB8FD89CCF761",
                "sessionImageId": "Ae3PVWlXAmVAnXgkAFt1QSjGUWONKzWiSr2iPh9p9G4I",
                "verifyImageHash": "43B7D8E8769533C3290DBD37A84D821B2C28CB4381DF9C6784DBC4AAF7E45018"
                }
            },
            {
                "attemptId": 1,
                "attemptStatus": "Failed",
                "error": {
                    "code": "FaceWithMaskDetected",
                    "message": "Mask detected on face image.",
                    "targets": {
                        "color": {
                        "faceRectangle": {
                                "top": 669,
                                "left": 203,
                                "width": 646,
                                "height": 724
                            }
                        }
                    }
                }
            }
            ],
            "verifyReferences": [
                {
                    "referenceType": "image",
                    "faceRectangle": {
                    "top": 316,
                    "left": 131,
                    "width": 498,
                    "height": 677
                    },
                    "qualityForRecognition": "high"
                }
            ]
            }
        }
    
  3. 如果不再需要会话结果,应用服务器可以删除会话。

    using var client = new HttpClient();
    client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
    
    await client.DeleteAsync($"{endpoint}/face/v1.2/livenessWithVerifySessions/{sessionId}");
    Console.WriteLine($"Liveness-with-Verify session deleted: {sessionId}");
    

在活体检测后执行其他人脸操作

(可选)可以在活体检查之后执行进一步的人脸操作,例如人脸分析(如获取人脸属性)和/或人脸标识操作。

  1. 若要启用此功能,需要在执行 Session-Creation 步骤期间将“enableSessionImage”参数设置为“true”。
  2. 会话完成后,可以从 Session-Get-Result 步骤中提取“sessionImageId”。
  3. 现在,你既可以下载会话图像(可参考活体状态:获取会话映像操作 API),也可以在根据会话图像 ID 进行检测 API操作中提供 "sessionImageId",以便继续执行其他人脸分析或人脸识别操作。 有关这些操作的详细信息,请参阅人脸检测概念人脸识别概念

支持选项

除了使用主要的 Azure AI 服务支持选项之外,还可以在 SDK 存储库的问题部分发布问题。

若要了解如何将活体解决方案集成到现有的应用程序,请参阅 Azure AI 视觉 SDK 参考。

若要详细了解可用于协调实时解决方案的功能,请参阅会话 REST API 参考。