使用 PersonDirectory 结构Use the PersonDirectory structure

若要执行人脸识别操作(如识别和查找相似对象),人脸 API 客户需要创建一份 Person 对象的分类列表。To perform face recognition operations such as Identify and Find Similar, Face API customers need to create an assorted list of Person objects. 新的 PersonDirectory 是一种数据结构,其中包含添加到目录的每个人员身份识别的唯一 ID、可选名称字符串和可选用户元数据字符串 。The new PersonDirectory is a data structure that contains unique IDs, optional name strings, and optional user metadata strings for each Person identity added to the directory.

目前,人脸 API 提供 LargePersonGroup 结构,该结构具有相似功能,但限制添加 100,0000 个身份识别。Currently, the Face API offers the LargePersonGroup structure, which has similar functionality but is limited to 1 million identities. PersonDirectory 结构最多可扩展到 750,00000 个标识。The PersonDirectory structure can scale up to 75 million identities.

PersonDirectory 和之前的数据结构之间还存在一个重大差异,即在将人脸添加到 Person 对象后,便无需再执行任何定型调用,因为更新进程会自动发生。Another major difference between PersonDirectory and previous data structures is that you'll no longer need to make any Train calls after adding faces to a Person object—the update process happens automatically.

先决条件Prerequisites

  • Azure 订阅 - 创建试用订阅Azure subscription - Create one for trial.
  • 拥有 Azure 订阅后,在 Azure 门户中创建人脸资源,获取密钥和终结点。Once you have your Azure subscription, create a Face resource in the Azure portal to get your key and endpoint. 部署后,单击“转到资源”。After it deploys, click Go to resource.
    • 需要从创建的资源获取密钥和终结点,以便将应用程序连接到人脸 API。You'll need the key and endpoint from the resource you create to connect your application to the Face API. 可以将密钥和终结点粘贴到下方代码中。You'll paste your key and endpoint into the code below.
    • 可以使用免费定价层 (F0) 试用该服务,然后再升级到付费层进行生产。You can use the free pricing tier (F0) to try the service, and upgrade later to a paid tier for production.

将人员添加到 PersonDirectoryAdd Persons to the PersonDirectory

人员是 PersonDirectory 中的基本注册单元。Persons are the base enrollment units in the PersonDirectory. 在将人员添加到目录后,你可以按识别模型向该人员添加最多 248 张人脸图像。Once you add a Person to the directory, you can add up to 248 face images to that Person, per recognition model. 然后,你可以使用不同的作用域来识别这些图像中的人脸。Then you can identify faces against them using varying scopes.

创建人员Create the Person

若要创建人员,需要调用 CreatePerson API 并提供 name 或 userData 属性值。To create a Person, you need to call the CreatePerson API and provide a name or userData property value.

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 将为相关人员和操作位置返回生成的 ID。The CreatePerson call will return a generated ID for the Person and an operation location. 人员数据将以异步方式进行处理,因此你可以使用操作位置提取结果。The Person data will be processed asynchronously, so you use the operation location to fetch the results.

等待异步操作完成Wait for asynchronous operation completion

你需要使用返回的操作位置字符串查询异步操作的状态,以检查操作进度。You'll need to query the async operation status using the returned operation location string to check the progress.

首先,应定义如下所示的数据模型来处理状态响应。First, you should define a data model like the following to handle the status response.

[Serializable]
public class AsyncStatus
{
    [DataMember(Name = "status")]
    public string AsyncStatus { 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 并等待结果。Using the HttpResponseMessage from above, you can then poll the URL and wait for results.

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 对象视为已添加到目录中。Once the status returns as "succeeded", the Person object is considered added to the directory.

备注

来自创建人员调用的异步操作无需显示“成功”状态,你便可将人脸添加到其中,但你需要先完成此操作,然后才能将人员添加到 DynamicPersonGroup 中(参阅下方的创建与更新 DynamicPersonGroup),或者在识别调用期间进行比较。The asynchronous operation from the Create Person call does not have to show "succeeded" status before faces can be added to it, but it does need to be completed before the Person can be added to a DynamicPersonGroup (see below Create and update a DynamicPersonGroup) or compared during an Identify call. 验证在将人脸成功添加到人员后,调用是否立即生效。Verify calls will work immediately after faces are successfully added to the Person.

将人脸添加到人员Add faces to Persons

通过创建人员调用获得人员 ID 后,便可为每个识别模型的人员添加最多 248 张人脸图像。Once you have the Person ID from the Create Person call, you can add up to 248 face images to a Person per recognition model. 指定要在调用中使用的识别模型(并选择性指定检测模型),因为每个识别模型下的数据将会在 PersonDirectory 中单独处理。Specify the recognition model (and optionally the detection model) to use in the call, as data under each recognition model will be processed separately inside the PersonDirectory.

当前支持的识别模型包括:The currently supported recognition models are:

  • Recognition_02
  • Recognition_03
  • Recognition_04

此外,如果图像包含多个人脸,则需要为作为预期目标的人脸指定矩形边界框。Additionally, if the image contains multiple faces, you'll need to specify the rectangle bounding box for the face that is the intended target. 下列代码可用于将人脸添加到 Person 对象。The following code adds faces to a Person object.

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

添加人脸调用后,人脸数据将以异步方式进行处理,而你需要以与之前相同的方式等待操作成功。After the Add Faces call, the face data will be processed asynchronously, and you'll need to wait for the success of the operation in the same manner as before.

人脸添加操作完成后,相关数据将会在身份识别调用中准备就绪。When the operation for the face addition finishes, the data will be ready for in Identify calls.

创建并更新 DynamicPersonGroupCreate and update a DynamicPersonGroup

DynamicPersonGroups 是对 PersonDirectory 中 Person 对象的引用集合;它们将用于创建目录的子集。DynamicPersonGroups are collections of references to Person objects within a PersonDirectory; they're used to create subsets of the directory. 一种常见的用途是,如果你想要在执行身份识别操作时减少误报并增加准确性,只需将作用域限制为你期望匹配的 Person 对象即可。A common use is when you want to get fewer false positives and increased accuracy in an Identify operation by limiting the scope to just the Person objects you expect to match. 实际用例包括在较大校园或组织中访问特定建筑物的目录。Practical use cases include directories for specific building access among a larger campus or organization. 组织目录可能包含 500,0000 个人,但你只需通过搜索特定 800 个人来找到特定的建筑物,因此你可以创建一个包含这些特定个人的 DynamicPersonGroup。The organization directory may contain 5 million individuals, but you only need to search a specific 800 people for a particular building, so you would create a DynamicPersonGroup containing those specific individuals.

如果之前使用过 PersonGroup,请注意两个主要区别:If you've used a PersonGroup before, take note of two major differences:

  • DynamicPersonGroup 中的每个人员都是对 PersonDirectory 中实际人员的引用,这意味着无需在每个组中重新创建人员 。Each Person inside a DynamicPersonGroup is a reference to the actual Person in the PersonDirectory, meaning that it's not necessary to recreate a Person in each group.
  • 如先前章节中所述,你无需执行定型调用,因为人脸数据会自动在目录级别进行处理。As mentioned in previous sections, there is no need to make Train calls, as the face data is processed at the Directory level automatically.

创建组Create the group

若要创建 DynamicPersonGroup,需要提供包含字母数字或破折号字符的组 ID。To create a DynamicPersonGroup, you need to provide a group ID with alphanumeric or dash characters. 此 ID 将用作组的所有用途的唯一标识符。This ID will function as the unique identifier for all usage purposes of the group.

有两种方式可以初始化组集合。There are two ways to initialize a group collection. 你可以一开始创建一个空组,并于之后填充:You can create an empty group initially, and populate it later:

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

此为即时过程,无需等待任何异步操作成功。This process is immediate and there is no need to wait for any asynchronous operations to succeed.

或者,你可以使用一组人员 ID 来创建组,并通过在 AddPersonIds 参数中提供集以从一开始便将这些引用包含在其中:Alternatively, you can create it with a set of Person IDs to contain those references from the beginning by providing the set in the AddPersonIds argument:

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 便可在身份识别调用中使用,而且该过程会提供任何人员引用。As soon as the call returns, the created DynamicPersonGroup will be ready to use in an Identify call, with any Person references provided in the process. 另一方面,返回的操作 ID 的完成状态可指示“人员对组”关系的更新状态。The completion status of the returned operation ID, on the other hand, indicates the update status of the person-to-group relationship.

更新 DynamicPersonGroupUpdate the DynamicPersonGroup

初始创建之后,可以通过更新动态人员组 API 添加和删除来自 DynamicPersonGroup 的人员引用。After the initial creation, you can add and remove Person references from the DynamicPersonGroup with the Update Dynamic Person Group API. 若要将 Person 对象添加到组,请在 addPersonsIds 参数中列出人员 ID。To add Person objects to the group, list the Person IDs in the addPersonsIds argument. 若要删除 Person 对象,请在 removePersonIds 参数中列出这些对象。To remove Person objects, list them in the removePersonIds argument. 添加和删除操作都可在单个调用中执行:Both adding and removing can be performed in a single call:

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

一旦调用返回,系统将会在查询组时反映集合的更新。Once the call returns, the updates to the collection will be reflected when the group is queried. 与创建 API 一样,返回的操作将指示与更新相关的任何人员的“人员对组”关系的更新状态。As with the creation API, the returned operation indicates the update status of person-to-group relationship for any Person that's involved in the update. 在对组进一步执行更新调用之前,你不需要等待操作完成。You don't need to wait for the completion of the operation before making further Update calls to the group.

识别 PersonDirectory 中的人脸Identify faces in a PersonDirectory

在 PersonDirectory 中使用人脸数据最常见的方法是将已注册的 Person 对象与给定的人脸进行比较,并找出其最可能所属的候选对象。The most common way to use face data in a PersonDirectory is to compare the enrolled Person objects against a given face and identify the most likely candidate it belongs to. 请求中可提供多个人脸,每个人脸都将在响应中收到自己的一组比较结果。Multiple faces can be provided in the request, and each will receive its own set of comparison results in the response.

在 PersonDirectory 中,每个人脸都可以通过三种类型的作用域来进行识别:In PersonDirectory, there are three types of scopes each face can be identified against:

方案 1:根据 DynamicPersonGroup 进行识别Scenario 1: Identify against a DynamicPersonGroup

通过在请求中指定 dynamicPersonGroupId 属性,便可将人脸与组中引用的每个人员 进行比较。Specifying the dynamicPersonGroupId property in the request compares the face against every Person referenced in the group. 只能在调用中识别单个 DynamicPersonGroup。Only a single DynamicPersonGroup can be identified against in a call.

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:根据特定人员列表进行识别Scenario 2: Identify against a specific list of persons

你还可以在 personIds 属性中指定人员 ID 列表,以将人脸与其中的每个人员进行比较。You can also specify a list of Person IDs in the personIds property to compare the face against each of them.

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 进行识别Scenario 3: Identify against the entire PersonDirectory

在请求的 personIds 属性中提供单个星号,便会将人脸与在 PersonDirectory 中注册的每个人员进行比较 。Providing a single asterisk in the personIds property in the request compares the face against every single Person enrolled in the 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", "['*']");
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 调用以“成功”响应返回的人脸进行比较。For all three scenarios, the identification only compares the incoming face against faces whose AddPersonFace call has returned with a "succeeded" response.

验证 PersonDirectory 中人员的人脸Verify faces against persons in the PersonDirectory

通过自检测调用返回的人脸 ID,你可以验证人脸是否属于在 PersonDirectory 中注册的特定人员 。With a face ID returned from a detection call, you can verify if the face belongs to a specific Person enrolled inside the PersonDirectory. 使用 personId 属性指定人员。Specify the Person using the personId property.

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

响应将包含布尔值(指示服务是否将新的人脸视为属于同一人员),以及用于预测的可信度分数。The response will contain a Boolean value indicating whether the service considers the new face to belong to the same Person, and a confidence score for the prediction.

后续步骤Next steps

在本指南中,你已经学习了如何使用 PersonDirectory 结构来存储人脸应用的人脸和人员数据。In this guide, you learned how to use the PersonDirectory structure to store face and person data for your Face app. 接下来,请学习添加用户人脸数据的最佳做法。Next, learn the best practices for adding your users' face data.