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

将人脸添加到 PersonGroup

注意

为了支持我们负责任的 AI 原则,基于资格和使用标准对人脸服务访问进行限制。 人脸服务仅适用于 Microsoft 托管客户和合作伙伴。 使用人脸识别引入表单来申请访问。 有关详细信息,请参阅人脸受限访问页面。

本指南演示了如何将大量人员和人脸添加到 PersonGroup 对象。 此同一策略还适用于 LargePersonGroup、FaceList 和 LargeFaceList 对象。 此示例是用 C# 编写的。

初始化

下面的代码声明了多个变量并实现了一个帮助程序函数来调度人脸添加请求:

  • PersonCount 是总人数。
  • CallLimitPerSecond 是因订阅层而异的每秒调用数上限。
  • _timeStampQueue 是用于记录请求时间戳的队列。
  • await WaitCallLimitPerSecondAsync() 将等待,直至可以发送下一请求。
const int PersonCount = 10000;
const int CallLimitPerSecond = 10;
static Queue<DateTime> _timeStampQueue = new Queue<DateTime>(CallLimitPerSecond);

static async Task WaitCallLimitPerSecondAsync()
{
    Monitor.Enter(_timeStampQueue);
    try
    {
        if (_timeStampQueue.Count >= CallLimitPerSecond)
        {
            TimeSpan timeInterval = DateTime.UtcNow - _timeStampQueue.Peek();
            if (timeInterval < TimeSpan.FromSeconds(1))
            {
                await Task.Delay(TimeSpan.FromSeconds(1) - timeInterval);
            }
            _timeStampQueue.Dequeue();
        }
        _timeStampQueue.Enqueue(DateTime.UtcNow);
    }
    finally
    {
        Monitor.Exit(_timeStampQueue);
    }
}

创建 PersonGroup

此代码创建一个名为 "MyPersonGroup" 的 PersonGroup 来保存人员。 为了确保整体验证,请求时间排入 _timeStampQueue 队列。

const string personGroupId = "mypersongroupid";
const string personGroupName = "MyPersonGroup";
_timeStampQueue.Enqueue(DateTime.UtcNow);
using (var content = new ByteArrayContent(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new Dictionary<string, object> { ["name"] = personGroupName, ["recognitionModel"] = "recognition_04" }))))
{
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    await httpClient.PutAsync($"{ENDPOINT}/face/v1.0/persongroups/{personGroupId}", content);
}

为 PersonGroup 创建人员

此代码同时创建 Persons,并使用 await WaitCallLimitPerSecondAsync() 来避免超出调用速率限制。

string?[] persons = new string?[PersonCount];
Parallel.For(0, PersonCount, async i =>
{
    await WaitCallLimitPerSecondAsync();

    string personName = $"PersonName#{i}";
    using (var content = new ByteArrayContent(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new Dictionary<string, object> { ["name"] = personName }))))
    {
        content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
        using (var response = await httpClient.PostAsync($"{ENDPOINT}/face/v1.0/persongroups/{personGroupId}/persons", content))
        {
            string contentString = await response.Content.ReadAsStringAsync();
            persons[i] = (string?)(JsonConvert.DeserializeObject<Dictionary<string, object>>(contentString)?["personId"]);
        }
    }
});

向人员添加人脸

添加到不同人员的人脸是并发处理的。 为单个特定人员添加的人脸是按顺序处理的。 同样,为了确保请求频率在限制范围内,还会调用 await WaitCallLimitPerSecondAsync()

Parallel.For(0, PersonCount, async i =>
{
    string personImageDir = @"/path/to/person/i/images";

    foreach (string imagePath in Directory.GetFiles(personImageDir, "*.jpg"))
    {
        await WaitCallLimitPerSecondAsync();

        using (Stream stream = File.OpenRead(imagePath))
        {
            using (var content = new StreamContent(stream))
            {
                content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                await httpClient.PostAsync($"{ENDPOINT}/face/v1.0/persongroups/{personGroupId}/persons/{persons[i]}/persistedfaces?detectionModel=detection_03", content);
            }
        }
    }
});

总结

在本指南中,你已学习了如何创建包含大量人员和人脸的 PersonGroup。 请注意以下几点:

  • 此策略也适用于 FaceLists 和 LargePersonGroups。
  • 为 LargePersonGroups 中的不同 FaceLists 或人员添加或删除人脸是并发处理的。
  • 为 LargePersonGroup 中的某个特定 FaceList 或人员添加或删除人脸是按顺序处理的。

后续步骤

接下来,了解如何使用增强的数据结构 PersonDirectory 对人脸数据执行更多操作。