Узнайте, как интегрировать обнаружение активности лиц в рабочий процесс с помощью логики на стороне сервера и клиентских приложений внешнего интерфейса.
В этом руководстве описано, как запустить интерфейсное приложение с сервером приложений для обнаружения активности. Кроме того, можно добавить проверку лиц на различных платформах и языках.
Это важно
Пакеты SDK для клиента распознавания лиц для определения живости — это функция с ограниченным доступом. Необходимо запросить доступ к функции проверки живости, заполнив форму-заявку на распознавание лиц. Когда подписка Azure предоставляет доступ, вы можете скачать пакет SDK для распознавания лиц.
Необходимые условия
- Подписка Azure — создайте бесплатную учетную запись.
- Для вашей учетной записи Azure должна быть назначена роль Участник служб когнитивных служб, чтобы вы могли согласиться с условиями ответственного использования ИИ и создать ресурс. Чтобы назначить эту роль своей учетной записи, следуйте инструкциям, описанным в документации по назначению ролей, или обратитесь к администратору.
- После получения подписки Azure на портале Azure, чтобы получить ключ и конечную точку. После развертывания выберите Перейти к ресурсу.
- Вам потребуется ключ и конечная точка из ресурса, создаваемого для подключения приложения к службе распознавания лиц.
- Доступ к закрытым артефактам, необходимым для Azure Vision в пакете инструментов Foundry, при использовании клиентского SDK для распознавания лиц на мобильных устройствах (iOS и Android) и в Интернет.
- Знакомство с функцией определения живости лица. См. концептуальное руководство.
Подсказка
После выполнения необходимых условий вы можете попробовать опыт взаимодействия в реальном времени на следующих платформах:
-
iOS: iOS App Store — коснитесь экрана приложения 10 раз после установки, чтобы включить режим разработчика.
- Android: Google Play Store — коснитесь экрана приложения 10 раз после установки, чтобы включить режим разработчика.
- Веб: испытайте его прямо в Vision Studio.
Вы также можете создать и запустить полный пример внешнего интерфейса (iOS, Android или Web) из раздела "Примеры ".
Подготовка интерфейсного приложения
Пакеты SDK доступны на нескольких языках, чтобы упростить интеграцию с интерфейсным приложением. Ознакомьтесь с readME для выбранного пакета SDK в следующих разделах, чтобы интегрировать пользовательский интерфейс и обязательный код.
Это важно
Для каждого внешнего пакета SDK требуется доступ к закрытому ресурсу для успешной компиляции. См. следующие инструкции по настройке этого доступа.
Для Swift iOS:
Для Kotlin/Java Android:
Для JavaScript Web:
После интеграции с фронтенд-приложением пакет SDK запускает камеру, направляет пользователя для настройки своей позиции, создает пакет данных активности и отправляет его в службу Azure Face для обработки.
Отслеживайте раздел Releases для новых обновлений версии пакета SDK и включите оповещения об автоматическом обновлении зависимостей, такие как GitHub Dependabot (для репозиториев GitHub) или Ремонт (GitHub, GitLab, Bitbucket, Azure Repos).
Ниже описан процесс оркестрации активности.
Интерфейсное приложение запускает проверку активности и уведомляет сервер приложений.
Сервер приложений создает новый сеанс активности с помощью Службы распознавания лиц Azure. Служба создает сеанс активности и отвечает маркером авторизации сеанса. Дополнительные сведения о каждом параметре запроса, связанном с созданием сеанса liveness, см. в разделе операция 'Создание сеанса liveness'.
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()}");
String endpoint = System.getenv("FACE_ENDPOINT");
String key = System.getenv("FACE_APIKEY");
String body = """
{
"livenessOperationMode": "PassiveActive",
"deviceCorrelationId": "723d6d03-ef33-40a8-9682-23a1feb7bccd",
"enableSessionImage": true,
}
""";
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create(endpoint + "/face/v1.2/detectLiveness-sessions"))
.header("Content-Type", "application/json")
.header("Ocp-Apim-Subscription-Key", key)
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> res = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
if (res.statusCode() != 200) throw new RuntimeException("HTTP error: " + res.statusCode());
JsonNode json = new ObjectMapper().readTree(res.body());
System.out.println("Session created");
System.out.println("sessionId : " + json.get("sessionId").asText());
System.out.println("authToken : " + json.get("authToken").asText());
endpoint = os.environ["FACE_ENDPOINT"]
key = os.environ["FACE_APIKEY"]
url = f"{endpoint}/face/v1.2/detectLiveness-sessions"
body = {
"livenessOperationMode": "PassiveActive",
"deviceCorrelationId": "723d6d03-ef33-40a8-9682-23a1feb7bccd",
"enableSessionImage": True
}
headers = {
"Ocp-Apim-Subscription-Key": key,
"Content-Type": "application/json"
}
res = requests.post(url, headers=headers, data=json.dumps(body))
res.raise_for_status()
data = res.json()
print("Session created")
print("sessionId :", data["sessionId"])
print("authToken :", data["authToken"])
const endpoint = process.env['FACE_ENDPOINT'];
const apikey = process.env['FACE_APIKEY'];
const url = `${endpoint}/face/v1.2/detectLiveness-sessions`;
const body = {
livenessOperationMode: "PassiveActive",
deviceCorrelationId: "723d6d03-ef33-40a8-9682-23a1feb7bccd",
enableSessionImage: true
};
const headers = {
"Ocp-Apim-Subscription-Key": key,
"Content-Type": "application/json"
};
async function createLivenessSession() {
const res = await fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body)
});
if (!res.ok) {
throw new Error(`${res.status} ${await res.text()}`);
}
const data = await res.json();
console.log("Session created");
console.log("sessionId :", data.sessionId);
console.log("authToken :", data.authToken);
}
curl --request POST --location "%FACE_ENDPOINT%/face/v1.2/detectLiveness-sessions" ^
--header "Ocp-Apim-Subscription-Key: %FACE_APIKEY%" ^
--header "Content-Type: application/json" ^
--data ^
"{ ^
""livenessOperationMode"": ""passiveactive"", ^
""deviceCorrelationId"": ""723d6d03-ef33-40a8-9682-23a1feb7bccd"", ^
""enableSessionImage"": ""true"" ^
}"
curl --request POST --location "${FACE_ENDPOINT}/face/v1.2/detectLivenesswithVerify-sessions" \
--header "Ocp-Apim-Subscription-Key: ${FACE_APIKEY}" \
--header "Content-Type: application/json" \
--data \
'{
"livenessOperationMode": "passiveactive",
"deviceCorrelationId": "723d6d03-ef33-40a8-9682-23a1feb7bccd",
"enableSessionImage": "true"
}'
Пример текста ответа:
{
"sessionId": "a6e7193e-b638-42e9-903f-eaf60d2b40a5",
"authToken": "<session-authorization-token>",
"status": "NotStarted",
"modelVersion": "2025-05-20",
"results": {
"attempts": []
}
}
Сервер приложений предоставляет маркер авторизации сеанса обратно в клиентское приложение.
Интерфейсное приложение использует маркер авторизации сеанса для запуска детектора активности лиц, который запускает поток активности.
FaceLivenessDetector(
sessionAuthorizationToken = FaceSessionToken.sessionToken,
verifyImageFileContent = FaceSessionToken.sessionSetInClientVerifyImage,
deviceCorrelationId = "null",
onSuccess = viewModel::onSuccess,
onError = viewModel::onError
)
struct HostView: View {
@State var livenessDetectionResult: LivenessDetectionResult? = nil
var token: String
var body: some View {
if livenessDetectionResult == nil {
FaceLivenessDetectorView(result: $livenessDetectionResult,
sessionAuthorizationToken: token)
} else if let result = livenessDetectionResult {
VStack {
switch result {
case .success(let success):
/// <#show success#>
case .failure(let error):
/// <#show failure#>
}
}
}
}
}
faceLivenessDetector = document.createElement("azure-ai-vision-face-ui");
document.getElementById("container").appendChild(faceLivenessDetector);
faceLivenessDetector.start(session.authToken)
Пакет SDK запускает камеру, помогает пользователю правильно расположиться, а затем подготавливает полезную нагрузку для вызова конечной точки службы проверки на жизнеспособность.
Пакет SDK вызывает службу Azure Vision Face для выполнения проверки живости. Когда служба отвечает, пакет SDK уведомляет интерфейсное приложение о завершении проверки активности. Ответ службы не содержит решения о жизнеспособности. Запросите эти сведения с сервера приложений.
Интерфейсное приложение передает завершение проверки активности серверу приложений.
Сервер приложений запрашивает результат определения живости из службы распознавания лиц Azure Vision.
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()}");
}
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create(endpoint + "/face/v1.2/livenessSessions/" + sessionId + "/result"))
.header("Ocp-Apim-Subscription-Key", key)
.GET()
.build();
HttpResponse<String> res = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
if (res.statusCode() != 200) throw new RuntimeException("HTTP error: " + res.statusCode());
JsonNode root = new ObjectMapper().readTree(res.body());
JsonNode attempts = root.path("results").path("attempts");
JsonNode latestAttempt = attempts.get(attempts.size() - 1);
String attemptStatus = latestAttempt.path("attemptStatus").asText();
System.out.println("Session id: " + root.path("sessionId").asText());
System.out.println("Session status: " + root.path("status").asText());
System.out.println("Latest attempt status: " + attemptStatus);
if ("Succeeded".equals(attemptStatus)) {
System.out.println("Liveness detection decision: " +
latestAttempt.path("result").path("livenessDecision").asText());
} else {
JsonNode error = latestAttempt.path("error");
System.out.println("Error: " + error.path("code").asText() + " - " +
error.path("message").asText());
}
url = f"{endpoint}/face/v1.2/livenessSessions/{sessionId}/result"
headers = { "Ocp-Apim-Subscription-Key": key }
res = requests.get(url, headers=headers)
res.raise_for_status()
data = res.json()
attempts = data["results"]["attempts"]
latest_attempt = attempts[-1]
attempt_status = latest_attempt.get("attemptStatus")
print(f"Session id: {data['sessionId']}")
print(f"Session status: {data['status']}")
print(f"Latest attempt status: {attempt_status}")
if attempt_status == "Succeeded":
print(f"Liveness detection decision: {latest_attempt['result']['livenessDecision']}")
else:
err = latest_attempt.get("error", {})
print(f"Error: {err.get('code')} - {err.get('message')}")
const url = `${endpoint}/face/v1.2/livenessSessions/${sessionId}/result`;
const headers = {
"Ocp-Apim-Subscription-Key": apikey
};
async function getLivenessSessionResult() {
const res = await fetch(url, { method: "GET", headers });
if (!res.ok) {
throw new Error(`${res.status} ${await res.text()}`);
}
const data = await res.json();
const attempts = data.results.attempts;
const latestAttempt = attempts[attempts.length - 1];
const attemptStatus = latestAttempt.attemptStatus;
console.log("Session id :", data.sessionId);
console.log("Session status :", data.status);
console.log("Latest attempt status :", attemptStatus);
if (attemptStatus === "Succeeded") {
console.log("Liveness detection decision :", latestAttempt.result.livenessDecision);
} else {
const err = latestAttempt.error || {};
console.log(`Error: ${err.code} - ${err.message}`);
}
}
curl --request GET --location "%FACE_ENDPOINT%/face/v1.2/detectLiveness-sessions/<session-id>" ^
--header "Ocp-Apim-Subscription-Key: %FACE_APIKEY%"
curl --request GET --location "${FACE_ENDPOINT}/face/v1.2/detectLiveness-sessions/<session-id>" \
--header "Ocp-Apim-Subscription-Key: ${FACE_APIKEY}"
Пример текста ответа:
{
"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
}
}
}
}
}
]
}
}
Сервер приложений удаляет сеанс после запроса всех результатов сеанса.
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}");
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create(endpoint + "/face/v1.2/livenessSessions/" + sessionId))
.header("Ocp-Apim-Subscription-Key", key)
.DELETE()
.build();
HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
System.out.println("Session deleted: " + sessionId);
headers = { "Ocp-Apim-Subscription-Key": key }
requests.delete(f"{endpoint}/face/v1.2/livenessSessions/{sessionId}", headers=headers)
print(f"Session deleted: {sessionId}")
const headers = { "Ocp-Apim-Subscription-Key": apikey };
await fetch(`${endpoint}/face/v1.2/livenessSessions/${sessionId}`, { method: "DELETE", headers });
console.log(`Session deleted: ${sessionId}`);
curl --request DELETE --location "%FACE_ENDPOINT%/face/v1.2/detectLiveness-sessions/<session-id>" ^
--header "Ocp-Apim-Subscription-Key: %FACE_APIKEY%"
curl --request DELETE --location "${FACE_ENDPOINT}/face/v1.2/detectLiveness-sessions/<session-id>" \
--header "Ocp-Apim-Subscription-Key: ${FACE_APIKEY}"
Объединение проверки лица с определением реальности позволяет осуществлять биометрическую проверку конкретного человека, представляющего интерес, с дополнительной гарантией того, что этот человек физически присутствует в системе.
Интеграция обнаружения активности с проверкой включает две части:
Шаг 1. Выбор эталонного изображения
Чтобы получить наиболее точные результаты распознавания, следуйте рекомендациям, приведенным в требованиях к композиции для сценариев проверки идентификаторов.
Шаг 2. Настройка оркестрации живости с проверкой
На следующих высокоуровневых шагах показано, как оркестрировать живость с проверкой.
Предоставьте эталонный образ проверки с помощью одного из следующих двух методов:
Сервер приложений предоставляет эталонный образ при создании сеанса проверки живости. Дополнительные сведения о каждом параметре запроса, связанном с созданием сеанса активности с проверкой подлинности, см. в статье 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()}");
String endpoint = System.getenv("FACE_ENDPOINT");
String key = System.getenv("FACE_APIKEY");
String json = """
{
"livenessOperationMode": "PassiveActive",
"deviceCorrelationId": "723d6d03-ef33-40a8-9682-23a1feb7bcc",
"enableSessionImage": true
}
""";
byte[] img = Files.readAllBytes(Path.of("test.png"));
String boundary = "----faceBoundary" + java.util.UUID.randomUUID();
var head =
"--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"CreateLivenessWithVerifySessionRequest\"\r\n" +
"Content-Type: application/json\r\n\r\n" +
json + "\r\n" +
"--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"VerifyImage\"; filename=\"test.png\"\r\n" +
"Content-Type: image/png\r\n\r\n";
var tail = "\r\n--" + boundary + "--\r\n";
byte[] body = java.nio.ByteBuffer
.allocate(head.getBytes(StandardCharsets.UTF_8).length + img.length + tail.getBytes(StandardCharsets.UTF_8).length)
.put(head.getBytes(StandardCharsets.UTF_8))
.put(img)
.put(tail.getBytes(StandardCharsets.UTF_8))
.array();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create(endpoint + "/face/v1.2/createLivenessWithVerifySession"))
.header("Ocp-Apim-Subscription-Key", key)
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
.POST(HttpRequest.BodyPublishers.ofByteArray(body))
.build();
HttpResponse<String> res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
if (res.statusCode() != 200) throw new RuntimeException("HTTP error: " + res.statusCode());
JsonNode root = new ObjectMapper().readTree(res.body());
System.out.println("Session created.");
System.out.println("Session id: " + root.get("sessionId").asText());
System.out.println("Auth token: " + root.get("authToken").asText());
endpoint = os.environ["FACE_ENDPOINT"]
key = os.environ["FACE_APIKEY"]
url = f"{endpoint}/face/v1.2/createLivenessWithVerifySession"
files = {
"CreateLivenessWithVerifySessionRequest": (
"request.json",
json.dumps({
"livenessOperationMode": "PassiveActive",
"deviceCorrelationId": "723d6d03-ef33-40a8-9682-23a1feb7bcc",
"enableSessionImage": True
}),
"application/json"
),
"VerifyImage": ("test.png", open("test.png", "rb"), "image/png")
}
headers = { "Ocp-Apim-Subscription-Key": key }
res = requests.post(url, headers=headers, files=files)
res.raise_for_status()
data = res.json()
print("Session created.")
print("Session id:", data["sessionId"])
print("Auth token:", data["authToken"])
const endpoint = process.env["FACE_ENDPOINT"];
const apikey = process.env["FACE_APIKEY"];
const form = new FormData();
form.append(
"CreateLivenessWithVerifySessionRequest",
new Blob([JSON.stringify({
livenessOperationMode: "PassiveActive",
deviceCorrelationId: "723d6d03-ef33-40a8-9682-23a1feb7bcc",
enableSessionImage: true
})], { type: "application/json" }),
"request.json"
);
// If your runtime doesn't support Blob here, you can use fs.createReadStream instead.
form.append("VerifyImage", new Blob([fs.readFileSync("test.png")], { type: "image/png" }), "test.png");
const res = await fetch(`${endpoint}/face/v1.2/createLivenessWithVerifySession`, {
method: "POST",
headers: { "Ocp-Apim-Subscription-Key": apikey },
body: form
});
if (!res.ok) {
throw new Error(`${res.status} ${await res.text()}`);
}
const data = await res.json();
console.log("Session created.");
console.log("Session id:", data.sessionId);
console.log("Auth token:", data.authToken);
curl --request POST --location "%FACE_ENDPOINT%/face/v1.2/detectLivenesswithVerify-sessions" ^
--header "Ocp-Apim-Subscription-Key: %FACE_APIKEY%" ^
--form "Parameters=""{\\\""livenessOperationMode\\\"": \\\""passiveactive\\\"", \\\""deviceCorrelationId\\\"": \\\""723d6d03-ef33-40a8-9682-23a1feb7bccd\\\"", ""enableSessionImage"": ""true""}""" ^
--form "VerifyImage=@""test.png"""
curl --request POST --location "${FACE_ENDPOINT}/face/v1.2/detectLivenesswithVerify-sessions" \
--header "Ocp-Apim-Subscription-Key: ${FACE_APIKEY}" \
--form 'Parameters="{
\"livenessOperationMode\": \"passiveactive\",
\"deviceCorrelationId\": \"723d6d03-ef33-40a8-9682-23a1feb7bccd\"
}"' \
--form 'VerifyImage=@"test.png"'
Пример текста ответа:
{
"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
)
struct HostView: View {
@State var livenessDetectionResult: LivenessDetectionResult? = nil
var token: String
var body: some View {
if livenessDetectionResult == nil {
FaceLivenessDetectorView(result: $livenessDetectionResult,
sessionAuthorizationToken: token)
} else if let result = livenessDetectionResult {
VStack {
switch result {
case .success(let success):
/// <#show success#>
case .failure(let error):
/// <#show failure#>
}
}
}
}
}
Теперь сервер приложений может запрашивать результат проверки в дополнение к результату активности.
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()}");
}
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create(endpoint + "/face/v1.2/livenessSessions/" + sessionId + "/result"))
.header("Ocp-Apim-Subscription-Key", key)
.GET()
.build();
HttpResponse<String> res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
if (res.statusCode() != 200) throw new RuntimeException("HTTP error: " + res.statusCode());
ObjectMapper om = new ObjectMapper();
JsonNode root = om.readTree(res.body());
JsonNode attempts = root.path("results").path("attempts");
JsonNode latest = attempts.get(attempts.size() - 1);
String attemptStatus = latest.path("attemptStatus").asText();
System.out.println("Session id: " + root.path("sessionId").asText());
System.out.println("Session status: " + root.path("status").asText());
System.out.println("Latest attempt status: " + attemptStatus);
if ("Succeeded".equals(attemptStatus)) {
String decision = latest.path("result").path("livenessDecision").asText();
JsonNode verify = latest.path("verifyResult");
System.out.println("Liveness detection decision: " + decision);
System.out.println("Verify isIdentical: " + verify.path("isIdentical").asBoolean());
System.out.println("Verify matchConfidence: " + verify.path("matchConfidence").asDouble());
} else {
JsonNode err = latest.path("error");
System.out.println("Error: " + err.path("code").asText() + " - " + err.path("message").asText());
}
url = f"{endpoint}/face/v1.2/livenessSessions/{sessionId}/result"
headers = {"Ocp-Apim-Subscription-Key": key}
res = requests.get(url, headers=headers)
res.raise_for_status()
data = res.json()
attempts = data["results"]["attempts"]
latest = attempts[-1]
attempt_status = latest.get("attemptStatus")
print(f"Session id: {data['sessionId']}")
print(f"Session status: {data['status']}")
print(f"Latest attempt status: {attempt_status}")
if attempt_status == "Succeeded":
decision = latest["result"]["livenessDecision"]
verify = latest.get("verifyResult", {})
print(f"Liveness detection decision: {decision}")
print(f"Verify isIdentical: {verify.get('isIdentical')}")
print(f"Verify matchConfidence: {verify.get('matchConfidence')}")
else:
err = latest.get("error", {})
print(f"Error: {err.get('code')} - {err.get('message')}")
const url = `${endpoint}/face/v1.2/livenessSessions/${sessionId}/result`;
const headers = { "Ocp-Apim-Subscription-Key": apikey };
async function getLivenessWithVerifyResult() {
const res = await fetch(url, { method: "GET", headers });
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
const attempts = data.results.attempts;
const latest = attempts[attempts.length - 1];
const attemptStatus = latest.attemptStatus;
console.log("Session id:", data.sessionId);
console.log("Session status:", data.status);
console.log("Latest attempt status:", attemptStatus);
if (attemptStatus === "Succeeded") {
console.log("Liveness detection decision:", latest.result.livenessDecision);
console.log("Verify isIdentical:", latest.verifyResult?.isIdentical);
console.log("Verify matchConfidence:", latest.verifyResult?.matchConfidence);
} else {
const err = latest.error || {};
console.log(`Error: ${err.code} - ${err.message}`);
}
}
curl --request GET --location "%FACE_ENDPOINT%/face/v1.2/detectLivenesswithVerify-sessions/<session-id>" ^
--header "Ocp-Apim-Subscription-Key: %FACE_APIKEY%"
curl --request GET --location "${FACE_ENDPOINT}/face/v1.2/detectLivenesswithVerify-sessions/<session-id>" \
--header "Ocp-Apim-Subscription-Key: ${FACE_APIKEY}"
Пример текста ответа:
{
"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"
}
]
}
}
Сервер приложений может удалить сеанс, если его результат больше не нужен.
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}");
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create(endpoint + "/face/v1.2/livenessWithVerifySessions/" + sessionId))
.header("Ocp-Apim-Subscription-Key", key)
.DELETE()
.build();
HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
System.out.println("Liveness-with-Verify session deleted: " + sessionId);
headers = { "Ocp-Apim-Subscription-Key": key }
requests.delete(f"{endpoint}/face/v1.2/livenessWithVerifySessions/{sessionId}", headers=headers)
print(f"Liveness-with-Verify session deleted: {sessionId}")
const headers = { "Ocp-Apim-Subscription-Key": apikey };
await fetch(`${endpoint}/face/v1.2/livenessWithVerifySessions/${sessionId}`, { method: "DELETE", headers });
console.log(`Liveness-with-Verify session deleted: ${sessionId}`);
curl --request DELETE --location "%FACE_ENDPOINT%/face/v1.2/detectLivenesswithVerify-sessions/<session-id>" ^
--header "Ocp-Apim-Subscription-Key: %FACE_APIKEY%"
curl --request DELETE --location "${FACE_ENDPOINT}/face/v1.2/detectLivenesswithVerify-sessions/<session-id>" \
--header "Ocp-Apim-Subscription-Key: ${FACE_APIKEY}"
При необходимости можно выполнять дополнительные операции распознавания лиц после проверки активности, например анализа лиц (для получения атрибутов лиц) и операций идентификации лиц.
- Установите параметр
enableSessionImage на true во время этапа создания сессии.
- Извлеките
sessionImageId из шага сеанса Get-Result.
- Скачайте изображение сеанса (упомянутое в API операции получения изображения сеанса Liveness), или предоставьте
sessionImageId в операции API обнаружения по идентификатору изображения сеанса, чтобы продолжить другие операции анализа лиц или операций с идентичностью лиц.
Дополнительные сведения об этих операциях см. в концепциях обнаружения лиц и концепциях распознавания лиц.
Варианты поддержки
Помимо использования основных вариантов поддержки средств Foundry, вы также можете опубликовать свои вопросы в разделе вопросов репозитория SDK.
Связанный контент
Чтобы узнать, как интегрировать решение liveness в существующее приложение, ознакомьтесь со справочником по пакету SDK для визуального распознавания Azure.
Чтобы узнать больше о функциях, доступных для оркестрации решения для проверки живости, смотрите справочник по сеансовому REST API.