[置顶] 微软认知服务开发实践(3) - 人脸识别

前言

人们对人脸识别的研究已经有很长一段时间,起初局限于获取基础的人脸信息,随着机器学习领域的发展,人脸识别的应用更加广泛,已经可以被用于人脸搜索、人脸鉴权等相关应用。本文将针对微软认知服务中提供的人脸识别API的调用方法进行一些初步的讲解。

Face API

Face API中提供了3方面功能:

  1. 人脸检测
  2. 人脸分组
  3. 人脸识别(搜索)

首先是人脸检测,主要是指传统概念上的人脸识别功能,识别图片中的人的面孔,给出人脸出现的坐标区域,并根据识别出来的人脸分析出一些基本的信息(例如年龄)。

其次是人脸分组,可以在已经预制好的若干张人脸中根据相似度进行相似度搜索或者是根据相似度进行分组或者是认证操作。

最后是人脸识别,这里的人脸识别是指,通过给定一张人脸在构建并训练完成的人脸库中搜索名称的功能。

同样,Face API在调用过程中,也有一系列的限制,如果在调用过程中确认代码逻辑没有问题的情况下,依然出错,可以检查如下几点:

  1. 图片的格式需要是JPEG、PNG、GIF(仅限第一帧)以及BMP
  2. 图片尺寸不可以大于4MB
  3. 人脸像素需要介于36x36 (px)与4096x4096 (px)之间
  4. 每张照片中最多包含64张面部信息
  5. FaceID的有效期为24小时(自生成之时起)

人脸检测(Detect)

人脸检测功能,可以识别照片中人脸的位置信息,包括脸部的范围以及脸部的各个细节的位置(眼睛、鼻子、嘴等信息),还可以识别出面部装束信息(是否有胡子等),最后还可以针对所识别出来的人脸做一些智能的分析功能,可以获取性别、年龄、是否微笑等。

首先是接口URL:

https://api.projectoxford.ai/face/v1.0/detect[?returnFaceId][&returnFaceLandmarks][&returnFaceAttributes]

URL中包含了3个参数returnFaceId、returnFaceLandmarks以及returnFaceAttributes,3个参数都是可选参数。

returnFaceId 设定是否返回FaceID,默认值是true
returnFaceLandmarks 设定是否返回详细的面部细节位置信息(包括鼻子、眼睛、嘴等),默认值是false
*returnFaceAttributes 设定进行面部智能分析(分析性别、年龄、微笑等)的项目,可设置为agegenderheadPosesmilefacialHairglasses.多个项目中间使用逗号进行分割(,

*每项分析内容都需要增加额外的计算时间。

和之前在计算机视觉中介绍的类似,微软认知服务每个API的调用,都需要在Header中包含Ocp-Apim-Subscription-Key来标示出服务订阅的Key,可以在自己的账户中找到。

这个API通过POST的方式进行调用,除了必要的之外Ocp-Apim-Subscription-Key,还可以设置Content-Type

Content-Type(可选) 设定Content-Type信息,这个是可选的,不设定会根据Post过去的数据自动识别出来,可以设定为application/jsonapplication/octet-stream

当设置为application/octet-stream时, POST中的数据直接就是Binary流。而当设置为application/json时,POST中的数据按如下格式实现,

{“url”:”http://example.com/images/test.jpg“}

最后介绍的是这个API的返回值,返回信息为一串JSON字符串。格式如下:

[
    {
        "faceId": "c5c24a82-6845-4031-9d5d-978df9175426",
        "faceRectangle": {
            "width": 78,
            "height": 78,
            "left": 394,
            "top": 54
        },
        "faceLandmarks": {
            "pupilLeft": {
                "x": 412.7,
                "y": 78.4 
            },
            "pupilRight": {
                "x": 446.8,
                "y": 74.2 
            },
            "noseTip": {
                "x": 437.7,
                "y": 92.4 
            },
            "mouthLeft": {
                "x": 417.8,
                "y": 114.4 
            },
            "mouthRight": {
                "x": 451.3,
                "y": 109.3 
            },
            "eyebrowLeftOuter": {
                "x": 397.9,
                "y": 78.5 
            },
            "eyebrowLeftInner": {
                "x": 425.4,
                "y": 70.5 
            },
            "eyeLeftOuter": {
                "x": 406.7,
                "y": 80.6 
            },
            "eyeLeftTop": {
                "x": 412.2,
                "y": 76.2 
            },
            "eyeLeftBottom": {
                "x": 413.0,
                "y": 80.1 
            },
            "eyeLeftInner": {
                "x": 418.9,
                "y": 78.0 
            },
            "eyebrowRightInner": {
                "x": 4.8,
                "y": 69.7 
            },
            "eyebrowRightOuter": {
                "x": 5.5,
                "y": 68.5 
            },
            "eyeRightInner": {
                "x": 441.5,
                "y": 75.0 
            },
            "eyeRightTop": {
                "x": 446.4,
                "y": 71.7 
            },
            "eyeRightBottom": {
                "x": 447.0,
                "y": 75.3 
            },
            "eyeRightOuter": {
                "x": 451.7,
                "y": 73.4 
            },
            "noseRootLeft": {
                "x": 428.0,
                "y": 77.1 
            },
            "noseRootRight": {
                "x": 435.8,
                "y": 75.6 
            },
            "noseLeftAlarTop": {
                "x": 428.3,
                "y": 89.7 
            },
            "noseRightAlarTop": {
                "x": 442.2,
                "y": 87.0 
            },
            "noseLeftAlarOutTip": {
                "x": 424.3,
                "y": 96.4 
            },
            "noseRightAlarOutTip": {
                "x": 446.6,
                "y": 92.5 
            },
            "upperLipTop": {
                "x": 437.6,
                "y": 105.9 
            },
            "upperLipBottom": {
                "x": 437.6,
                "y": 108.2 
            },
            "underLipTop": {
                "x": 436.8,
                "y": 111.4 
            },
            "underLipBottom": {
                "x": 437.3,
                "y": 114.5 
            }
        },
        "faceAttributes": {
            "age": 71.0,
            "gender": "male",
            "smile": 0.88,
            "facialHair": {
                "mustache": 0.8,
                "beard": 0.1,
                "sideburns": 0.02
                }
            },
            "glasses": "sunglasses",
            "headPose": {
                "roll": 2.1,
                "yaw": 3,
                "pitch": 0
            }
        }
    }
]

返回的JSON数据中,人脸的数目不一定只有一个,每一个面部信息,都将会被阻止在JSON数据中的第一层中。

每个面部信息中包含3部分,首先是FaceID,这个ID可以用于后续的一些API调用中使用(例如Verify之类的)。
其次是照片中人脸识别的结果,结果会以坐标以及范围的矩形方式给出,如果在请求的URL中指定需要获取面部细节的位置信息,还会在其中给出具体的眼睛、鼻子以及嘴部的详细坐标。
最后如果请求了高级别的智能分析功能,还会给出性别、年龄、微笑程度等信息。

同样,如果请求(或调用)API的过程中,如果其中有异常抛出,则会在Response中返回异常的详细内容,类似格式如下:

{
    "error":{
        "code":"BadArgument",
        "message":"Request body is invalid." 
    }
}

整个API的具体调用示例,C#可以参考如下:

static async void MakeRequest()
{
    var client = new HttpClient();
    var queryString = HttpUtility.ParseQueryString(string.Empty);

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

    // Request parameters
    queryString["returnFaceId"] = "true";
    queryString["returnFaceLandmarks"] = "false";
    queryString["returnFaceAttributes"] = "{string}";
    var uri = "https://api.projectoxford.ai/face/v1.0/detect?" + queryString;

    HttpResponseMessage response;

    // Request body
    byte[] byteData = Encoding.UTF8.GetBytes("{body}");

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

}

人脸分组(Group)

分组这部分其实包含了3个功能,

  1. 首先是相似度搜索,将给定的面部信息在一系列面部信息中筛选出相似度比较高的前几项
  2. 其次是自动分组,将给定的一系列面部信息中,自动的进行分组
  3. 最后是鉴权认证,给定两个面部信息项,比对是否为相同,并给出相似度的值

这3个功能,都是基于相似度来进行的,所以这里将这三种都归结到人脸分组下面。

相似度搜索

在介绍相似度搜索前,笔者将对Face List API做一些简单的说明,因为相似度搜索包含两个参数项,首先是搜索的目标,其次是一组面部信息,而这组面部信息可以由JSON数组将ID传入,也可以根据以构建好的FaceList的ID传入。所以在此需要先介绍下FaceListAPI。

Face List

FaceListAPI中包含了一系列的调用用于构建、查询、修改以及删除一个FaceList这几种操作。

List Face Lists
接口URL:

https://api.projectoxford.ai/face/v1.0/facelists

该接口用于列举出该账户下已经注册了哪些FaceList。

每个API的调用,都需要在Header中包含Ocp-Apim-Subscription-Key来标示出服务订阅的Key,可以在自己的账户中找到。

返回的JSON的格式如下:

[
    {
        "faceListId": "sample_list",
        "name": "list1",
        "userData":"User-provided data attached to the face list" 
    },
    …
]

Get a Face List
接口URL:

https://api.projectoxford.ai/face/v1.0/facelists/{faceListId}

该接口用于或许某一个FaceList的详细信息,其中的FaceListId可以通过List Face Lists接口获得。

每个API的调用,都需要在Header中包含Ocp-Apim-Subscription-Key来标示出服务订阅的Key,可以在自己的账户中找到。

返回的JSON的格式如下:

{
    "faceListId": "sample_list",
    "name": "list1",
    "userData":"User-provided data attached to the face list",
    "persistedFaces":[
        {
            "persistedFaceId":"B8D802CF-DD8F-4E61-B15C-9E6C5844CCBD",
            "userData":"User-provided data attached to the face" 
        },
        …
    ]
}

Create a Face List
PUT方式的接口URL:

https://api.projectoxford.ai/face/v1.0/facelists/{faceListId}

该接口用于在该账户下已经注册一个新的FaceList。
除了请求的URL中需要指定FaceListID之外,还需要在其POST过去的RequestBody中按如下格式指定一些信息,其中的userData可以由用于写入一些特定的数据信息。

{
    "name":"sample_list",
    "userData":"User-provided data attached to the face list" 
}

每个API的调用,都需要在Header中包含Ocp-Apim-Subscription-Key来标示出服务订阅的Key,可以在自己的账户中找到。

调用后,根据返回的ResponseCode是否为200来识别是否调用成功。

Update a Face List
UPDATE方式的接口URL:

https://api.projectoxford.ai/face/v1.0/facelists/{faceListId}

该接口用于更新在该账户下某一指定的FaceList,调用方式与Create a Face List API相同。
除了请求的URL中需要指定FaceListID之外,还需要在其POST过去的RequestBody中按如下格式指定一些信息,其中的userData可以由用于写入一些特定的数据信息。

{
    "name":"sample_list",
    "userData":"User-provided data attached to the face list" 
}

每个API的调用,都需要在Header中包含Ocp-Apim-Subscription-Key来标示出服务订阅的Key,可以在自己的账户中找到。

调用后,根据返回的ResponseCode是否为200来识别是否调用成功。

Delete a Face List
DELETE方式的接口URL:

https://api.projectoxford.ai/face/v1.0/facelists/{faceListId}

该接口用于删除在该账户下某一指定的FaceList。

每个API的调用,都需要在Header中包含Ocp-Apim-Subscription-Key来标示出服务订阅的Key,可以在自己的账户中找到。

调用后,根据返回的ResponseCode是否为200来识别是否调用成功。

Add a Face to a Face List
接口URL:

https://api.projectoxford.ai/face/v1.0/facelists/{faceListId}/persistedFaces[?userData][&targetFace]

该接口用于添加Face信息到一个FaseList中,除了请求的URL中需要指定FaceListID之外,还可以在URL中指定如下几项可选内容,

userData 在该条数据上指定一些用户数据(字符串的Tag信息)
targetFace 按照格式targetFace=left,top,width,height标记图片中面部信息的坐标, 例如argetFace=10,10,100,100。如果没有指定则代表先对图片进行面部识别后获得的唯一面部信息。

这个API通过POST的方式进行调用,除了必要的之外Ocp-Apim-Subscription-Key,还可以设置Content-Type

Content-Type(可选) 设定Content-Type信息,这个是可选的,不设定会根据Post过去的数据自动识别出来,可以设定为application/jsonapplication/octet-stream

当设置为application/octet-stream时, POST中的数据直接就是Binary流。而当设置为application/json时,POST中的数据按如下格式实现,

{“url”:”http://example.com/images/test.jpg“}

调用后,根据返回的ResponseCode是否为200来识别是否调用成功,并返回如下信息。

{
    "persistedFaceId": "B8D802CF-DD8F-4E61-B15C-9E6C5844CCBA" 
}

其中的persistedFaceId用于标记所录入的面部信息的ID。

Delete a Face from a Face List
DELETE方式的接口URL:

https://api.projectoxford.ai/face/v1.0/facelists/{faceListId}/persistedFaces/{persistedFaceId}

该接口用于删除在该账户下某一指定FaceList中某一个面部信息。需要在请求的URL中指定faceListId以及persistedFaceId。

每个API的调用,都需要在Header中包含Ocp-Apim-Subscription-Key来标示出服务订阅的Key,可以在自己的账户中找到。

调用后,根据返回的ResponseCode是否为200来识别是否调用成功。

Find Similar

相似度搜索功能,可以在给定的一组面部信息中,寻找特定的面部信息匹配的情况,并返回前若干条相似度比较高的面部信息的ID,以及匹配度,可以借此来实现面部搜索功能。

首先是接口URL:

https://api.projectoxford.ai/face/v1.0/findsimilars

该接口通过POST方式进行调用,调用时Header中需要包含Ocp-Apim-Subscription-Key来标示出服务订阅的Key。
POST请求的Body中,需要包含如下几项内容,

faceId 需要进行搜索的faceID
*faceListId 指定faceListId来设定搜索的范围
*faceIds 同构构建的faceID的数组来设定搜索的范围
maxNumOfCandidatesReturned 返回的最大条目,可以设定为1-20的值,默认值为20

*faceListId与faceIds只可以同时指定其中的一个,不可一同指定。

类似的请求的Body的格式如下:

{
    "faceId":"c5c24a82-6845-4031-9d5d-978df9175426", 
    "faceListId":"sample_list",
    "maxNumOfCandidatesReturned":10 
}

当使用faceIds来设定搜索范围时,faceIds为一个数组,使用如下格式替换faceListId,即可:

{
    "faceId":"c5c24a82-6845-4031-9d5d-978df9175426", 
        "faceIds":[
        "c5c24a82-6845-4031-9d5d-978df9175426",
        "015839fb-fbd9-4f79-ace9-7675fc2f1dd9",
        "65d083d4-9447-47d1-af30-b626144bf0fb",
        "fce92aed-d578-4d2e-8114-068f8af4492e",
        "30ea1073-cc9e-4652-b1e3-d08fb7b95315",
        "be386ab3-af91-4104-9e6d-4dae4c9fddb7",
        "fbd2a038-dbff-452c-8e79-2ee81b1aa84e",
        "b64d5e15-8257-4af2-b20a-5a750f8940e7",
        ...
    ]
    "maxNumOfCandidatesReturned":10 
}

最后使用POST的方式将其发送出去后如果没有异常发生则返回如下格式的JSON响应,

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

其中会按照相似度倒序返回符合的数据项。

人脸分组(Group)

人脸分组功能可以自动的将给定的一些列面部信息进行自动的分组,最大支持1000个面部信息的分组计算。

首先是接口URL:

https://api.projectoxford.ai/face/v1.0/group

该接口通过POST方式进行调用,调用时Header中需要包含Ocp-Apim-Subscription-Key来标示出服务订阅的Key。
POST请求的Body中,需要包含如下几项内容,

faceIds 指定用于分组的数据源的faceID数组

类似的请求的Body的格式如下:

{
    "faceIds":[
        "c5c24a82-6845-4031-9d5d-978df9175426",
        "015839fb-fbd9-4f79-ace9-7675fc2f1dd9",
        "65d083d4-9447-47d1-af30-b626144bf0fb",
        "fce92aed-d578-4d2e-8114-068f8af4492e",
        "30ea1073-cc9e-4652-b1e3-d08fb7b95315",
        "be386ab3-af91-4104-9e6d-4dae4c9fddb7",
        "fbd2a038-dbff-452c-8e79-2ee81b1aa84e",
        "b64d5e15-8257-4af2-b20a-5a750f8940e7" 
    ]
}

最后使用POST的方式将其发送出去后如果没有异常发生则返回如下格式的JSON响应,

{
    "groups": [
        [
            "c5c24a82-6845-4031-9d5d-978df9175426",
            "015839fb-fbd9-4f79-ace9-7675fc2f1dd9",
            "fce92aed-d578-4d2e-8114-068f8af4492e",
            "b64d5e15-8257-4af2-b20a-5a750f8940e7"
        ],[
            "65d083d4-9447-47d1-af30-b626144bf0fb",
            "30ea1073-cc9e-4652-b1e3-d08fb7b95315"
        ]
    ],
    "messyGroup": [
        "be386ab3-af91-4104-9e6d-4dae4c9fddb7"
    ]
}

返回的数据中包含两部分,其中第一个部分是groups,里面即使分组的结果,但是一些面部信息可能无法被安排到任何一个分组中,则会被单独的放在messyGroup中。

C#的调用示例如下:

static async void MakeRequest()
{
    var client = new HttpClient();
    var queryString = HttpUtility.ParseQueryString(string.Empty);

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

    var uri = "https://api.projectoxford.ai/face/v1.0/group?" + queryString;

    HttpResponseMessage response;

    // Request body
    byte[] byteData = Encoding.UTF8.GetBytes("{body}");

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

}

人脸认证(鉴权)(Verify)

人脸认证功能,是传入两张人脸信息,然后比对其相似度,来判断是否为同一个人。虽然也可以使用相似度搜索功能来实现,但是人脸认证功能背后的算法也许更加精确。

首先是接口URL:

https://api.projectoxford.ai/face/v1.0/verify

该接口通过POST方式进行调用,调用时Header中需要包含Ocp-Apim-Subscription-Key来标示出服务订阅的Key。
POST请求的Body中,只需要包含两个面部信息即可(faceId1、faceId2),类似的请求的Body的格式如下:

{
    "faceId1":"c5c24a82-6845-4031-9d5d-978df9175426",
    "faceId2":"015839fb-fbd9-4f79-ace9-7675fc2f1dd9" 
}

最后使用POST的方式将其发送出去后如果没有异常发生则返回如下格式的JSON响应,

{
    "isIdentical":true,
    "confidence":0.9 
}

其中isIdentical表示是否通过鉴权,confidence表示可信程度(相似度)为多少。

C#的调用示例如下:

static async void MakeRequest()
{
    var client = new HttpClient();
    var queryString = HttpUtility.ParseQueryString(string.Empty);

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

    var uri = "https://api.projectoxford.ai/face/v1.0/verify?" + queryString;

    HttpResponseMessage response;

    // Request body
    byte[] byteData = Encoding.UTF8.GetBytes("{body}");

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

}

人脸识别

人脸识别功能可以从已经制作并且训练好的PersonGroup中,根据指定面部信息来识别出特定的Person信息。简答的说就是给定一张面部的照片,可以识别出来这个人是谁,当然这个识别的范围需要预先构建并训练好。
本章节将先讲解如何构建PersonGroup并且进行训练,然后再介绍人脸识别(Identify)接口如何调用。

构建PersonGroup

人脸识别需要预先构建好PersonGroup,然后再PersonGroup中构建Person信息。
构建PersonGroup涉及到如下几个API的调用,

  1. List Person Groups
  2. Create a Person Group
  3. Update a Person Group
  4. Delete a Person Group

List Person Groups
其中List Person Groups API的接口URL为,

https://api.projectoxford.ai/face/v1.0/persongroups

返回JSON中包含目前该账户下所构建的所有PersonGroup的列表,

[
    {
        "personGroupId":"sample_group",
        "name":"group1",
        "userData":"User-provided data attached to the person group" 
    },{
        "personGroupId":"sample_group2",
        "name":"group2",
        "userData":"User-provided data attached to the person group" 
    }
]

* Create/Update/Delete a Person Group*
其中 Create/Update/Delete a Person Group API的接口URL三者相同,

https://api.projectoxford.ai/face/v1.0/persongroups/{personGroupId}
区别是,使用不同的调用方式,其中Create使用PUT调用,Update使用UPDATE调用,最后Delete使用DELETE方式进行调用。
调用过程中,除了Delete操作不需要特定的Body以外,Create、Update两种操作都需要指定PersonGroup的信息。

{
    "name":"group1",
    "userData":"user-provided data attached to the person group" 
}

调用后,根据返回的ResponseCode是否为200来识别是否调用成功。

构建Person相关操作

Person则为对应在PersonGroup中的一个单独的实例,其查询以及构建方式通PersonGroup类似,包括如下4条API,

  1. List Persons in a Person Group
  2. Create a Person
  3. Get a Person
  4. Update a Person
  5. Delete a Person

List Persons in a Person Group以及Get a Person
其中List Persons in a Person Group API的接口URL为,

https://api.projectoxford.ai/face/v1.0/persongroups/{personGroupId}/persons

而Get a Person API的接口为,

https://api.projectoxford.ai/face/v1.0/persongroups/{personGroupId}/persons/{personId}

返回JSON中包含目前该账户下所构建的所有Person的列表,其中每个Person还包括了已经录入的FaceID,
两个API的区别是,List Persons in a Person Group返回所有的而Get a Person只返回指定的。

[
    {
        "personId":"25985303-c537-4467-b41d-bdb45cd95ca1",
        "name":"Ryan",
        "userData":"User-provided data attached to the person",
        "persistedFaceIds":[
            "015839fb-fbd9-4f79-ace9-7675fc2f1dd9",
            "fce92aed-d578-4d2e-8114-068f8af4492e",
            "b64d5e15-8257-4af2-b20a-5a750f8940e7" 
        ]
    },{
        "personId":"2ae4935b-9659-44c3-977f-61fac20d0538",
        "name":"David",
        "userData":"User-provided data attached to the person",
        "faceIds":[
            "30ea1073-cc9e-4652-b1e3-d08fb7b95315",
            "fbd2a038-dbff-452c-8e79-2ee81b1aa84e" 
        ]
    }
]

* Create/Update/Delete a Person*
其中 Create/Update/Delete a Person API的接口URL相同,

https://api.projectoxford.ai/face/v1.0/persongroups/{personGroupId}/persons/{personId}
区别是,使用不同的调用方式,其中Create使用PUT调用,Update使用UPDATE调用,最后Delete使用DELETE方式进行调用。
调用过程中,除了Get以及Delete操作不需要特定的Body以外,Create、Update两种操作都需要指定PersonGroup的信息。

{
    "name":"Person1",
    "userData":"User-provided data attached to the person" 
}

调用后,根据返回的ResponseCode是否为200来识别是否调用成功。

构建PersonFace

每个Person可以预先指定若干条面部信息用于训练,可以通过如下几条API来对每个Person的Face信息进行构建,

  1. Add a Person Face to Person
  2. Update a Person Face
  3. Delete a Person Face

除Delete操作外,PersonFace API的URL接口都为,

https://api.projectoxford.ai/face/v1.0/persongroups/{personGroupId}/persons/{personId}/persistedFaces[?userData][&targetFace]

而Delete操作则是在URL中多了一项persistedFaceId而已,

https://api.projectoxford.ai/face/v1.0/persongroups/{personGroupId}/persons/{personId}/persistedFaces/{persistedFaceId}

在URL中需要指定PersonGroupId以及personId来指定当前操作的面部信息属于哪个组的那个人,在Add或者Update操作中,可以通过userData来定义一小段有关该面部信息的描述,以及通过targetFace来传入当前图片中的面部信息的位置信息,如果没有传入的话将会通过面部检测功能自动识别出当前图片中唯一的面部信息的位置。

Add以及Update以及Delete3种虽然都是用同一个URL但是调用方式不同,Add是通过PUT方式进行调用,而Update则使用过UPDATE方式调用,最后的Delete通过DELETE方式进行调用。

在Add以及Update中,Body可以是Binary的图片数据,也可以是JSON来指定来自互联网的URL的图片地址,如果使用后者则Body格式如下,

{
    "url":"http://example.com/1.jpg"
}

Add以及Update的调用结果为返回新添加的或者更新的面部信息id,
{
“persistedFaceId”: “B8D802CF-DD8F-4E61-B15C-9E6C5844CCBA”
}

而Delete操作则是以ResponseCode是否为200来识别是否调用成功。

训练PersonGroup

PersonGroup在进行构建或者修改后,需要训练后才可真正用于人脸识别操作。训练操作涉及2个API,

  1. Train Person Group
  2. Get Person Group Training Status

由于训练过程不是立刻就能完成的,并且也不一定是立刻开始执行的,所以在启动训练后需要通过查询状态来了解训练的结果。

首先是Train API的URL,该URL中只需要指定需要训练的PersonGroupId后直接调用即可,

https://api.projectoxford.ai/face/v1.0/persongroups/{personGroupId}/train

根据返回的ResponseCode是否为200来识别是否调用成功。

在启动训练后,可以通过如下URL查询其训练的状态,

https://api.projectoxford.ai/face/v1.0/persongroups/{personGroupId}/training

调用后可能返回的JSON数据包含status、createdDataTime、lastActionDateTime、message信息,其格式如下,

{
    "status":"succeeded",
    "createdDateTime": "2015-05-15T13:45:30",
    "lastActionDateTime": null,
    "message": "The operation was timeout." 
}

人脸识别(Identify)

人脸识别功能,可以在已经构建好的PersonGroup中,根据指定的照片中人脸信息,搜索出具体的某一个Person。该API可以一次请求多个Face的识别(但是最多10项)。

首先是接口URL:

https://api.projectoxford.ai/face/v1.0/identify

请求通过POST调用中,且需要在Header中包含Ocp-Apim-Subscription-Key来标示出服务订阅的Key。类似的请求Body的格式如下,

{
    "personGroupId":"sample_group",
    "faceIds":[
        "c5c24a82-6845-4031-9d5d-978df9175426",
        "65d083d4-9447-47d1-af30-b626144bf0fb" 
    ],
    "maxNumOfCandidatesReturned":1 
}

在POST过去的Body中需要包括如下几项内容,

faceIds 设定查询FaceId的数组,由于是使用数组,所以可以一次请求多个Face的识别过程,但是最多10个
personGroupId 通过设定personGroupId来指定搜索的范围
maxNumOfCandidatesReturned 设定返回候选项的数目(1到5),默认值为1

如果调用过程中未发生异常,则返回识别的结果,格式如下:

{
    [
        {
            "faceId":"c5c24a82-6845-4031-9d5d-978df9175426",
            "candidates":[
                {
                    "personId":"25985303-c537-4467-b41d-bdb45cd95ca1",
                    "confidence":0.92 
                }
            ]
        },{
            "faceId":"65d083d4-9447-47d1-af30-b626144bf0fb",
            "candidates":[
                {
                    "personId":"2ae4935b-9659-44c3-977f-61fac20d0538",
                    "confidence":0.89
                }
            ]
        }
    ]
}

其中返回的单位为具体的PersonId,可以通过GetPersionAPI来获取该Person的详细信息。

整个API的具体调用示例,C#可以参考如下:

static async void MakeRequest()
{
    var client = new HttpClient();
    var queryString = HttpUtility.ParseQueryString(string.Empty);

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

    var uri = "https://api.projectoxford.ai/face/v1.0/identify?" + queryString;

    HttpResponseMessage response;

    // Request body
    byte[] byteData = Encoding.UTF8.GetBytes("{body}");

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

}

总结

本文中对微软认知服务中的面部识别部分做了一些简单的介绍,并针对其所提供的API进行了一些调用相关的说明。微软在计算机视觉中提供的3方面功能,

  1. 人脸检测
    主要是指传统概念上的人脸识别功能,识别图片中的人的面孔,给出人脸出现的坐标区域,并根据识别出来的人脸分析出一些基本的信息(例如年龄)。
  2. 人脸分组
    可以在已经预制好的若干张人脸中根据相似度进行相似度搜索或者是根据相似度进行分组或者是认证操作。
  3. 人脸识别
    可以通过给定一张人脸在构建并训练完成的PersonGroup中搜索指定的Person的功能。

微软认知服务中提供的有关人脸相关的API,涵盖了基本的人脸识别的任务,加以具体的业务逻辑,即可简单的实现人脸搜索、人脸鉴权等相关应用。望本文能够为初接触微软认知服务人脸识别的开发者给予一定便利。

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。

Hadoop MapReduce原理及实例 - 2016-07-17 17:07:30

MapReduce是用于数据处理的一种编程模型,简单但足够强大,专门为并行处理大数据而设计。 1. 通俗理解MapReduce MapReduce的处理过程分为两个步骤:map和reduce。每个阶段的输入输出都是key-value的形式,key和value的类型可以自行指定。map阶段对切分好的数据进行并行处理,处理结果传输给reduce,由reduce函数完成最后的汇总。 例如从大量历史数据中找出往年最高气温,NCDC公开了过去每一年的所有气温等天气数据的检测,每一行记录一条观测记录,格式如下: 为了
前几天有幸参加了OpenStack Days China的两天技术峰会,集合了全球及国内顶尖的OpenStack技术专家,为我们分享了许多关于OpenStack的技术报告。 有许多人参加类似技术峰会都有这些感受: 1、一般主会场的领导和院士发言基本没有什么干货,也就是对我们实际工作没有太大帮助 2、一般讲的不错的都是公司的CEO、CTO等,但是他们都是公司商业因素占据很多,技术并不是他们实干,好像也没有什么收获 3、一般分享干货的实践者往往讲的水平一般,枯燥乏味,太干了,干的让人无法消化 当然,我觉得现如

Flume性能测试报告 - 2016-07-16 17:07:11

1. 测试环境 1.1 硬件 CPU:Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz(8核) 内存:16G 1.2 软件 Flume:1.6.0 Hadoop:2.6.0-cdh5.5.0 Kfaka:2.11-0.9.0.1 JDK:1.8.0_91-b14 64位 1.3 测试文件 文件大小:107M ,共490010条记录 1.4 Flume配置 (1)Source配置 Flume Source采用spooldir的方式,直接读取预先准备好的测试文件。 agent .
我最近研究了hive的相关技术,有点心得,这里和大家分享下。 首先我们要知道hive到底是做什么的。下面这几段文字很好的描述了hive的特性: 1.hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供完整的sql查询功能,可以将sql语句转换为MapReduce任务进行运行。其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。 2.Hive是建立在 Hadoop 上的数据仓

webSocket使用教程 - 2016-07-16 14:07:11

webSocket使用教程 Gson简介 GSON是Google开发的Java API,用于转换Java对象和Json对象 gson和其他现有java json类库最大的不同时gson需要序列化的实体类不需要使用annotation来标识需要序列化的字段,同时gson又可以 通过使用annotation来灵活配置需要序列化的字段。在Java开发中,有时需要保存一个数据结构成字符串,可能你会考虑用Json,但是当 Json字符串转换成Java对象时,转换成的是JsonObject,并不是你想要的Class类
目录 目录 前言 Openstack基金委员会 Openstack贡献者须知 注册Openstack In Launchpad 生成并上传OpenPGP密钥 生成并上传SSH公钥 Join The OpenStack Foundation 签署CLA贡献者协议 参考资料 前言 由Openstack基金委员会管理的Openstack社区,现在已经成为了全球第二大开源社区仅次于Linux社区,所以也有人将Openstack定义为下一个Linux。就从我个人角度出发,我认为Openstack和Linux不属于同
文本详细介绍了HDFS中的许多概念,对于理解Hadoop分布式文件系统很有帮助。 1. 介绍 在现代的企业环境中,单机容量往往无法存储大量数据,需要跨机器存储。统一管理分布在集群上的文件系统称为分布式文件系统。而一旦在系统中,引入网络,就不可避免地引入了所有网络编程的复杂性,例如挑战之一是如果保证在节点不可用的时候数据不丢失。 传统的网络文件系统(NFS)虽然也称为分布式文件系统,但是其存在一些限制。由于NFS中,文件是存储在单机上,因此无法提供可靠性保证,当很多客户端同时访问NFS Server时,很容
首先,在这里首先感谢台湾林智仁先生的开源工具包libsvm。使SVM算法更加普及。大家可以到下面的libsvm官网去了解相关的信息。 Libsvm官方网站- https://www.csie.ntu.edu.tw/~cjlin/libsvm/ 其次,我在使用过程中发现,先生svm_scale文件中无法将经过规约的文件输出到本地txt文件中,只能在控制台重定向,而我并不想在程序运行中打开控制台进行较为繁琐的操作。 所以我改造了svm_scale文件,实现了文件的写入,在这里可以和大家分享一下。 改造后新增参

Sqoop-1.4.5用户手册 - 2016-07-15 17:07:22

本文以 Sqoop User Guide (v1.4.5) 为主,对Sqoop-1.4.5的用户手册进行翻译,同时会结合一些实际操作中的注意事项一并写入。由于原文档很长,本文首先会以实际使用到的部分为主,逐步进行完善。 1、Introduction Sqoop是一个用于在Hadoop和关系型数据库之间流转数据的一个工具。可以使用Sqoop将数据从关系型数据库系统(RDBMS)比如MySQL或者Oracle导入到Hadoop分布式文件系统(HDFS)上,然后数据在Hadoop MapReduce上转换,以及
前言 近日在线上发现有些mapreduce作业的执行时间很长,我们需要解决这个问题。输入文件的大小是5G,采用了lzo压缩,整个集群的默认block大小是128M。本文将详细描述这次线上问题的排查过程。 现象 线上有一个脚本,为了便于展示,我将这个脚本重新copy了一份并重命名为zzz。这个脚本实际是使用Hadoop streaming运行一个mapreduce任务,在线上执行它的部分输出内容如下: 可以看到map任务划分为1个。这个执行过程十分漫长,我将中间的一些信息省略,map与reduce任务的执行