教學課程:偵測臉部活動

學習如何利用伺服器端邏輯及伴隨前端客戶端應用程式,將臉部直播偵測整合進您的工作流程中。

小提示

如需臉部活躍度偵測的一般資訊,請參閱 概念指南。

在這個教學中,你將學習如何搭配應用程式伺服器執行前端應用程式來進行活度偵測。 你也可以在各種平台和語言上新增 臉部驗證 功能。

這很重要

適用於臉部活動的臉部用戶端 SDK 是一項受管制功能。 您必須填寫臉部辨識資訊表單以要求存取活體檢測功能。 當您的 Azure 訂用帳戶獲得存取權時,您可以下載人臉活體檢測 SDK。

先決條件

  • Azure 訂用帳戶 - 建立免費帳戶
  • 你的Azure帳號必須被分配一個認知服務貢獻者角色,這樣你才能同意負責任的 AI 條款並建立資源。 若要將此角色指派給您的帳戶,請遵循指派角色文件中的步驟,或連絡系統管理員。
  • 當你擁有 Azure 訂閱後,建立,在 Azure 入口網站建立一個 Face 資源,取得你的金鑰和端點。 在其部署後,選取 [前往資源]。
    • 您需要來自所建立資源的金鑰和端點,以將應用程式連線至人臉服務。
  • 存取適用於行動裝置 (iOS 和 Android)和 Web 的 Foundry Tools 臉部用戶端 SDK 中 Azure Vision 所需的閘道成品。
  • 熟悉臉部活動偵測功能。 請參閱 概念指南。

小提示

完成先決條件後,即可在以下平台上嘗試活動體驗:

  • iOS: iOS App Store — 安裝後點擊應用程式畫面 10 次即可啟用開發者模式。
  • Android: Google Play 商店 — 安裝後點擊應用程式畫面 10 次即可啟用開發者模式。
  • 網路:直接在 Vision Studio 裡試試看。

你也可以從 範例 區塊建立並執行完整的前端範例(iOS、Android 或網頁版)。

準備前端應用程式

SDK 有多種語言版本,方便與前端應用程式整合。 請參閱以下章節中所選 SDK 的 README,以整合使用者介面與所需程式碼。

這很重要

每個前端 SDK 都需要存取閘控資產才能成功編譯。 請參考以下說明來設定此存取權限。

適用於 Swift iOS:

適用於 Kotlin/Java Android:

適用於 JavaScript Web:

一旦整合到前端應用程式中,SDK 會啟動攝影機,引導使用者調整位置,撰寫即時負載,並送至 Azure Face 服務進行處理。

監控倉庫的 Releases 區塊 是否有新的 SDK 版本更新,並啟用自動相依關係更新警示——例如 GitHub Dependabot(針對GitHub倉庫)或 Renovate(GitHub、GitLab、Bitbucket、Azure Repos)。

執行臉部活動偵測

以下步驟說明活躍度的協調流程:

Azure Face 中 liveness 工作流程的示意圖。

  1. 前端應用程式會啟動存活檢查,並通知應用程式伺服器。

  2. 應用程式伺服器會建立一個具有 Azure 臉部服務的新直播工作階段。 該服務建立一個活躍度工作階段,並回傳工作階段授權權杖。 關於建立 liveness session 所涉及的每個請求參數的更多資訊,請參閱 Liveness Create Session 操作。

    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 Vision Face 服務來執行活度偵測。 當服務回應時,SDK 會通知前端應用程式活體檢查完成。 服務回應未包含存留性判斷。 請從應用程式伺服器查詢這些資訊。

  7. 前端應用程式會將存活檢查的完成狀態傳送到應用程式伺服器。

  8. 應用程式伺服器會查詢 Azure Vision Face 服務的活體偵測結果。

    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 Face 活體檢測與面部驗證工作流程示意圖

將活體偵測與驗證整合包含兩個部分:

步驟 1 - 選取參考影像

為了獲得最準確的辨識結果,請遵循身分 驗證情境寫作要求中列出的建議。

步驟 2 - 設定含驗證的活躍度的協調流程

以下高階步驟會顯示如何協調含驗證的活躍度:

  1. 請使用以下兩種方法之一提供驗證參考影像:

    • 應用程式伺服器會在建立臉部活動工作階段時提供參考影像。 關於建立帶驗證的生命狀態會話所需的每個請求參數的更多資訊,請參見 「生命狀態驗證建立會話操作」。

      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時提供參考映像。 這個情境在網頁解決方案中並不支援。

          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. 在 enableSessionImage中將參數設定true為。
  2. 從 sessionImageId中擷取 。
  3. 下載會話影像(參考 Liveness Get Session Image Operation API 中),或在sessionImageId」操作中提供,以繼續進行其他臉部分析或臉部身份操作。 如需這些作業的詳細資訊,請參閱 臉部偵測概念 和 臉部辨識概念。

支援選項

除了使用 Foundry Tools 的主要支援選項外,你也可以在 SDK 倉庫的 issues 區塊發問。

想了解如何將活化解決方案整合到現有應用程式中,請參閱 Azure Vision SDK 參考資料。

若要深入了解可用來協調臉部活動解決方案的功能,請參閱工作階段 REST API 參考。