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

快速入门:使用人脸客户端库

开始使用适用于 .NET 的人脸客户端库进行人脸识别。 请按照以下步骤安装程序包并试用基本任务的示例代码。 通过人脸服务,可以访问用于检测和识别图像中的人脸的高级算法。

使用适用于 .NET 的人脸客户端库可以:

参考文档 | 库源代码 | 包 (NuGet) | 示例

先决条件

  • Azure 订阅 - 免费创建订阅
  • Visual Studio IDE 或最新版本的 .NET Core
  • 你的 Azure 帐户必须分配有认知服务参与者角色,你才能同意负责的 AI 条款并创建资源。 若要将此角色分配给你的帐户,请按照分配角色文档中的步骤进行操作,或与管理员联系。
  • 拥有 Azure 订阅后,请在 Azure 门户中创建人脸资源,以获取密钥和终结点。 部署后,单击“转到资源”。
    • 需要从创建的资源获取密钥和终结点,以便将应用程序连接到人脸 API。 你稍后会在快速入门中将密钥和终结点粘贴到下方的代码中。
    • 可以使用免费定价层 (F0) 试用该服务,然后再升级到付费层进行生产。

设置

新建 C# 应用程序

使用 Visual Studio 创建新的 .NET Core 应用程序。

安装客户端库

创建新项目后,右键单击“解决方案资源管理器”中的项目解决方案,然后选择“管理 NuGet 包”,以安装客户端库 。 在打开的包管理器中,选择“浏览”,选中“包括预发行版”并搜索 Microsoft.Azure.CognitiveServices.Vision.Face。 选择版本 2.7.0-preview.1,然后选择“安装”。

提示

想要立即查看整个快速入门代码文件? 可以在 GitHub 上找到它,其中包含此快速入门中的代码示例。

从项目目录中,打开 Program.cs 文件,并添加以下 using 指令:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.Azure.CognitiveServices.Vision.Face;
using Microsoft.Azure.CognitiveServices.Vision.Face.Models;

在应用程序的“Program”类中,为资源的密钥和终结点创建变量。

重要

转到 Azure 门户。 如果你在“先决条件”部分创建的人脸资源部署成功,请单击“后续步骤”下的“转到资源”按钮 。 在资源的“密钥和终结点”页的“资源管理”下可以找到密钥和终结点 。

重要

完成后,请记住将密钥从代码中删除,并且永远不要公开发布该密钥。 对于生产环境,请考虑使用安全的方法来存储和访问凭据。 有关详细信息,请参阅认知服务安全性文章。

// From your Face subscription in the Azure portal, get your subscription key and endpoint.
const string SUBSCRIPTION_KEY = "PASTE_YOUR_FACE_SUBSCRIPTION_KEY_HERE";
const string ENDPOINT = "PASTE_YOUR_FACE_ENDPOINT_HERE";

在应用程序的“Main”方法中,添加对本快速入门中使用的方法的调用。 稍后将实现这些操作。

// Authenticate.
IFaceClient client = Authenticate(ENDPOINT, SUBSCRIPTION_KEY);

// Detect - get features from faces.
DetectFaceExtract(client, IMAGE_BASE_URL, RECOGNITION_MODEL4).Wait();
// Find Similar - find a similar face from a list of faces.
FindSimilar(client, IMAGE_BASE_URL, RECOGNITION_MODEL4).Wait();
// Verify - compare two images if the same person or not.
Verify(client, IMAGE_BASE_URL, RECOGNITION_MODEL4).Wait();

// Identify - recognize a face(s) in a person group (a person group is created in this example).
IdentifyInPersonGroup(client, IMAGE_BASE_URL, RECOGNITION_MODEL4).Wait();
// LargePersonGroup - create, then get data.
LargePersonGroup(client, IMAGE_BASE_URL, RECOGNITION_MODEL4).Wait();
// Group faces - automatically group similar faces.
Group(client, IMAGE_BASE_URL, RECOGNITION_MODEL4).Wait();
// FaceList - create a face list, then get data

对象模型

以下类和接口将处理人脸 .NET 客户端库的某些主要功能:

名称 说明
FaceClient 此类代表使用人脸服务的授权,使用所有人脸功能时都需要用到它。 请使用你的订阅信息实例化此类,然后使用它来生成其他类的实例。
FaceOperations 此类处理可对人脸执行的基本检测和识别任务。
DetectedFace 此类代表已从图像中的单个人脸检测到的所有数据。 可以使用它来检索有关人脸的详细信息。
FaceListOperations 此类管理云中存储的 FaceList 构造,这些构造存储各种不同的人脸。
PersonGroupPersonExtensions 此类管理云中存储的 Person 构造,这些构造存储属于单个人员的一组人脸。
PersonGroupOperations 此类管理云中存储的 PersonGroup 构造,这些构造存储各种不同的 Person 对象。

代码示例

以下代码片段演示如何使用适用于 .NET 的人脸客户端库执行以下任务:

验证客户端

在新方法中,使用终结点和密钥实例化客户端。 使用密钥创建一个 ApiKeyServiceClientCredentials 对象,并在终结点中使用该对象创建一个 FaceClient 对象。

/*
 *	AUTHENTICATE
 *	Uses subscription key and region to create a client.
 */
public static IFaceClient Authenticate(string endpoint, string key)
{
    return new FaceClient(new ApiKeyServiceClientCredentials(key)) { Endpoint = endpoint };
}

声明帮助程序字段

你稍后将添加的几个人脸操作需要以下字段。 在“Program”类的根目录中定义以下 URL 字符串。 此 URL 指向示例图像的文件夹。

// Used for all examples.
// URL for the images.
const string IMAGE_BASE_URL = "https://csdx.blob.core.windows.net/resources/Face/Images/";

在“Main”方法中,定义字符串以指向不同的识别模型类型。 稍后,你将能够指定要用于人脸检测的识别模型。 有关这些选项的信息,请参阅指定识别模型

// Recognition model 4 was released in 2021 February.
// It is recommended since its accuracy is improved
// on faces wearing masks compared with model 3,
// and its overall accuracy is improved compared
// with models 1 and 2.
const string RECOGNITION_MODEL4 = RecognitionModel.Recognition04;

检测和分析人脸

在所有其他情况下,需要将人脸检测作为第一步。 本部分介绍如何返回额外的人脸属性数据。 如果只想检测人脸以进行人脸识别或验证,请跳到后面的部分。

获取检测到的人脸对象

创建新方法以检测人脸。 DetectFaceExtract 方法处理给定 URL 处的三个图像,并在程序内存中创建 DetectedFace 对象的列表。 FaceAttributeType 值列表指定要提取的特征。

/* 
 * DETECT FACES
 * Detects features from faces and IDs them.
 */
public static async Task DetectFaceExtract(IFaceClient client, string url, string recognitionModel)
{
    Console.WriteLine("========DETECT FACES========");
    Console.WriteLine();

    // Create a list of images
    List<string> imageFileNames = new List<string>
                    {
                        "detection1.jpg",    // single female with glasses
                        // "detection2.jpg", // (optional: single man)
                        // "detection3.jpg", // (optional: single male construction worker)
                        // "detection4.jpg", // (optional: 3 people at cafe, 1 is blurred)
                        "detection5.jpg",    // family, woman child man
                        "detection6.jpg"     // elderly couple, male female
                    };

    foreach (var imageFileName in imageFileNames)
    {
        IList<DetectedFace> detectedFaces;

        // Detect faces with all attributes from image url.
        detectedFaces = await client.Face.DetectWithUrlAsync($"{url}{imageFileName}",
                returnFaceAttributes: new List<FaceAttributeType> { FaceAttributeType.Accessories, FaceAttributeType.Age,
                FaceAttributeType.Blur, FaceAttributeType.Emotion, FaceAttributeType.Exposure, FaceAttributeType.FacialHair,
                FaceAttributeType.Glasses, FaceAttributeType.Hair, FaceAttributeType.HeadPose,
                FaceAttributeType.Makeup, FaceAttributeType.Noise, FaceAttributeType.Occlusion, FaceAttributeType.Smile, 
                FaceAttributeType.Smile, FaceAttributeType.QualityForRecognition },
                // We specify detection model 1 because we are retrieving attributes.
                detectionModel: DetectionModel.Detection01,
                recognitionModel: recognitionModel);

        Console.WriteLine($"{detectedFaces.Count} face(s) detected from image `{imageFileName}`.");

上面的代码处理以下远程图像:

Photo of a woman smilingPhoto of a man, woman, and babyPhoto of an older man and woman

提示

还可以检测本地图像中的人脸。 请参阅 IFaceOperations 方法,例如 DetectWithStreamAsync。

显示检测到的人脸数据

DetectFaceExtract 方法的其余部分将分析和打印每个检测到的人脸的属性数据。 每个属性必须在原始人脸检测 API 调用中单独指定(在 FaceAttributeType 列表中)。 下面的代码处理每个属性,但你可能只需要使用一个或一些属性。

        // Parse and print all attributes of each detected face.
        foreach (var face in detectedFaces)
        {
            Console.WriteLine($"Face attributes for {imageFileName}:");

            // Get bounding box of the faces
            Console.WriteLine($"Rectangle(Left/Top/Width/Height) : {face.FaceRectangle.Left} {face.FaceRectangle.Top} {face.FaceRectangle.Width} {face.FaceRectangle.Height}");

            // Get accessories of the faces
            List<Accessory> accessoriesList = (List<Accessory>)face.FaceAttributes.Accessories;
            int count = face.FaceAttributes.Accessories.Count;
            string accessory; string[] accessoryArray = new string[count];
            if (count == 0) { accessory = "NoAccessories"; }
            else
            {
                for (int i = 0; i < count; ++i) { accessoryArray[i] = accessoriesList[i].Type.ToString(); }
                accessory = string.Join(",", accessoryArray);
            }
            Console.WriteLine($"Accessories : {accessory}");

            // Get face other attributes
            Console.WriteLine($"Age : {face.FaceAttributes.Age}");
            Console.WriteLine($"Blur : {face.FaceAttributes.Blur.BlurLevel}");

            // Get emotion on the face
            string emotionType = string.Empty;
            double emotionValue = 0.0;
            Emotion emotion = face.FaceAttributes.Emotion;
            if (emotion.Anger > emotionValue) { emotionValue = emotion.Anger; emotionType = "Anger"; }
            if (emotion.Contempt > emotionValue) { emotionValue = emotion.Contempt; emotionType = "Contempt"; }
            if (emotion.Disgust > emotionValue) { emotionValue = emotion.Disgust; emotionType = "Disgust"; }
            if (emotion.Fear > emotionValue) { emotionValue = emotion.Fear; emotionType = "Fear"; }
            if (emotion.Happiness > emotionValue) { emotionValue = emotion.Happiness; emotionType = "Happiness"; }
            if (emotion.Neutral > emotionValue) { emotionValue = emotion.Neutral; emotionType = "Neutral"; }
            if (emotion.Sadness > emotionValue) { emotionValue = emotion.Sadness; emotionType = "Sadness"; }
            if (emotion.Surprise > emotionValue) { emotionType = "Surprise"; }
            Console.WriteLine($"Emotion : {emotionType}");

            // Get more face attributes
            Console.WriteLine($"Exposure : {face.FaceAttributes.Exposure.ExposureLevel}");
            Console.WriteLine($"FacialHair : {string.Format("{0}", face.FaceAttributes.FacialHair.Moustache + face.FaceAttributes.FacialHair.Beard + face.FaceAttributes.FacialHair.Sideburns > 0 ? "Yes" : "No")}");
            Console.WriteLine($"Glasses : {face.FaceAttributes.Glasses}");

            // Get hair color
            Hair hair = face.FaceAttributes.Hair;
            string color = null;
            if (hair.HairColor.Count == 0) { if (hair.Invisible) { color = "Invisible"; } else { color = "Bald"; } }
            HairColorType returnColor = HairColorType.Unknown;
            double maxConfidence = 0.0f;
            foreach (HairColor hairColor in hair.HairColor)
            {
                if (hairColor.Confidence <= maxConfidence) { continue; }
                maxConfidence = hairColor.Confidence; returnColor = hairColor.Color; color = returnColor.ToString();
            }
            Console.WriteLine($"Hair : {color}");

            // Get more attributes
            Console.WriteLine($"HeadPose : {string.Format("Pitch: {0}, Roll: {1}, Yaw: {2}", Math.Round(face.FaceAttributes.HeadPose.Pitch, 2), Math.Round(face.FaceAttributes.HeadPose.Roll, 2), Math.Round(face.FaceAttributes.HeadPose.Yaw, 2))}");
            Console.WriteLine($"Makeup : {string.Format("{0}", (face.FaceAttributes.Makeup.EyeMakeup || face.FaceAttributes.Makeup.LipMakeup) ? "Yes" : "No")}");
            Console.WriteLine($"Noise : {face.FaceAttributes.Noise.NoiseLevel}");
            Console.WriteLine($"Occlusion : {string.Format("EyeOccluded: {0}", face.FaceAttributes.Occlusion.EyeOccluded ? "Yes" : "No")} " +
                $" {string.Format("ForeheadOccluded: {0}", face.FaceAttributes.Occlusion.ForeheadOccluded ? "Yes" : "No")}   {string.Format("MouthOccluded: {0}", face.FaceAttributes.Occlusion.MouthOccluded ? "Yes" : "No")}");
            Console.WriteLine($"Smile : {face.FaceAttributes.Smile}");
            
            // Get quality for recognition attribute
            Console.WriteLine($"QualityForRecognition : {face.FaceAttributes.QualityForRecognition}");
            Console.WriteLine();
        }
    }
}

“QualityForRecognition”属性是有关检测中所用图像的质量是否足以尝试人脸识别的整体图像质量指示器。 若要利用质量属性,用户需要通过将 detectionModel 参数设置为 detection_01 或 detection_03,将 recognitionModel 参数设置为 recognition_03 或 recognition_04 来分配模型版本,并在请求中包含 QualityForRecognition 属性,如上面的示例所示。

识别人脸

识别操作获取一个人(或多个人)的图像,并查找与图像中的每个人脸相关联的存储的人员对象(人脸识别搜索)。 它将检测到的每个人脸与某个 PersonGroup(面部数据已知的不同人员对象的数据库)进行比较 。 为了执行“识别”操作,你首先需要创建并训练 PersonGroup

创建人员组

以下代码创建包含六个不同 Person 对象的 PersonGroup。 它将每个 Person 与一组示例图像相关联,然后进行训练以按面部特征识别每个人。 PersonPersonGroup 对象在验证、识别和分组操作中使用。

在类的根目录中声明一个字符串变量,用于表示要创建的 PersonGroup 的 ID。

static string personGroupId = Guid.NewGuid().ToString();

在新方法中添加以下代码。 此方法将执行“识别”操作。 第一个代码块将人员的姓名与其示例图像相关联。

public static async Task IdentifyInPersonGroup(IFaceClient client, string url, string recognitionModel)
{
    Console.WriteLine("========IDENTIFY FACES========");
    Console.WriteLine();

    // Create a dictionary for all your images, grouping similar ones under the same key.
    Dictionary<string, string[]> personDictionary =
        new Dictionary<string, string[]>
            { { "Family1-Dad", new[] { "Family1-Dad1.jpg", "Family1-Dad2.jpg" } },
              { "Family1-Mom", new[] { "Family1-Mom1.jpg", "Family1-Mom2.jpg" } },
              { "Family1-Son", new[] { "Family1-Son1.jpg", "Family1-Son2.jpg" } },
              { "Family1-Daughter", new[] { "Family1-Daughter1.jpg", "Family1-Daughter2.jpg" } },
              { "Family2-Lady", new[] { "Family2-Lady1.jpg", "Family2-Lady2.jpg" } },
              { "Family2-Man", new[] { "Family2-Man1.jpg", "Family2-Man2.jpg" } }
            };
    // A group photo that includes some of the persons you seek to identify from your dictionary.
    string sourceImageFileName = "identification1.jpg";

请注意,此代码定义 sourceImageFileName 变量。 此变量对应于源图像 - 包含要识别的人员的图像。

接下来添加以下代码,以便为字典中的每个人员创建一个 Person 对象,并从相应的图像添加人脸数据。 每个 Person 对象通过其唯一 ID 字符串来与同一个 PersonGroup 相关联。 请记得将变量 clienturlRECOGNITION_MODEL1 传入此方法。

// Create a person group. 
Console.WriteLine($"Create a person group ({personGroupId}).");
await client.PersonGroup.CreateAsync(personGroupId, personGroupId, recognitionModel: recognitionModel);
// The similar faces will be grouped into a single person group person.
foreach (var groupedFace in personDictionary.Keys)
{
    // Limit TPS
    await Task.Delay(250);
    Person person = await client.PersonGroupPerson.CreateAsync(personGroupId: personGroupId, name: groupedFace);
    Console.WriteLine($"Create a person group person '{groupedFace}'.");

    // Add face to the person group person.
    foreach (var similarImage in personDictionary[groupedFace])
    {
        Console.WriteLine($"Check whether image is of sufficient quality for recognition");
        IList<DetectedFace> detectedFaces = await client.Face.DetectWithUrlAsync($"{url}{similarImage}", 
            recognitionModel: recognition_model, 
            detectionModel: DetectionModel.Detection03,
            returnFaceAttributes: new List<FaceAttributeType> { FaceAttributeType.QualityForRecognition });
        bool sufficientQuality = true;
        foreach (var face in detectedFaces)
        {
            var faceQualityForRecognition = face.FaceAttributes.QualityForRecognition;
            //  Only "high" quality images are recommended for person enrollment
            if (faceQualityForRecognition.HasValue && (faceQualityForRecognition.Value != QualityForRecognition.High)){
                sufficientQuality = false;
                break;
            }
        }

        if (!sufficientQuality){
            continue;
        }


        Console.WriteLine($"Add face to the person group person({groupedFace}) from image `{similarImage}`");
        PersistedFace face = await client.PersonGroupPerson.AddFaceFromUrlAsync(personGroupId, person.PersonId,
            $"{url}{similarImage}", similarImage);
    }
}

提示

你还可以从本地图像创建 PersonGroup。 请参阅 IPersonGroupPerson 方法,例如 AddFaceFromStreamAsync.

训练 PersonGroup

从图像中提取人脸数据并将其分类成不同的 Person 对象后,必须训练 PersonGroup 才能识别与其每个 Person 对象关联的视觉特征。 以下代码调用异步 train 方法并轮询结果,然后将状态输出到控制台。

// Start to train the person group.
Console.WriteLine();
Console.WriteLine($"Train person group {personGroupId}.");
await client.PersonGroup.TrainAsync(personGroupId);

// Wait until the training is completed.
while (true)
{
    await Task.Delay(1000);
    var trainingStatus = await client.PersonGroup.GetTrainingStatusAsync(personGroupId);
    Console.WriteLine($"Training status: {trainingStatus.Status}.");
    if (trainingStatus.Status == TrainingStatusType.Succeeded) { break; }
}
Console.WriteLine();

提示

人脸 API 在一组预构建的模型呢上运行,这些模型在本质上是静态的(模型的性能不会因为运行服务而提高或降低)。 如果 Microsoft 更新模型的后端,但不迁移整个新模型版本,那么模型生成的结果可能会变化。 若要使用更新的模型版本,可重新训练 PersonGroup,将更新的模型指定为具有相同注册映像的参数。

现已准备好在验证、识别或分组操作中使用此 Person 组及其关联的 Person 对象。

标识人脸

以下代码采用源映像,创建在图像中检测到的所有人脸的列表。 将会根据 PersonGroup 识别这些人脸。

List<Guid> sourceFaceIds = new List<Guid>();
// Detect faces from source image url.
List<DetectedFace> detectedFaces = await DetectFaceRecognize(client, $"{url}{sourceImageFileName}", recognitionModel);

// Add detected faceId to sourceFaceIds.
foreach (var detectedFace in detectedFaces) { sourceFaceIds.Add(detectedFace.FaceId.Value); }

下一代码片段将调用 IdentifyAsync 操作,并将结果输出到控制台。 此处,服务会尝试将源图像中的每个人脸与给定 PersonGroup 中的某个 Person 进行匹配。 Identify 方法就此结束。

    // Identify the faces in a person group. 
    var identifyResults = await client.Face.IdentifyAsync(sourceFaceIds, personGroupId);

    foreach (var identifyResult in identifyResults)
    {
        Person person = await client.PersonGroupPerson.GetAsync(personGroupId, identifyResult.Candidates[0].PersonId);
        Console.WriteLine($"Person '{person.Name}' is identified for face in: {sourceImageFileName} - {identifyResult.FaceId}," +
            $" confidence: {identifyResult.Candidates[0].Confidence}.");
    }
    Console.WriteLine();
}

查找相似人脸

以下代码采用检测到的单个人脸(源),并搜索其他一组人脸(目标),以找到匹配项(按图像进行人脸搜索)。 找到匹配项后,它会将匹配的人脸的 ID 输出到控制台。

检测人脸以进行比较

首先定义另一个人脸检测方法。 需要先检测图像中的人脸,然后才能对其进行比较;此检测方法已针对比较操作进行优化。 它不会提取以上部分所示的详细人脸属性,而是使用另一个识别模型。

private static async Task<List<DetectedFace>> DetectFaceRecognize(IFaceClient faceClient, string url, string recognition_model)
{
    // Detect faces from image URL. Since only recognizing, use the recognition model 1.
    // We use detection model 3 because we are not retrieving attributes.
    IList<DetectedFace> detectedFaces = await faceClient.Face.DetectWithUrlAsync(url, recognitionModel: recognition_model, detectionModel: DetectionModel.Detection03, FaceAttributes: new List<FaceAttributeType> { FaceAttributeType.QualityForRecognition });
    List<DetectedFace> sufficientQualityFaces = new List<DetectedFace>();
    foreach (DetectedFace detectedFace in detectedFaces){
        var faceQualityForRecognition = detectedFace.FaceAttributes.QualityForRecognition;
        if (faceQualityForRecognition.HasValue && (faceQualityForRecognition.Value >= QualityForRecognition.Medium)){
            sufficientQualityFaces.Add(detectedFace);
        }
    }
    Console.WriteLine($"{detectedFaces.Count} face(s) with {sufficientQualityFaces.Count} having sufficient quality for recognition detected from image `{Path.GetFileName(url)}`");

    return sufficientQualityFaces.ToList();
}

查找匹配项

以下方法检测一组目标图像和单个源图像中的人脸。 然后,它将比较这些人脸,并查找与源图像类似的所有目标图像。

// Find a similar face(s) in the list of IDs. Comapring only the first in list for testing purposes.
IList<SimilarFace> similarResults = await client.Face.FindSimilarAsync(detectedFaces[0].FaceId.Value, null, null, targetFaceIds);

在此程序中,以下远程图像将用作源:

Photo of a man smiling

以下代码将匹配详细信息输出到控制台:

foreach (var similarResult in similarResults)
{
    Console.WriteLine($"Faces from {sourceImageFileName} & ID:{similarResult.FaceId} are similar with confidence: {similarResult.Confidence}.");
}
Console.WriteLine();

在此程序中,在这个图像中检测到的人脸应该作为与源图像人脸相似的人脸返回。

Photo of a man smiling; this is the same person as the previous image

运行应用程序

单击 IDE 窗口顶部的“调试”按钮,运行应用程序。

清理资源

如果想要清理并删除认知服务订阅,可以删除资源或资源组。 删除资源组同时也会删除与之相关联的任何其他资源。

如果你在本快速入门中创建了 PersonGroup 并想要删除它,请在程序中运行以下代码:

// At end, delete person groups in both regions (since testing only)
Console.WriteLine("========DELETE PERSON GROUP========");
Console.WriteLine();
DeletePersonGroup(client, personGroupId).Wait();

使用以下代码定义删除方法:

/*
 * DELETE PERSON GROUP
 * After this entire example is executed, delete the person group in your Azure account,
 * otherwise you cannot recreate one with the same name (if running example repeatedly).
 */
public static async Task DeletePersonGroup(IFaceClient client, String personGroupId)
{
    await client.PersonGroup.DeleteAsync(personGroupId);
    Console.WriteLine($"Deleted the person group {personGroupId}.");
}

后续步骤

在本快速入门中,你已了解如何使用适用于 .NET 的人脸客户端库来执行基本人脸识别任务。 接下来,了解不同的人脸检测模型,学习如何为你的用例指定适当的模型。

快速入门:适用于 JavaScript 的人脸客户端库

开始使用适用于 JavaScript 的人脸客户端库进行人脸识别。 请按照以下步骤安装程序包并试用基本任务的示例代码。 通过人脸服务,可以访问用于检测和识别图像中的人脸的高级算法。

使用适用于 JavaScript 的人脸客户端库可以:

参考文档 | 库源代码 | 包 (npm) | 示例

先决条件

  • Azure 订阅 - 免费创建订阅
  • 最新版本的 Node.js
  • 你的 Azure 帐户必须分配有认知服务参与者角色,你才能同意负责的 AI 条款并创建资源。 若要将此角色分配给你的帐户,请按照分配角色文档中的步骤进行操作,或与管理员联系。
  • 拥有 Azure 订阅后,请在 Azure 门户中创建人脸资源,以获取密钥和终结点。 部署后,单击“转到资源”。
    • 需要从创建的资源获取密钥和终结点,以便将应用程序连接到人脸 API。 你稍后会在快速入门中将密钥和终结点粘贴到下方的代码中。
    • 可以使用免费定价层 (F0) 试用该服务,然后再升级到付费层进行生产。

设置

创建新的 Node.js 应用程序

在控制台窗口(例如 cmd、PowerShell 或 Bash)中,为应用创建一个新目录并导航到该目录。

mkdir myapp && cd myapp

运行 npm init 命令以使用 package.json 文件创建一个 node 应用程序。

npm init

安装客户端库

安装 ms-rest-azureazure-cognitiveservices-face NPM 包:

npm install @azure/cognitiveservices-face @azure/ms-rest-js

应用的 package.json 文件将使用依赖项进行更新。

创建一个名为 index.js 的文件,并导入以下库:

提示

想要立即查看整个快速入门代码文件? 可以在 GitHub 上找到它,其中包含此快速入门中的代码示例。

const msRest = require("@azure/ms-rest-js");
const Face = require("@azure/cognitiveservices-face");
const uuid = require("uuid/v4");

为资源的 Azure 终结点和密钥创建变量。

重要

转到 Azure 门户。 如果你在“先决条件”部分创建的人脸资源部署成功,请单击“后续步骤”下的“转到资源”按钮 。 在资源的“密钥和终结点”页的“资源管理”下可以找到密钥和终结点 。

重要

完成后,请记住将密钥从代码中删除,并且永远不要公开发布该密钥。 对于生产环境,请考虑使用安全的方法来存储和访问凭据。 有关详细信息,请参阅认知服务安全性文章。

key = "<paste-your-face-key-here>"
endpoint = "<paste-your-face-endpoint-here>"

对象模型

以下类和接口将处理人脸 .NET 客户端库的某些主要功能:

名称 说明
FaceClient 此类代表使用人脸服务的授权,使用所有人脸功能时都需要用到它。 请使用你的订阅信息实例化此类,然后使用它来生成其他类的实例。
人脸 此类处理可对人脸执行的基本检测和识别任务。
DetectedFace 此类代表已从图像中的单个人脸检测到的所有数据。 可以使用它来检索有关人脸的详细信息。
FaceList 此类管理云中存储的 FaceList 构造,这些构造存储各种不同的人脸。
PersonGroupPerson 此类管理云中存储的 Person 构造,这些构造存储属于单个人员的一组人脸。
PersonGroup 此类管理云中存储的 PersonGroup 构造,这些构造存储各种不同的 Person 对象。

代码示例

以下代码片段演示如何使用适用于 .NET 的人脸客户端库执行以下任务:

提示

想要立即查看整个快速入门代码文件? 可以在 GitHub 上找到它,其中包含此快速入门中的代码示例。

验证客户端

使用终结点和密钥实例化某个客户端。 使用密钥创建 ApiKeyCredentials 对象,并使用该对象在终结点中创建 FaceClient 对象 。

const credentials = new msRest.ApiKeyCredentials({ inHeader: { 'Ocp-Apim-Subscription-Key': key } });
const client = new Face.FaceClient(credentials, endpoint);

声明全局值和 helper 函数

你稍后将添加的一些人脸操作需要以下全局值。

该 URL 指向示例图像的文件夹。 UUID 将用作要创建的 PersonGroup 的名称和 ID。

const image_base_url = "https://csdx.blob.core.windows.net/resources/Face/Images/";
const person_group_id = uuid();

你将使用以下函数来等待 PersonGroup 的训练完成。

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

检测和分析人脸

人脸检测是进行人脸分析和身份验证的第一步。 本部分介绍如何返回额外的人脸属性数据。 如果只想检测人脸以进行人脸识别或验证,请跳到后面的部分。

获取检测到的人脸对象

创建新方法以检测人脸。 DetectFaceExtract 方法处理给定 URL 处的三个图像,并在程序内存中创建 DetectedFace 对象的列表。 FaceAttributeType 值列表指定要提取的特征。

然后,DetectFaceExtract 方法会分析并输出每个检测到的人脸的属性数据。 每个属性必须在原始人脸检测 API 调用中单独指定(在 FaceAttributeType 列表中)。 下面的代码处理每个属性,但你可能只需要使用一个或一些属性。

“QualityForRecognition”属性是有关检测中所用图像的质量是否足以尝试人脸识别的整体图像质量指示器。 若要利用质量属性,用户需要通过将 detectionModel 参数设置为 detection_01 或 detection_03,将 recognitionModel 参数设置为 recognition_03 或 recognition_04 来分配模型版本,并在请求中包含 QualityForRecognition 属性,如上面的示例所示。

async function DetectFaceExtract() {
    console.log("========DETECT FACES========");
    console.log();

    // Create a list of images
    const image_file_names = [
        "detection1.jpg",    // single female with glasses
        // "detection2.jpg", // (optional: single man)
        // "detection3.jpg", // (optional: single male construction worker)
        // "detection4.jpg", // (optional: 3 people at cafe, 1 is blurred)
        "detection5.jpg",    // family, woman child man
        "detection6.jpg"     // elderly couple, male female
    ];

// NOTE await does not work properly in for, forEach, and while loops. Use Array.map and Promise.all instead.
    await Promise.all (image_file_names.map (async function (image_file_name) {
        let detected_faces = await client.face.detectWithUrl(image_base_url + image_file_name,
            {
                returnFaceAttributes: ["Accessories","Age","Blur","Emotion","Exposure","FacialHair","Glasses","Hair","HeadPose","Makeup","Noise","Occlusion","Smile","QualityForRecognition"],
                // We specify detection model 1 because we are retrieving attributes.
                detectionModel: "detection_01",
                recognitionModel: "recognition_03"
            });
        console.log (detected_faces.length + " face(s) detected from image " + image_file_name + ".");
        console.log("Face attributes for face(s) in " + image_file_name + ":");

// Parse and print all attributes of each detected face.
        detected_faces.forEach (async function (face) {
            // Get the bounding box of the face
            console.log("Bounding box:\n  Left: " + face.faceRectangle.left + "\n  Top: " + face.faceRectangle.top + "\n  Width: " + face.faceRectangle.width + "\n  Height: " + face.faceRectangle.height);

            // Get the accessories of the face
            let accessories = face.faceAttributes.accessories.join();
            if (0 === accessories.length) {
                console.log ("No accessories detected.");
            }
            else {
                console.log ("Accessories: " + accessories);
            }

            // Get face other attributes
            console.log("Age: " + face.faceAttributes.age);
            console.log("Blur: " + face.faceAttributes.blur.blurLevel);

            // Get emotion on the face
            let emotions = "";
            let emotion_threshold = 0.0;
            if (face.faceAttributes.emotion.anger > emotion_threshold) { emotions += "anger, "; }
            if (face.faceAttributes.emotion.contempt > emotion_threshold) { emotions += "contempt, "; }
            if (face.faceAttributes.emotion.disgust > emotion_threshold) { emotions +=  "disgust, "; }
            if (face.faceAttributes.emotion.fear > emotion_threshold) { emotions +=  "fear, "; }
            if (face.faceAttributes.emotion.happiness > emotion_threshold) { emotions +=  "happiness, "; }
            if (face.faceAttributes.emotion.neutral > emotion_threshold) { emotions +=  "neutral, "; }
            if (face.faceAttributes.emotion.sadness > emotion_threshold) { emotions +=  "sadness, "; }
            if (face.faceAttributes.emotion.surprise > emotion_threshold) { emotions +=  "surprise, "; }
            if (emotions.length > 0) {
                console.log ("Emotions: " + emotions.slice (0, -2));
            }
            else {
                console.log ("No emotions detected.");
            }
            
            // Get more face attributes
            console.log("Exposure: " + face.faceAttributes.exposure.exposureLevel);
            if (face.faceAttributes.facialHair.moustache + face.faceAttributes.facialHair.beard + face.faceAttributes.facialHair.sideburns > 0) {
                console.log("FacialHair: Yes");
            }
            else {
                console.log("FacialHair: No");
            }
            console.log("Glasses: " + face.faceAttributes.glasses);

            // Get hair color
            var color = "";
            if (face.faceAttributes.hair.hairColor.length === 0) {
                if (face.faceAttributes.hair.invisible) { color = "Invisible"; } else { color = "Bald"; }
            }
            else {
                color = "Unknown";
                var highest_confidence = 0.0;
                face.faceAttributes.hair.hairColor.forEach (function (hair_color) {
                    if (hair_color.confidence > highest_confidence) {
                        highest_confidence = hair_color.confidence;
                        color = hair_color.color;
                    }
                });
            }
            console.log("Hair: " + color);

            // Get more attributes
            console.log("Head pose:");
            console.log("  Pitch: " + face.faceAttributes.headPose.pitch);
            console.log("  Roll: " + face.faceAttributes.headPose.roll);
            console.log("  Yaw: " + face.faceAttributes.headPose.yaw);
 
            console.log("Makeup: " + ((face.faceAttributes.makeup.eyeMakeup || face.faceAttributes.makeup.lipMakeup) ? "Yes" : "No"));
            console.log("Noise: " + face.faceAttributes.noise.noiseLevel);

            console.log("Occlusion:");
            console.log("  Eye occluded: " + (face.faceAttributes.occlusion.eyeOccluded ? "Yes" : "No"));
            console.log("  Forehead occluded: " + (face.faceAttributes.occlusion.foreheadOccluded ? "Yes" : "No"));
            console.log("  Mouth occluded: " + (face.faceAttributes.occlusion.mouthOccluded ? "Yes" : "No"));

            console.log("Smile: " + face.faceAttributes.smile);

            console.log("QualityForRecognition: " + face.faceAttributes.qualityForRecognition)
            console.log();
        });
    }));
}

上面的代码处理以下远程图像:

Photo of a woman smilingPhoto of a man, woman, and babyPhoto of an older man and woman

提示

还可以检测本地图像中的人脸。 请参阅 Face 方法,如 DetectWithStreamAsync

识别人脸

识别操作获取一个人(或多个人)的图像,并查找与图像中的每个人脸相关联的存储的人员对象(人脸识别搜索)。 它将每个检测到的人脸与某个 PersonGroup(面部特征已知的不同 Person 对象的数据库)进行比较。 为了执行“识别”操作,你首先需要创建并训练 PersonGroup

将人脸添加到 PersonGroup

创建以下函数以将人脸添加到 PersonGroup

async function AddFacesToPersonGroup(person_dictionary, person_group_id) {
    console.log ("Adding faces to person group...");
    // The similar faces will be grouped into a single person group person.
    
    await Promise.all (Object.keys(person_dictionary).map (async function (key) {
        const value = person_dictionary[key];

        // Wait briefly so we do not exceed rate limits.
        await sleep (1000);

        let person = await client.personGroupPerson.create(person_group_id, { name : key });
        console.log("Create a person group person: " + key + ".");

        // Add faces to the person group person.
        await Promise.all (value.map (async function (similar_image) {
            // Check if the image is of sufficent quality for recognition.
            let sufficientQuality = true;
            let detected_faces = await client.face.detectWithUrl(image_base_url + similar_image,
                {
                    returnFaceAttributes: ["QualityForRecognition"],
                    detectionModel: "detection_03",
                    recognitionModel: "recognition_03"
                });
            detected_faces.forEach(detected_face => {
                if (detected_face.faceAttributes.qualityForRecognition != 'high'){
                    sufficientQuality = false;
                }
            });

            // Quality is sufficent, add to group.
            if (sufficientQuality){
                console.log("Add face to the person group person: (" + key + ") from image: " + similar_image + ".");
                await client.personGroupPerson.addFaceFromUrl(person_group_id, person.personId, image_base_url + similar_image);
            }
        }));
    }));

    console.log ("Done adding faces to person group.");
}

等待 PersonGroup 训练

创建以下帮助程序函数,静待 PersonGroup完成训练。

async function WaitForPersonGroupTraining(person_group_id) {
    // Wait so we do not exceed rate limits.
    console.log ("Waiting 10 seconds...");
    await sleep (10000);
    let result = await client.personGroup.getTrainingStatus(person_group_id);
    console.log("Training status: " + result.status + ".");
    if (result.status !== "succeeded") {
        await WaitForPersonGroupTraining(person_group_id);
    }
}

创建人员组

以下代码:

  • 创建 PersonGroup
  • 通过调用你以前定义的 AddFacesToPersonGroup,将人脸添加到 PersonGroup。
  • 训练 PersonGroup。
  • 识别该 PersonGroup 中的人脸。

现已准备好在“验证”、“识别”或“分组”操作中使用此 PersonGroup 及其关联的 Person 对象 。

async function IdentifyInPersonGroup() {
    console.log("========IDENTIFY FACES========");
    console.log();

// Create a dictionary for all your images, grouping similar ones under the same key.
    const person_dictionary = {
        "Family1-Dad" : ["Family1-Dad1.jpg", "Family1-Dad2.jpg"],
        "Family1-Mom" : ["Family1-Mom1.jpg", "Family1-Mom2.jpg"],
        "Family1-Son" : ["Family1-Son1.jpg", "Family1-Son2.jpg"],
        "Family1-Daughter" : ["Family1-Daughter1.jpg", "Family1-Daughter2.jpg"],
        "Family2-Lady" : ["Family2-Lady1.jpg", "Family2-Lady2.jpg"],
        "Family2-Man" : ["Family2-Man1.jpg", "Family2-Man2.jpg"]
    };

    // A group photo that includes some of the persons you seek to identify from your dictionary.
    let source_image_file_name = "identification1.jpg";

    // Create a person group. 
    console.log("Creating a person group with ID: " + person_group_id);
    await client.personGroup.create(person_group_id, { name : person_group_id, recognitionModel : "recognition_04" });

    await AddFacesToPersonGroup(person_dictionary, person_group_id);

    // Start to train the person group.
    console.log();
    console.log("Training person group: " + person_group_id + ".");
    await client.personGroup.train(person_group_id);

    await WaitForPersonGroupTraining(person_group_id);
    console.log();

    // Detect faces from source image url and only take those with sufficient quality for recognition.
    let face_ids = (await DetectFaceRecognize(image_base_url + source_image_file_name)).map (face => face.faceId);
    // Identify the faces in a person group.
    let results = await client.face.identify(face_ids, { personGroupId : person_group_id});
    await Promise.all (results.map (async function (result) {
        let person = await client.personGroupPerson.get(person_group_id, result.candidates[0].personId);
        console.log("Person: " + person.name + " is identified for face in: " + source_image_file_name + " with ID: " + result.faceId + ". Confidence: " + result.candidates[0].confidence + ".");
    }));
    console.log();
}

提示

你还可以从本地图像创建 PersonGroup。 请参阅 PersonGroupPerson 方法,如 AddFaceFromStream

查找相似人脸

以下代码采用检测到的单个人脸(源),并搜索其他一组人脸(目标),以找到匹配项(按图像进行人脸搜索)。 找到匹配项后,它会将匹配的人脸的 ID 输出到控制台。

检测人脸以进行比较

首先定义另一个人脸检测方法。 需要先检测图像中的人脸,然后才能对其进行比较;此检测方法已针对比较操作进行优化。 它不会提取以上部分所示的详细人脸属性,而是使用另一个识别模型。

async function DetectFaceRecognize(url) {
    // Detect faces from image URL. Since only recognizing, use the recognition model 4.
    // We use detection model 3 because we are only retrieving the qualityForRecognition attribute.
    // Result faces with quality for recognition lower than "medium" are filtered out.
    let detected_faces = await client.face.detectWithUrl(url,
        {
            detectionModel: "detection_03",
            recognitionModel: "recognition_04",
            returnFaceAttributes: ["QualityForRecognition"]
        });
    return detected_faces.filter(face => face.faceAttributes.qualityForRecognition == 'high' || face.faceAttributes.qualityForRecognition == 'medium');
}

查找匹配项

以下方法检测一组目标图像和单个源图像中的人脸。 然后,它将比较这些人脸,并查找与源图像类似的所有目标图像。 最后,该方法会将匹配项详细信息输出到控制台。

// Find a similar face(s) in the list of IDs. Comapring only the first in list for testing purposes.
let results = await client.face.findSimilar(detected_faces[0].faceId, { faceIds : target_face_ids });
results.forEach (function (result) {
    console.log("Faces from: " + source_image_file_name + " and ID: " + result.faceId + " are similar with confidence: " + result.confidence + ".");
});
console.log();

在此程序中,以下远程图像将用作源:

Photo of a man smiling

在此图像中检测到的人脸应作为与源图像人脸相似的人脸返回。

Photo of a man smiling; this is the same person as the previous image

Main

最后,创建并调用 main 函数。

async function main() {
    await DetectFaceExtract();
    await FindSimilar();
    await IdentifyInPersonGroup();
    console.log ("Done.");
}
main();

运行应用程序

在快速入门文件中使用 node 命令运行应用程序。

node index.js

清理资源

如果想要清理并删除认知服务订阅,可以删除资源或资源组。 删除资源组同时也会删除与之相关联的任何其他资源。

后续步骤

此快速入门介绍了如何使用适用于 JavaScript 的人脸客户端库来执行基本的人脸识别任务。 接下来,了解不同的人脸检测模型,以及如何为用例指定正确的模型。

开始使用适用于 Python 的人脸客户端库进行人脸识别。 请按照以下步骤安装程序包并试用基本任务的示例代码。 通过人脸服务,可以访问用于检测和识别图像中的人脸的高级算法。

使用适用于 Python 的人脸客户端库可以:

参考文档 | 库源代码 | 包 (PiPy) | 示例

先决条件

  • Azure 订阅 - 免费创建订阅
  • Python 3.x
    • 你的 Python 安装应包含 pip。 可以通过在命令行上运行 pip --version 来检查是否安装了 pip。 通过安装最新版本的 Python 获取 pip。
  • 你的 Azure 帐户必须分配有认知服务参与者角色,你才能同意负责的 AI 条款并创建资源。 若要将此角色分配给你的帐户,请按照分配角色文档中的步骤进行操作,或与管理员联系。
  • 拥有 Azure 订阅后,在 Azure 门户中创建人脸资源,获取密钥和终结点。 部署后,单击“转到资源”。
    • 需要从创建的资源获取密钥和终结点,以便将应用程序连接到人脸 API。 你稍后会在快速入门中将密钥和终结点粘贴到下方的代码中。
    • 可以使用免费定价层 (F0) 试用该服务,然后再升级到付费层进行生产。

设置

安装客户端库

在安装 Python 后,可以通过以下命令安装客户端库:

pip install --upgrade azure-cognitiveservices-vision-face

创建新的 Python 应用程序

创建新的 Python 脚本,例如 quickstart-file.py。 在喜好的编辑器或 IDE 中打开该文件,并导入以下库。

import asyncio
import io
import glob
import os
import sys
import time
import uuid
import requests
from urllib.parse import urlparse
from io import BytesIO
# To install this module, run:
# python -m pip install Pillow
from PIL import Image, ImageDraw
from azure.cognitiveservices.vision.face import FaceClient
from msrest.authentication import CognitiveServicesCredentials
from azure.cognitiveservices.vision.face.models import TrainingStatusType, Person, QualityForRecognition

提示

想要立即查看整个快速入门代码文件? 可以在 GitHub 上找到它,其中包含此快速入门中的代码示例。

然后,为该资源的 Azure 终结点和密钥创建变量。

# This key will serve all examples in this document.
KEY = "PASTE_YOUR_FACE_SUBSCRIPTION_KEY_HERE"

# This endpoint will be used in all examples in this quickstart.
ENDPOINT = "PASTE_YOUR_FACE_ENDPOINT_HERE"

重要

转到 Azure 门户。 如果你在“先决条件”部分创建的人脸资源部署成功,请单击“后续步骤”下的“转到资源”按钮 。 在资源的“密钥和终结点”页的“资源管理”下可以找到密钥和终结点 。

重要

完成后,请记住将密钥从代码中删除,并且永远不要公开发布该密钥。 对于生产环境,请考虑使用安全的方法来存储和访问凭据。 有关详细信息,请参阅认知服务安全性文章。

对象模型

以下类和接口将处理人脸 Python 客户端库的某些主要功能。

名称 说明
FaceClient 此类代表使用人脸服务的授权,使用所有人脸功能时都需要用到它。 请使用你的订阅信息实例化此类,然后使用它来生成其他类的实例。
FaceOperations 此类处理可对人脸执行的基本检测和识别任务。
DetectedFace 此类代表已从图像中的单个人脸检测到的所有数据。 可以使用它来检索有关人脸的详细信息。
FaceListOperations 此类管理云中存储的 FaceList 构造,这些构造存储各种不同的人脸。
PersonGroupPersonOperations 此类管理云中存储的 Person 构造,这些构造存储属于单个人员的一组人脸。
PersonGroupOperations 此类管理云中存储的 PersonGroup 构造,这些构造存储各种不同的 Person 对象。
ShapshotOperations 此类管理快照功能;可以使用它来暂时保存所有基于云的人脸数据,并将这些数据迁移到新的 Azure 订阅。

代码示例

这些代码片段演示如何使用适用于 Python 的人脸客户端库执行以下任务:

验证客户端

使用终结点和密钥实例化某个客户端。 使用密钥创建 CognitiveServicesCredentials 对象,然后在终结点上使用该对象创建 FaceClient 对象。

# Create an authenticated FaceClient.
face_client = FaceClient(ENDPOINT, CognitiveServicesCredentials(KEY))

检测和分析人脸

人脸检测是进行人脸分析和身份验证所必需的。 本部分介绍如何返回额外的人脸属性数据。 如果只想检测人脸以进行人脸识别或验证,请跳到后面的部分。

以下代码检测远程图像中的人脸。 它将检测到的人脸 ID 输出到控制台,并将其存储在程序内存中。 然后,它在包含多个人员的图像中检测人脸,并将其 ID 输出到控制台。 更改 detect_with_url 方法中的参数可以返回包含每个 DetectedFace 对象的不同信息。

“QualityForRecognition”属性是有关检测中所用图像的质量是否足以尝试人脸识别的整体图像质量指示器。 若要利用质量属性,用户需要通过将 detectionModel 参数设置为 detection_01 或 detection_03,将 recognitionModel 参数设置为 recognition_03 或 recognition_04 来分配模型版本,并在请求中包含 QualityForRecognition 属性,如上面的示例所示。

# Detect a face in an image that contains a single face
single_face_image_url = 'https://www.biography.com/.image/t_share/MTQ1MzAyNzYzOTgxNTE0NTEz/john-f-kennedy---mini-biography.jpg'
single_image_name = os.path.basename(single_face_image_url)
# We use detection model 3 to get better performance.
detected_faces = face_client.face.detect_with_url(url=single_face_image_url, detection_model='detection_03')
if not detected_faces:
    raise Exception('No face detected from image {}'.format(single_image_name))

# Display the detected face ID in the first single-face image.
# Face IDs are used for comparison to faces (their IDs) detected in other images.
print('Detected face ID from', single_image_name, ':')
for face in detected_faces: print (face.face_id)
print()

# Save this ID for use in Find Similar
first_image_face_ID = detected_faces[0].face_id

提示

还可以检测本地图像中的人脸。 请参阅 FaceOperations 方法,如 detect_with_stream。

显示和定格人脸

下面的代码使用 DetectedFace.faceRectangle 属性将给定的图像输出到显示屏并在人脸周围绘制矩形。

# Detect a face in an image that contains a single face
single_face_image_url = 'https://raw.githubusercontent.com/Microsoft/Cognitive-Face-Windows/master/Data/detection1.jpg'
single_image_name = os.path.basename(single_face_image_url)
# We use detection model 3 to get better performance.
detected_faces = face_client.face.detect_with_url(url=single_face_image_url, detection_model='detection_03')
if not detected_faces:
    raise Exception('No face detected from image {}'.format(single_image_name))

# Convert width height to a point in a rectangle
def getRectangle(faceDictionary):
    rect = faceDictionary.face_rectangle
    left = rect.left
    top = rect.top
    right = left + rect.width
    bottom = top + rect.height
    
    return ((left, top), (right, bottom))

def drawFaceRectangles() :
# Download the image from the url
    response = requests.get(single_face_image_url)
    img = Image.open(BytesIO(response.content))

# For each face returned use the face rectangle and draw a red box.
    print('Drawing rectangle around face... see popup for results.')
    draw = ImageDraw.Draw(img)
    for face in detected_faces:
        draw.rectangle(getRectangle(face), outline='red')

# Display the image in the default image browser.
    img.show()

# Uncomment this to show the face rectangles.
#    drawFaceRectangles()

A young woman with a red rectangle drawn around the face

识别人脸

识别操作采用一个(或多个)人员的图像,并在图像中查找每个人脸的标识(人脸识别搜索)。 它将每个检测到的人脸与某个 PersonGroup(面部特征已知的不同 Person 对象的数据库)进行比较。

创建人员组

以下代码创建包含三个不同 Person 对象的 PersonGroup。 它将每个 Person 与一组示例图像相关联,然后进行训练以便能够识别每个人。

若要逐步完成此方案,需将以下图像保存到项目的根目录: https://github.com/Azure-Samples/cognitive-services-sample-data-files/tree/master/Face/images

此图像组包含三组人脸图像,这些图像对应于三个不同的人。 该代码定义三个 Person 对象,并将其关联到以 womanmanchild 开头的图像文件。

设置图像后,在脚本的顶部为要创建的 PersonGroup 对象定义一个标签。

# Used in the Person Group Operations and Delete Person Group examples.
# You can call list_person_groups to print a list of preexisting PersonGroups.
# SOURCE_PERSON_GROUP_ID should be all lowercase and alphanumeric. For example, 'mygroupname' (dashes are OK).
PERSON_GROUP_ID = str(uuid.uuid4()) # assign a random ID (or name it anything)

# Used for the Delete Person Group example.
TARGET_PERSON_GROUP_ID = str(uuid.uuid4()) # assign a random ID (or name it anything)

然后将以下代码添加到脚本的底部。 此代码创建一个 PersonGroup 对象和三个 Person 对象。

'''
Create the PersonGroup
'''
# Create empty Person Group. Person Group ID must be lower case, alphanumeric, and/or with '-', '_'.
print('Person group:', PERSON_GROUP_ID)
face_client.person_group.create(person_group_id=PERSON_GROUP_ID, name=PERSON_GROUP_ID)

# Define woman friend
woman = face_client.person_group_person.create(PERSON_GROUP_ID, "Woman")
# Define man friend
man = face_client.person_group_person.create(PERSON_GROUP_ID, "Man")
# Define child friend
child = face_client.person_group_person.create(PERSON_GROUP_ID, "Child")

将人脸添加到 Person

以下代码按图像前缀对图像排序、检测人脸,然后将人脸分配到每个 Person 对象。

'''
Detect faces and register to correct person
'''
# Find all jpeg images of friends in working directory
woman_images = [file for file in glob.glob('*.jpg') if file.startswith("w")]
man_images = [file for file in glob.glob('*.jpg') if file.startswith("m")]
child_images = [file for file in glob.glob('*.jpg') if file.startswith("ch")]

# Add to a woman person
for image in woman_images:
    w = open(image, 'r+b')
    # Check if the image is of sufficent quality for recognition.
    sufficientQuality = True
    detected_faces = face_client.face.detect_with_url(url=single_face_image_url, detection_model='detection_03', recognition_model='recognition_04', return_face_attributes=['qualityForRecognition'])
    for face in detected_faces:
        if face.face_attributes.quality_for_recognition != QualityForRecognition.high:
            sufficientQuality = False
            break
    if not sufficientQuality: continue
    face_client.person_group_person.add_face_from_stream(PERSON_GROUP_ID, woman.person_id, w)

# Add to a man person
for image in man_images:
    m = open(image, 'r+b')
    # Check if the image is of sufficent quality for recognition.
    sufficientQuality = True
    detected_faces = face_client.face.detect_with_url(url=single_face_image_url, detection_model='detection_03', recognition_model='recognition_04', return_face_attributes=['qualityForRecognition'])
    for face in detected_faces:
        if face.face_attributes.quality_for_recognition != QualityForRecognition.high:
            sufficientQuality = False
            break
    if not sufficientQuality: continue
    face_client.person_group_person.add_face_from_stream(PERSON_GROUP_ID, man.person_id, m)

# Add to a child person
for image in child_images:
    ch = open(image, 'r+b')
    # Check if the image is of sufficent quality for recognition.
    sufficientQuality = True
    detected_faces = face_client.face.detect_with_url(url=single_face_image_url, detection_model='detection_03', recognition_model='recognition_04', return_face_attributes=['qualityForRecognition'])
    for face in detected_faces:
        if face.face_attributes.quality_for_recognition != QualityForRecognition.high:
            sufficientQuality = False
            break
    if not sufficientQuality: continue
    face_client.person_group_person.add_face_from_stream(PERSON_GROUP_ID, child.person_id, ch)

提示

还可以从 URL 引用的远程图像创建 PersonGroup。 请参阅 PersonGroupPersonOperations 方法,例如 add_face_from_url。

训练 PersonGroup

分配人脸后,必须训练 PersonGroup,使其能够识别与其每个 Person 对象关联的视觉特征。 以下代码调用异步 train 方法并轮询结果,然后将状态输出到控制台。

'''
Train PersonGroup
'''
print()
print('Training the person group...')
# Train the person group
face_client.person_group.train(PERSON_GROUP_ID)

while (True):
    training_status = face_client.person_group.get_training_status(PERSON_GROUP_ID)
    print("Training status: {}.".format(training_status.status))
    print()
    if (training_status.status is TrainingStatusType.succeeded):
        break
    elif (training_status.status is TrainingStatusType.failed):
        face_client.person_group.delete(person_group_id=PERSON_GROUP_ID)
        sys.exit('Training the person group has failed.')
    time.sleep(5)

提示

人脸 API 在一组预构建的模型呢上运行,这些模型在本质上是静态的(模型的性能不会因为运行服务而提高或降低)。 如果 Microsoft 更新模型的后端,但不迁移整个新模型版本,那么模型生成的结果可能会变化。 若要使用更新的模型版本,可重新训练 PersonGroup,将更新的模型指定为具有相同注册映像的参数。

获取测试图像

以下代码在项目根目录中查找图像 test-image-person-group.jpg,并检测该图像中的人脸。 可以使用用于 PersonGroup 管理的图像查找此图像: https://github.com/Azure-Samples/cognitive-services-sample-data-files/tree/master/Face/images

'''
Identify a face against a defined PersonGroup
'''
# Group image for testing against
test_image_array = glob.glob('test-image-person-group.jpg')
image = open(test_image_array[0], 'r+b')

print('Pausing for 60 seconds to avoid triggering rate limit on free account...')
time.sleep (60)

# Detect faces
face_ids = []
# We use detection model 3 to get better performance, recognition model 4 to support quality for recognition attribute.
faces = face_client.face.detect_with_stream(image, detection_model='detection_03', recognition_model='recognition_04', return_face_attributes=['qualityForRecognition'])
for face in faces:
    # Only take the face if it is of sufficient quality.
    if face.face_attributes.quality_for_recognition == QualityForRecognition.high or face.face_attributes.quality_for_recognition == QualityForRecognition.medium:
        face_ids.append(face.face_id)

输出识别的人脸 ID

identify 方法采用检测到的人脸数组,并将其与 PersonGroup 进行比较。 如果检测到的某个人脸与某个人相匹配,则它会保存结果。 此代码将详细的匹配结果输出到控制台。

# Identify faces
results = face_client.face.identify(face_ids, PERSON_GROUP_ID)
print('Identifying faces in {}'.format(os.path.basename(image.name)))
if not results:
    print('No person identified in the person group for faces from {}.'.format(os.path.basename(image.name)))
for person in results:
    if len(person.candidates) > 0:
        print('Person for face ID {} is identified in {} with a confidence of {}.'.format(person.face_id, os.path.basename(image.name), person.candidates[0].confidence)) # Get topmost confidence score
    else:
        print('No person identified for face ID {} in {}.'.format(person.face_id, os.path.basename(image.name)))

验证人脸

验证操作采用某个人脸 ID 和其他人脸 ID 或 Person 对象,并确定它们是否属于同一个人。 验证可用于重复检查识别操作返回的人脸匹配。

以下代码检测两个源图像中的人脸,然后针对从目标图像检测到的人脸来验证它们。

获取测试图像

以下代码块声明将指向验证操作的源和目标图像的变量。

# Base url for the Verify and Facelist/Large Facelist operations
IMAGE_BASE_URL = 'https://csdx.blob.core.windows.net/resources/Face/Images/'
# Create a list to hold the target photos of the same person
target_image_file_names = ['Family1-Dad1.jpg', 'Family1-Dad2.jpg']
# The source photos contain this person
source_image_file_name1 = 'Family1-Dad3.jpg'
source_image_file_name2 = 'Family1-Son1.jpg'

检测人脸进行验证

以下代码检测源和目标图像中的人脸并将其保存到变量中。

# Detect face(s) from source image 1, returns a list[DetectedFaces]
# We use detection model 3 to get better performance.
detected_faces1 = face_client.face.detect_with_url(IMAGE_BASE_URL + source_image_file_name1, detection_model='detection_03')
# Add the returned face's face ID
source_image1_id = detected_faces1[0].face_id
print('{} face(s) detected from image {}.'.format(len(detected_faces1), source_image_file_name1))

# Detect face(s) from source image 2, returns a list[DetectedFaces]
detected_faces2 = face_client.face.detect_with_url(IMAGE_BASE_URL + source_image_file_name2, detection_model='detection_03')
# Add the returned face's face ID
source_image2_id = detected_faces2[0].face_id
print('{} face(s) detected from image {}.'.format(len(detected_faces2), source_image_file_name2))

# List for the target face IDs (uuids)
detected_faces_ids = []
# Detect faces from target image url list, returns a list[DetectedFaces]
for image_file_name in target_image_file_names:
    # We use detection model 3 to get better performance.
    detected_faces = face_client.face.detect_with_url(IMAGE_BASE_URL + image_file_name, detection_model='detection_03')
    # Add the returned face's face ID
    detected_faces_ids.append(detected_faces[0].face_id)
    print('{} face(s) detected from image {}.'.format(len(detected_faces), image_file_name))

获取验证结果

以下代码将每个源图像与目标图像进行比较并打印出一条消息,指示它们是否属于同一个人。

# Verification example for faces of the same person. The higher the confidence, the more identical the faces in the images are.
# Since target faces are the same person, in this example, we can use the 1st ID in the detected_faces_ids list to compare.
verify_result_same = face_client.face.verify_face_to_face(source_image1_id, detected_faces_ids[0])
print('Faces from {} & {} are of the same person, with confidence: {}'
    .format(source_image_file_name1, target_image_file_names[0], verify_result_same.confidence)
    if verify_result_same.is_identical
    else 'Faces from {} & {} are of a different person, with confidence: {}'
        .format(source_image_file_name1, target_image_file_names[0], verify_result_same.confidence))

# Verification example for faces of different persons.
# Since target faces are same person, in this example, we can use the 1st ID in the detected_faces_ids list to compare.
verify_result_diff = face_client.face.verify_face_to_face(source_image2_id, detected_faces_ids[0])
print('Faces from {} & {} are of the same person, with confidence: {}'
    .format(source_image_file_name2, target_image_file_names[0], verify_result_diff.confidence)
    if verify_result_diff.is_identical
    else 'Faces from {} & {} are of a different person, with confidence: {}'
        .format(source_image_file_name2, target_image_file_names[0], verify_result_diff.confidence))

查找相似人脸

以下代码采用检测到的单个人脸(源),并搜索其他一组人脸(目标),以找到匹配项(按图像进行人脸搜索)。 找到匹配项后,它会将匹配的人脸的 ID 输出到控制台。

查找匹配项

首先,运行上一部分(检测并分析人脸)所示的代码,以保存对单个人脸的引用。 然后运行以下代码,以获取对图像组中多个人脸的引用。

# Detect the faces in an image that contains multiple faces
# Each detected face gets assigned a new ID
multi_face_image_url = "http://www.historyplace.com/kennedy/president-family-portrait-closeup.jpg"
multi_image_name = os.path.basename(multi_face_image_url)
# We use detection model 3 to get better performance.
detected_faces2 = face_client.face.detect_with_url(url=multi_face_image_url, detection_model='detection_03')

然后添加以下代码块,以查找该组中第一个人脸的实例。 若要了解如何修改此行为,请参阅 find_similar 方法。

# Search through faces detected in group image for the single face from first image.
# First, create a list of the face IDs found in the second image.
second_image_face_IDs = list(map(lambda x: x.face_id, detected_faces2))
# Next, find similar face IDs like the one detected in the first image.
similar_faces = face_client.face.find_similar(face_id=first_image_face_ID, face_ids=second_image_face_IDs)
if not similar_faces:
    print('No similar faces found in', multi_image_name, '.')

使用以下代码将匹配详细信息输出到控制台。

# Print the details of the similar faces detected
else:
    print('Similar faces found in', multi_image_name + ':')
    for face in similar_faces:
        first_image_face_ID = face.face_id
        # The similar face IDs of the single face image and the group image do not need to match, 
        # they are only used for identification purposes in each image.
        # The similar faces are matched using the Cognitive Services algorithm in find_similar().
        face_info = next(x for x in detected_faces2 if x.face_id == first_image_face_ID)
        if face_info:
            print('  Face ID: ', first_image_face_ID)
            print('  Face rectangle:')
            print('    Left: ', str(face_info.face_rectangle.left))
            print('    Top: ', str(face_info.face_rectangle.top))
            print('    Width: ', str(face_info.face_rectangle.width))
            print('    Height: ', str(face_info.face_rectangle.height))

运行应用程序

使用 python 命令从应用程序目录运行人脸识别应用。

python quickstart-file.py

清理资源

如果想要清理并删除认知服务订阅,可以删除资源或资源组。 删除资源组同时也会删除与之相关联的任何其他资源。

如果你在本快速入门中创建了 PersonGroup 并想要删除它,请在脚本中运行以下代码:

# Delete the main person group.
face_client.person_group.delete(person_group_id=PERSON_GROUP_ID)
print("Deleted the person group {} from the source location.".format(PERSON_GROUP_ID))
print()

后续步骤

在本快速入门中,你已了解如何使用适用于 Python 的人脸客户端库来执行基本人脸识别任务。 接下来,了解不同的人脸检测模型,以及如何为用例指定正确的模型。

开始使用人脸 REST API 进行人脸识别。 通过人脸服务,可以访问用于检测和识别图像中的人脸的高级算法。

使用人脸 REST API 执行以下操作:

注意

此快速入门使用 cURL 命令来调用 REST API。 也可以使用编程语言调用 REST API。 请参阅 GitHub 示例,查看 C#PythonJavaJavaScriptGo 的相关示例。

先决条件

  • Azure 订阅 - 免费创建订阅
  • 你的 Azure 帐户必须分配有认知服务参与者角色,你才能同意负责的 AI 条款并创建资源。 若要将此角色分配给你的帐户,请按照分配角色文档中的步骤进行操作,或与管理员联系。
  • 拥有 Azure 订阅后,请在 Azure 门户中创建人脸资源,以获取密钥和终结点。 部署后,单击“转到资源”。
    • 需要从创建的资源获取密钥和终结点,以便将应用程序连接到人脸 API。 你稍后会在快速入门中将密钥和终结点粘贴到下方的代码中。
    • 可以使用免费定价层 (F0) 试用该服务,然后再升级到付费层进行生产。
  • PowerShell 6.0 及以上版本,或类似的命令行应用程序。

检测和分析人脸

将使用如下所示的命令来调用人脸 API 并获取图像中的人脸属性数据。 首先,将代码复制到文本编辑器中 - 在运行它之前,需对命令的某些部分进行更改。

curl -H "Ocp-Apim-Subscription-Key: TODO_INSERT_YOUR_FACE_SUBSCRIPTION_KEY_HERE" "TODO_INSERT_YOUR_FACE_ENDPOINT_HERE/face/v1.0/detect?detectionModel=detection_03&returnFaceId=true&returnFaceLandmarks=false&returnFaceAttributes=qualityForRecognition" -H "Content-Type: application/json" --data-ascii "{\"url\":\"https://upload.wikimedia.org/wikipedia/commons/c/c3/RH_Louise_Lillian_Gish.jpg\"}"

进行以下更改:

  1. Ocp-Apim-Subscription-Key 分配到有效的人脸订阅密钥。
  2. 需更改该查询 URL 的第一部分,使之与订阅密钥的相应终结点匹配。

    注意

    2019 年 7 月 1 日之后创建的新资源将使用自定义子域名。 有关详细信息和区域终结点的完整列表,请参阅认知服务的自定义子域名

  3. 可以选择更改请求正文中的 URL 以指向不同的映像。

进行更改以后,请打开命令提示符并输入新的命令。 此代码将处理以下远程图像。

An older man and woman

检查结果

应该会在控制台窗口中看到显示为 JSON 数据的人脸信息。 例如:

[
  {
    "faceId": "49d55c17-e018-4a42-ba7b-8cbbdfae7c6f",
    "faceRectangle": {
      "top": 131,
      "left": 177,
      "width": 162,
      "height": 162
    }
  }
]  

获取人脸特性

若要提取人脸属性,请再次调用检测 API,但将 detectionModel 设置为 detection_01。 同时,添加 returnFaceAttributes 查询参数。 该命令现在应如下所示。 与之前一样,请插入你的人脸订阅密钥和终结点。

curl -H "Ocp-Apim-Subscription-Key: TODO_INSERT_YOUR_FACE_SUBSCRIPTION_KEY_HERE" "TODO_INSERT_YOUR_FACE_ENDPOINT_HERE/face/v1.0/detect?detectionModel=detection_01&returnFaceId=true&returnFaceLandmarks=false&returnFaceAttributes=age,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise,qualityForRecognition" -H "Content-Type: application/json" --data-ascii "{\"url\":\"https://upload.wikimedia.org/wikipedia/commons/c/c3/RH_Louise_Lillian_Gish.jpg\"}"

检查结果

返回的人脸信息现在包含人脸属性。 例如:

[
  {
    "faceId": "49d55c17-e018-4a42-ba7b-8cbbdfae7c6f",
    "faceRectangle": {
      "top": 131,
      "left": 177,
      "width": 162,
      "height": 162
    },
    "faceAttributes": {
      "smile": 0,
      "headPose": {
        "pitch": 0,
        "roll": 0.1,
        "yaw": -32.9
      },
      "glasses": "NoGlasses",
      "emotion": {
        "anger": 0,
        "contempt": 0,
        "disgust": 0,
        "fear": 0,
        "happiness": 0,
        "neutral": 0.986,
        "sadness": 0.009,
        "surprise": 0.005
      },
      "blur": {
        "blurLevel": "low",
        "value": 0.06
      },
      "exposure": {
        "exposureLevel": "goodExposure",
        "value": 0.67
      },
      "noise": {
        "noiseLevel": "low",
        "value": 0
      },
      "makeup": {
        "eyeMakeup": true,
        "lipMakeup": true
      },
      "accessories": [],
      "occlusion": {
        "foreheadOccluded": false,
        "eyeOccluded": false,
        "mouthOccluded": false
      },
      "hair": {
        "bald": 0,
        "invisible": false,
        "hairColor": [
          {
            "color": "brown",
            "confidence": 1
          },
          {
            "color": "black",
            "confidence": 0.87
          },
          {
            "color": "other",
            "confidence": 0.51
          },
          {
            "color": "blond",
            "confidence": 0.08
          },
          {
            "color": "red",
            "confidence": 0.08
          },
          {
            "color": "gray",
            "confidence": 0.02
          }
        ]
      }
    }
  }
]

查找相似人脸

此操作采用检测到的单个人脸(源),并搜索其他一组人脸(目标),以找到匹配项(按图像进行人脸搜索)。 找到匹配项后,它会将匹配的人脸的 ID 输出到控制台。

检测人脸以进行比较

首先,需要先检测图像中的人脸,然后再进行比较。 如在检测和分析部分中所做的那样,运行此命令。 此检测方法针对比较操作进行了优化。 它不会如以上部分所示提取详细人脸属性,而是使用另一个检测模型。

curl -H "Ocp-Apim-Subscription-Key: TODO_INSERT_YOUR_FACE_SUBSCRIPTION_KEY_HERE" "TODO_INSERT_YOUR_FACE_ENDPOINT_HERE/face/v1.0/detect?detectionModel=detection_03&returnFaceId=true&returnFaceLandmarks=false" -H "Content-Type: application/json" --data-ascii "{\"url\":\"https://csdx.blob.core.windows.net/resources/Face/Images/Family1-Dad1.jpg\"}"

查找 JSON 响应中的 "faceId" 值,并将其保存到一个临时位置。 然后,为其他这些图像 URL 再次调用上述命令,并保存各自的面部 ID。 你将使用这些 ID 作为目标人脸组,从中查找相似的人脸。

https://csdx.blob.core.windows.net/resources/Face/Images/Family1-Daughter1.jpg
https://csdx.blob.core.windows.net/resources/Face/Images/Family1-Mom1.jpg
https://csdx.blob.core.windows.net/resources/Face/Images/Family1-Son1.jpg
https://csdx.blob.core.windows.net/resources/Face/Images/Family2-Lady1.jpg
https://csdx.blob.core.windows.net/resources/Face/Images/Family2-Man1.jpg
https://csdx.blob.core.windows.net/resources/Face/Images/Family3-Lady1.jpg
https://csdx.blob.core.windows.net/resources/Face/Images/Family3-Man1.jpg

最后,检测要用于匹配的单一源人脸,并保存其 ID。 将此 ID 与其他 ID 分开。

https://csdx.blob.core.windows.net/resources/Face/Images/findsimilar.jpg

Photo of a man smiling

查找匹配项

将以下命令复制到文本编辑器。

curl -v -X POST "https://westus.api.cognitive.microsoft.com/face/v1.0/findsimilars" -H "Content-Type: application/json" -H "Ocp-Apim-Subscription-Key: {subscription key}" --data-ascii "{body}"

然后,进行以下更改:

  1. Ocp-Apim-Subscription-Key 分配到有效的人脸订阅密钥。
  2. 需更改该查询 URL 的第一部分,使之与订阅密钥的相应终结点匹配。

对于 body 值,使用以下 JSON 内容:

{
    "faceId": "",
    "faceIds": [],
    "maxNumOfCandidatesReturned": 10,
    "mode": "matchPerson"
}
  1. 对于 "faceId",使用源人脸 ID。
  2. 将其他人脸 ID 作为项粘贴到 "faceIds" 数组中。

检查结果

你将收到一个 JSON 响应,它列出了与你的查询人脸匹配的面部的 ID。

[
    {
        "persistedFaceId" : "015839fb-fbd9-4f79-ace9-7675fc2f1dd9",
        "confidence" : 0.82
    },
    ...
] 

在此程序中,在这个图像中检测到的人脸应该作为与源图像人脸相似的人脸返回。

Photo of a man smiling; this is the same person as the previous image

清理资源

如果想要清理并删除认知服务订阅,可以删除资源或资源组。 删除资源组同时也会删除与之相关联的任何其他资源。

后续步骤

在本快速入门中,你已了解如何使用人脸 REST API 来执行基本人脸识别任务。 接下来,了解不同的人脸检测模型,学习如何为你的用例指定适当的模型。