Использование структуры данных PersonDirectory (предварительная версия)

Внимание

Доступ к службе "Распознавание лиц" ограничен на основе соответствия требованиям и критериев использования для реализации поддержки наших принципов ответственного ИИ. Служба "Распознавание лиц" доступна только для клиентов и партнеров, управляемых корпорацией Майкрософт. Используйте форму приема Распознавания лиц, чтобы подать заявку на доступ. Дополнительные сведения см. на странице с ограниченным доступом для лиц.

Для выполнения таких операций распознавания лиц, как «Идентификация» и «Поиск похожих», клиентам API службы Распознавания лиц необходимо создать отсортированный список объектов Person. PersonDirectory представляет собой структуру данных в общедоступной предварительной версии, содержащую уникальные идентификаторы, необязательные строки имен и необязательные строки метаданных пользователя для каждого идентификатора Person, добавленного в каталог. В этом руководстве объясняется, как выполнять основные задачи с помощью PersonDirectory.

Преимущества PersonDirectory

В настоящее время API службы Распознавания лиц предлагает структуру LargePersonGroup, которая имеет аналогичную функциональность, но ограничена 1 миллионом идентификаторов. Структура PersonDirectory может масштабироваться до 75 миллионов идентификаторов.

Еще одно важное отличие между PersonDirectory и предыдущими структурами данных заключается в том, что вам больше не нужно будет выполнять какие-либо вызовы API Train после добавления лиц в объект Person — процесс обновления происходит автоматически.

Необходимые компоненты

  • Подписка Azure — создайте бесплатную учетную запись.
  • Получив подписку Azure, создайте ресурс Распознавания лиц на портале Azure, чтобы получить ключ и конечную точку. После развертывания ресурса выберите элемент Перейти к ресурсу.
    • Для подключения приложения к API Распознавания лиц потребуется ключ и конечная точка из созданного ресурса. Вы вставите свой ключ и конечную точку в нижеприведенный код.
    • Используйте бесплатную ценовую категорию (F0), чтобы опробовать службу, а затем выполните обновление до платного уровня для рабочей среды.

Добавление людей в PersonDirectory

Persons - это базовые единицы регистрации в PersonDirectory. После добавления Человека (Person) в каталог вы можете добавить до 248 изображений лиц к Person для каждой модели распознавания. После этого вы можете идентифицировать лица против них, используя различные прицелы.

Создание Person

Чтобы создать Person, необходимо вызвать API CreatePerson и указать имя или значение свойства userData.

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

var client = new HttpClient();

// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{subscription key}");

var addPersonUri = "https:// {endpoint}/face/v1.0-preview/persons";

HttpResponseMessage response;

// Request body
var body = new Dictionary<string, object>();
body.Add("name", "Example Person");
body.Add("userData", "User defined data");
byte[] byteData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(body));

using (var content = new ByteArrayContent(byteData))
{
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    response = await client.PostAsync(addPersonUri, content); 
}

Вызов функции CreatePerson вернет сгенерированный идентификатор для Person и местоположение операции. Данные Person будут обрабатываться асинхронно, поэтому вы используете местоположение операции для получения результатов.

Дождитесь завершения асинхронной операции

Вам нужно будет запросить статус асинхронной операции, используя возвращенную строку местоположения операции, чтобы проверить ход выполнения.

Во-первых, вы должны определить модель данных, подобную следующей, для обработки ответа о состоянии.

[Serializable]
public class AsyncStatus
{
    [DataMember(Name = "status")]
    public string Status { get; set; }

    [DataMember(Name = "createdTime")]
    public DateTime CreatedTime { get; set; }

    [DataMember(Name = "lastActionTime")]
    public DateTime? LastActionTime { get; set; }

    [DataMember(Name = "finishedTime", EmitDefaultValue = false)]
    public DateTime? FinishedTime { get; set; }

    [DataMember(Name = "resourceLocation", EmitDefaultValue = false)]
    public string ResourceLocation { get; set; }

    [DataMember(Name = "message", EmitDefaultValue = false)]
    public string Message { get; set; }
}

Затем, используя HttpResponseMessage, указанный выше, вы можете опросить URL-адрес и дождаться результатов.

string operationLocation = response.Headers.GetValues("Operation-Location").FirstOrDefault();

Stopwatch s = Stopwatch.StartNew();
string status = "notstarted";
do
{
    if (status == "succeeded")
    {
        await Task.Delay(500);
    }

    var operationResponseMessage = await client.GetAsync(operationLocation);

    var asyncOperationObj = JsonConvert.DeserializeObject<AsyncStatus>(await operationResponseMessage.Content.ReadAsStringAsync());
    status = asyncOperationObj.Status;

} while ((status == "running" || status == "notstarted") && s.Elapsed < TimeSpan.FromSeconds(30));

Когда статус возвращается как «выполнено успешно», объект Person считается добавленным в каталог.

Примечание.

Асинхронная операция из вызова Create Person не должна показывать статус "выполнено успешно", прежде чем лица могут быть добавлены к ней, но ее необходимо завершить, прежде чем можно будет добавить Person в DynamicPersonGroup (см. ниже Создание и обновление DynamicPersonGroup) или произвести сравнение во время вызова Identify. Убедитесь, что вызовы будут работать сразу после успешного добавления лиц к Person.

Добавить лица к Persons

Получив идентификатор Person из вызова Create Person (Создать Человека), вы можете добавить до 248 изображений лиц к Person для каждой модели распознавания. Укажите модель распознавания (и, по выбору, модель обнаружения) для использования в вызове, поскольку данные каждой модели распознавания будут обрабатываться отдельно внутри PersonDirectory.

В настоящее время поддерживаются следующие модели распознавания:

  • Recognition_02
  • Recognition_03
  • Recognition_04

Кроме того, если изображение содержит несколько лиц, вам необходимо указать прямоугольную ограничивающую рамку для лица, которое является предполагаемой целью. Следующий код добавляет лица к объекту Person.

var client = new HttpClient();

// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{subscription key}");

// Optional query strings for more fine grained face control
var queryString = "userData={userDefinedData}&targetFace={left,top,width,height}&detectionModel={detectionModel}";
var uri = "https://{endpoint}/face/v1.0-preview/persons/{personId}/recognitionModels/{recognitionModel}/persistedFaces?" + queryString;

HttpResponseMessage response;

// Request body
var body = new Dictionary<string, object>();
body.Add("url", "{image url}");
byte[] byteData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(body));

using (var content = new ByteArrayContent(byteData))
{
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    response = await client.PostAsync(uri, content);
}

После вызова функции Add Faces данные лиц будут обрабатываться асинхронно, и вам нужно будет дождаться успеха операции так же, как и раньше.

Когда операция по добавлению лица завершится, данные будут готовы для вызовов идентификации.

Создайте и обновите DynamicPersonGroup

DynamicPersonGroups - это коллекции ссылок на объекты Person в PersonDirectory; они используются для создания подмножеств каталога. Обычно используется, когда вы хотите получить меньше ложных срабатываний и повысить точность операции Identify, ограничив область действия только объектами Person, которые вы ожидаете сопоставить. Практические варианты использования включают каталоги для доступа к конкретным зданиям в более крупном кампусе или организации. Каталог организации может содержать 5 миллионов человек, но вам нужно найти только конкретных 800 человек для конкретного здания, поэтому вы должны создать DynamicPersonGroup, содержащую конкретных людей.

Если вы раньше использовали PersonGroup, обратите внимание на два основных отличия:

  • Каждый Person внутри DynamicPersonGroup является ссылкой на фактическое Person в PersonDirectory, что означает, что нет необходимости воссоздавать Person в каждой группе.
  • Как упоминалось в предыдущих разделах, выполнять вызовы API Train нет необходимости, поскольку данные лиц обрабатываются на уровне каталога (Directory) автоматически.

Создание группы

Для создания DynamicPersonGroup необходимо указать идентификатор группы с буквенно-цифровыми символами или дефисом. Данный идентификатор будет работать как уникальный идентификатор для всех целей использования группы.

Существует два способа инициализации групповой коллекции. Сперва вы можете создать пустую группу, а затем заполнить ее:

var client = new HttpClient();

// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{subscription key}");

var uri = "https://{endpoint}/face/v1.0-preview/dynamicpersongroups/{dynamicPersonGroupId}";

HttpResponseMessage response;

// Request body
var body = new Dictionary<string, object>();
body.Add("name", "Example DynamicPersonGroup");
body.Add("userData", "User defined data");
byte[] byteData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(body));

using (var content = new ByteArrayContent(byteData))
{
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    response = await client.PutAsync(uri, content);
}

Эта процедура выполняется немедленно, и ждать успешного выполнения каких-либо асинхронных операций нет необходимости.

В качестве альтернативы вы можете создать его с набором идентификаторов Person, чтобы содержать эти ссылки с самого начала, указав набор в аргументе AddPersonIds:

var client = new HttpClient();

// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{subscription key}");

var uri = "https://{endpoint}/face/v1.0-preview/dynamicpersongroups/{dynamicPersonGroupId}";

HttpResponseMessage response;

// Request body
var body = new Dictionary<string, object>();
body.Add("name", "Example DynamicPersonGroup");
body.Add("userData", "User defined data");
body.Add("addPersonIds", new List<string>{"{guid1}", "{guid2}", …});
byte[] byteData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(body));

using (var content = new ByteArrayContent(byteData))
{
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    response = await client.PutAsync(uri, content);

    // Async operation location to query the completion status from
    var operationLocation = response.Headers.Get("Operation-Location");
}

Примечание.

Как только вызов возвращается, созданная группа DynamicPersonGroup будет готова к использованию в вызове Identify с любыми ссылками на Person, предоставленными в рамках процесса. С другой стороны, статус завершения возвращенного идентификатора операции указывает статус обновления отношения человек-группа.

Обновление DynamicPersonGroup

После первоначального создания вы можете добавлять и удалять ссылки Person из DynamicPersonGroup с помощью API обновления динамической группы людей. Для добавления объектов Person в группу необходимо указать идентификаторы Person в аргументе addPersonsIds. Чтобы удалить объекты Person, укажите их в аргументе removePersonIds. Как добавление, так и удаление можно выполнить за один вызов:

var client = new HttpClient();

// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{subscription key}");

var uri = "https://{endpoint}/face/v1.0-preview/dynamicpersongroups/{dynamicPersonGroupId}";

HttpResponseMessage response;

// Request body
var body = new Dictionary<string, object>();
body.Add("name", "Example Dynamic Person Group updated");
body.Add("userData", "User defined data updated");
body.Add("addPersonIds", new List<string>{"{guid1}", "{guid2}", …});
body.Add("removePersonIds", new List<string>{"{guid1}", "{guid2}", …});
byte[] byteData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(body));

using (var content = new ByteArrayContent(byteData))
{
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    response = await client.PatchAsync(uri, content);

    // Async operation location to query the completion status from
    var operationLocation = response.Headers.Get("Operation-Location");
}

После возврата вызова обновления коллекции будут отражены при запросе группы. Как и в случае с API создания, возвращенная операция указывает статус обновления отношения человек-группа для любого человека из списка Persons, участвующего в обновлении. Нет необходимости ожидать завершения операции перед дальнейшими вызовами Update в группу.

Определение лиц в PersonDirectory

Наиболее распространенный способ использования данных о лицах в PersonDirectory - это сравнение зарегистрированных объектов Person с данным лицом и определение наиболее вероятного кандидата, которому оно принадлежит. В запросе может быть указано несколько лиц, и каждое из них получит свой собственный набор результатов сравнения в ответе.

В PersonDirectory есть три типа областей, по которым можно идентифицировать каждое лицо:

Сценарий 1. Идентификация по DynamicPersonGroup

При указании свойства dynamicPersonGroupId в запросе лицо сравнивается с каждым человеком из списка Person, на который имеется ссылка в группе. В вызове можно идентифицировать только одну группу DynamicPersonGroup.

var client = new HttpClient();

// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{subscription key}");

// Optional query strings for more fine grained face control
var uri = "https://{endpoint}/face/v1.0-preview/identify";

HttpResponseMessage response;

// Request body
var body = new Dictionary<string, object>();
body.Add("faceIds", new List<string>{"{guid1}", "{guid2}", …});
body.Add("dynamicPersonGroupId", "{dynamicPersonGroupIdToIdentifyIn}");
byte[] byteData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(body));

using (var content = new ByteArrayContent(byteData))
{
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    response = await client.PostAsync(uri, content);
}

Сценарий 2: Идентификация по определенному списку лиц

Вы также можете указать список идентификаторов Person в свойстве personIds, чтобы сравнить лицо с каждым из них.

var client = new HttpClient();

// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{subscription key}");
            
var uri = "https://{endpoint}/face/v1.0-preview/identify";

HttpResponseMessage response;

// Request body
var body = new Dictionary<string, object>();
body.Add("faceIds", new List<string>{"{guid1}", "{guid2}", …});
body.Add("personIds", new List<string>{"{guid1}", "{guid2}", …});
byte[] byteData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(body));

using (var content = new ByteArrayContent(byteData))
{
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    response = await client.PostAsync(uri, content);
}

Сценарий 3. Идентификация по всему PersonDirectory

Если указать одну звездочку в свойстве personIds в запросе, лицо будет сравниваться с каждым отдельным человеком из списка Person, зарегистрированным в PersonDirectory.

var client = new HttpClient();

// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{subscription key}");
            
var uri = "https://{endpoint}/face/v1.0-preview/identify";

HttpResponseMessage response;

// Request body
var body = new Dictionary<string, object>();
body.Add("faceIds", new List<string>{"{guid1}", "{guid2}", …});
body.Add("personIds", new List<string>{"*"});
byte[] byteData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(body));

using (var content = new ByteArrayContent(byteData))
{
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    response = await client.PostAsync(uri, content);
}

Для всех трех сценариев идентификация сравнивает только входящее лицо с лицами, чей вызов AddPersonFace вернул с ответом «успешно».

Сверка лиц с людьми в PersonDirectory

С помощью идентификатора лица, возвращенного из вызова обнаружения, вы можете проверить, принадлежит ли лицо определенному человека из списка Person, зарегистрированному в PersonDirectory. Укажите Person с помощью свойства personId.

var client = new HttpClient();

// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{subscription key}");

var uri = "https://{endpoint}/face/v1.0-preview/verify";

HttpResponseMessage response;

// Request body
var body = new Dictionary<string, object>();
body.Add("faceId", "{guid1}");
body.Add("personId", "{guid1}");
var jsSerializer = new JavaScriptSerializer();
byte[] byteData = Encoding.UTF8.GetBytes(jsSerializer.Serialize(body));

using (var content = new ByteArrayContent(byteData))
{
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    response = await client.PostAsync(uri, content);
}

Ответ будет содержать логическое значение, указывающее, считает ли служба, что новое лицо принадлежит одному и тому же человека из списка Person, а также показатель достоверности для прогноза.

Следующие шаги

В контексте данного руководства вы узнали, как использовать структуру PersonDirectory для хранения данных о лицах и лицах для вашего приложения по распознаванию лиц. После этого вы ознакомились с передовыми методами добавления данных о лицах ваших пользователей.