顔認証のクラウドサービスMercury Cloudで遊んでみる – 顔検索 –

2021.11.04

Mercury Cloudでは顔検索をできるAPIが提供されています。

仕組みは、特徴データベースに登録されている顔特徴のデータの中からアップロードされた画像を検索し、最も近い結果を返す というものです。

特徴データベースは自身で作成する必要があり、作成後、データベースに顔特徴を追加する必要があります。作成と追加もAPIが提供されています。

やってみる

特徴データベース作成

指定された名前、説明、および最大顔特徴登録サイズで空の特徴データベースを作成します。

URL: https://{domain}/openapi/face/v1/{app_id}/databases

リクエスト例)

curl --location --request POST 'https://{domain}/openapi/face/v1/{app_id}/databases' \
--header 'x-date: Thu, 04 Nov 2021 00:59:11 GMT' \
--header 'Authorization: hmac username="{access_key}", algorithm="hmac-sha256", headers="x-date request-line", signature="wo+1Ke+Z7RI1+JHfTIuerh2bPEC4Tqy6lSJ51UVuOBQ="' \
--header 'Content-Type: application/json' \
--data-raw '{
  "name": "Sample-db",
  "description": "Sample feature database.",
  "max_size": 10
}'

最大顔特徴登録サイズを10にした場合の例です。

※ このサイズは、ご購入したサブスクリプションで許容しているID数を超えられないので、ご注意ください サイズは作成後に変更することはできません。

レスポンス例)

呼び出しが成功すると、レスポンス本文に一意の特徴データベースID(db_id)が返されます。

特徴データベースに顔特徴を登録するときにdb_idを使用することになります。

{
    "trace_id": "a517f332fe0522f5a4862b9251a5c109",
    "name": "Sample-db",
    "db_id": "91309912-cbcf-4985-be08-552363ed6000",
    "object_type": "OBJECT_FACE",
    "feature_version": 24902,
    "description": "Sample feature database.",
    "created_at": "2021-11-04T01:00:02.615515501Z",
    "max_size": 10,
    "size": 0
}

特徴データベースに画像を追加

作成したデータベースに画像をアップロードすることにより顔特徴を追加することができます(複数を一括追加可能)。

なお、画像はいっさい保存されず、顔特徴のデータのみが保存されるとのことです。

画像データはbase64でエンコードされたバイナリである必要があります

URL: https://{domain}/openapi/face/v1/{app_id}/databases/{db_id}/features

リクエスト例)

Alice

Bob

という2つを特徴データベースに追加した例です

curl --location --request POST 'https://{domain}/openapi/face/v1/{app_id}/databases/{db_id}/features' \
--header 'x-date: Thu, 04 Nov 2021 01:17:45 GMT' \
--header 'Authorization: hmac username="{access_key}", algorithm="hmac-sha256", headers="x-date request-line", signature="tMU7Ign2TndOsOPugGIf1K/+a6nrAfTGSlXce5pqV8I="' \
--header 'Content-Type: application/json' \
--data-raw '{
  "images": [
    {
      "image": {
        "data": "/9j/4AAQSkZJRgA...Tpi3Q1lZTCn//Z",
        "rectangle": {
          "top": 50,
          "left": 100,
          "width": 500,
          "height": 800
        },
        "rotate": "AUTO"
      },
      "key": "Alice",
      "extra_info": "{'\''height'\'': '\''46'\'', '\''weight'\'': '\''1362'\''}",
      "quality_threshold": 0.8
    },
    {
      "image": {
        "data": "KB2/gMyt1O0NEnY...BJRU5ErkJggg=="
      },
      "key": "Bob",
      "extra_info": "{'\''height'\'': '\''12'\'', '\''weight'\'': '\''352'\''}",
      "quality_threshold": 0.8
    }
  ]
}'

画像はリスト化して複数追加できますが、詳細パラメータは

  • image
    • data
      • base64エンコーディング形式の画像バイナリデータ
    • rectangle
      • 画像内の特定領域を検知するための長方形の座標
    • rotate
      • APIが特定の画像に含める顔の向きをチェックするかどうかと、顔検出の前に画像を回転させるかどうかを設定
        • NONE : (既定値)APIに顔の向きをチェックせず、顔検出に元の画像をそのまま使用
        • AUTO : 検出の前に顔が上向きではない場合、APIに画像を自動に回転
        • CW90 : 顔検出の前に画像を時計回りに90度回転させます。入力画像の顔が右向きの場合、この値を使用します
        • CW180 : 顔検出の前に画像を時計回りに180度回転させます。入力画像の顔が下向きの場合、この値を使用します
        • CW270 : 顔検出の前に画像を時計回りに270度回転させます。入力画像の顔が左向きの場合、この値を使用します
  • key
    • 顔特徴を特定できる最大半角48文字の英数字、ダッシュ(-)で構成されるキーを指定
    • 複数の顔特徴が同じ人物に属している場合、重複させることもできます
  • extra_info
    • 最大1024文字のユーザー定義の追加情報。JSONまたはbase64でエンコードされたバイナリの文字列も保存できます
  • quality_threshold
    • 顔品質のしきい値。検知された画像の品質がしきい値よりも低い場合、サービスはエラーを応答します

レスポンス例)

上記のリクエスト例のAliceとBobというkeyで2つの画像を登録した結果です。

呼び出しが成功すると、顔特徴一括追加結果の配列codeと一括追加された画像処理の配列featuresが返されます

{
    "trace_id": "1e97c47d8889adffce5b058a068178b4",
    "results": [
        {
            "code": 0,
            "message": "Success.",
            "internal_code": 0
        },
        {
            "code": 0,
            "message": "Success.",
            "internal_code": 0
        }
    ],
    "features": [
        {
            "feature_id": "91309912cbcf4985be08552363ed6001000000000005bc40",
            "face": {
                "quality": 0.9877943,
                "rectangle": {
                    "top": 42,
                    "left": 88,
                    "width": 72,
                    "height": 80
                },
                "angle": {
                    "yaw": -20.966906,
                    "pitch": -0.99793977,
                    "roll": -5.079045
                },
                "landmarks": [
                    {
                        "x": 86,
                        "y": 56
                    },
                    ~~~~~~~,
                    {
                        "x": 148,
                        "y": 61
                    }
                ],
                "attributes": {
                    "age_lower_limit": {
                        "type": 0,
                        "category": "age_lower_limit",
                        "value": 42
                    },
                    "age_up_limit": {
                        "type": 0,
                        "category": "age_up_limit",
                        "value": 52
                    },
                    "cap_style": {
                        "type": 2,
                        "category": "HAT_STYLE_TYPE_NONE",
                        "value": 0.99995834
                    },
                    "gender_code": {
                        "type": 2,
                        "category": "MALE",
                        "value": 0.99983203
                    },
                    "glass_style": {
                        "type": 2,
                        "category": "GLASSES_STYLE_TYPE_NONE",
                        "value": 0.9868007
                    },
                    "mustache_style": {
                        "type": 2,
                        "category": "WHISKERS",
                        "value": 0.7086664
                    },
                    "respirator_color": {
                        "type": 2,
                        "category": "COLOR_TYPE_NONE",
                        "value": 0.9984269
                    },
                    "st_age": {
                        "type": 2,
                        "category": "ST_ADULT",
                        "value": 1
                    },
                    "st_expression": {
                        "type": 2,
                        "category": "ST_HAPPY",
                        "value": 0.728775
                    },
                    "st_helmet_style": {
                        "type": 2,
                        "category": "ST_HELMET_STYLE_TYPE_NONE",
                        "value": 0.9979849
                    },
                    "st_respirator": {
                        "type": 0,
                        "category": "",
                        "value": 0
                    }
                },
                "rotated": 1
            }
        },
        {
            "feature_id": "91309912cbcf4985be08552363ed6001000000000005bc41",
            "face": {
                "quality": 0.93020684,
                "rectangle": {
                    "top": 58,
                    "left": 87,
                    "width": 55,
                    "height": 55
                },
                "angle": {
                    "yaw": 2.292406,
                    "pitch": 4.962429,
                    "roll": -3.2841737
                },
                "landmarks": [
                    {
                        "x": 88,
                        "y": 70
                    },
                    ~~~~~~~,
                    {
                        "x": 126,
                        "y": 71
                    }
                ],
                "attributes": {
                    "age_lower_limit": {
                        "type": 0,
                        "category": "age_lower_limit",
                        "value": 24
                    },
                    "age_up_limit": {
                        "type": 0,
                        "category": "age_up_limit",
                        "value": 34
                    },
                    "cap_style": {
                        "type": 2,
                        "category": "HAT_STYLE_TYPE_NONE",
                        "value": 0.99999505
                    },
                    "gender_code": {
                        "type": 2,
                        "category": "MALE",
                        "value": 0.9999505
                    },
                    "glass_style": {
                        "type": 2,
                        "category": "GLASSES_STYLE_TYPE_NONE",
                        "value": 0.9988936
                    },
                    "mustache_style": {
                        "type": 2,
                        "category": "MUSTACHE_STYLE_TYPE_NONE",
                        "value": 0.98819935
                    },
                    "respirator_color": {
                        "type": 2,
                        "category": "COLOR_TYPE_NONE",
                        "value": 0.9999145
                    },
                    "st_age": {
                        "type": 2,
                        "category": "ST_ADULT",
                        "value": 1
                    },
                    "st_expression": {
                        "type": 2,
                        "category": "ST_CALM",
                        "value": 0.9982281
                    },
                    "st_helmet_style": {
                        "type": 2,
                        "category": "ST_HELMET_STYLE_TYPE_NONE",
                        "value": 0.9999406
                    },
                    "st_respirator": {
                        "type": 0,
                        "category": "",
                        "value": 0
                    }
                },
                "rotated": 1
            }
        }
    ]
}

顔特徴を追加するときは、前回の記事で試した品質チェックを行うことが推奨されています。画質が高いほど認識精度が高くなるためです。

顔検索

特徴データベースに追加した顔特徴を使って検索してみます。

顔検索APIは画像をアップロードし、検証スコアの結果に基づいて特徴データベース内の上位K個の類似した顔特徴を検索します。

指定された顔画像で、1つまたは複数の特徴データベースから類似した顔特徴を検索してくれます。

URL: https://{domain}/openapi/face/v1//{app_id}/databases/search

リクエスト例)

上記の画像をデータベースから検索してみました。 これはAliceの別画像です。

curl --location --request POST 'https://{domain}/openapi/face/v1/{app_id}/databases/search' \
--header 'x-date: Thu, 04 Nov 2021 01:56:01 GMT' \
--header 'Authorization: hmac username="{access_key}", algorithm="hmac-sha256", headers="x-date request-line", signature="cyVFwgrp1gPnWDyvPV9LcqkBY83BKPt2JMVzKZ394Lg="' \
--header 'Content-Type: application/json' \
--data-raw '{
  "image": {
    "data": "iVBORw0KGgoA~~~~~~~~~"
  },
  "db_ids": [
    "91309912-cbcf-4985-be08-552363ed6000"
  ],
  "top_k": 1,
  "min_score": 0.9
}'

top_k は  db_idsで指定された各特徴データベースの上位K個の類似検索結果を、[1、1024]の範囲で指定します。

min_score は 各特徴データベースで顔検索するときの最小スコアを、[0、1]の範囲で指定します。

レスポンス例)

特徴データベースで近似するものが見つかった場合、APIの応答には上位K件の結果が含まれます。

以下の例は、アップロードした画像が 91309912-cbcf-4985-be08-552363ed6000 というデータベースIDで見つかった例です。

{
    "trace_id": "5505a3307ed6c12f32c74b38cdc063b5",
    "results": [
        {
            "code": 0,
            "message": "Success.",
            "internal_code": 0
        }
    ],
    "batches": [
        {
            "db_id": "91309912-cbcf-4985-be08-552363ed6000",
            "features": [
                {
                    "score": 0.98156124,
                    "feature": {
                        "feature_id": "91309912cbcf4985be08552363ed6001000000000005bc40",
                        "key": "Alice",
                        "extra_info": ""
                    }
                }
            ]
        }
    ],
    "face": {
        "quality": 0.9874657,
        "rectangle": {
            "top": 82,
            "left": 32,
            "width": 83,
            "height": 86
        },
        "angle": {
            "yaw": -30.417383,
            "pitch": -1.8922046,
            "roll": -9.593876
        },
        "landmarks": [
            {
                "x": 35,
                "y": 87
            },
            ~~~~~~~~,
            {
                "x": 109,
                "y": 101
            }
        ],
        "attributes": {
            "age_lower_limit": {
                "type": 0,
                "category": "age_lower_limit",
                "value": 42
            },
            "age_up_limit": {
                "type": 0,
                "category": "age_up_limit",
                "value": 52
            },
            "cap_style": {
                "type": 2,
                "category": "HAT_STYLE_TYPE_NONE",
                "value": 0.99999493
            },
            "gender_code": {
                "type": 2,
                "category": "MALE",
                "value": 0.9999234
            },
            "glass_style": {
                "type": 2,
                "category": "GLASSES_STYLE_TYPE_NONE",
                "value": 0.9956901
            },
            "mustache_style": {
                "type": 2,
                "category": "MUSTACHE_STYLE_TYPE_NONE",
                "value": 0.91528034
            },
            "respirator_color": {
                "type": 2,
                "category": "COLOR_TYPE_NONE",
                "value": 0.99770385
            },
            "st_age": {
                "type": 2,
                "category": "ST_ADULT",
                "value": 1
            },
            "st_expression": {
                "type": 2,
                "category": "ST_CALM",
                "value": 0.99736077
            },
            "st_helmet_style": {
                "type": 2,
                "category": "ST_HELMET_STYLE_TYPE_NONE",
                "value": 0.99945897
            },
            "st_respirator": {
                "type": 0,
                "category": "",
                "value": 0
            }
        },
        "rotated": 1
    }
}

batchesというkeyを見ると、

ヒットした db_id, 検索された画像とこのオブジェクトの'feature'フィールドとの類似スコアを示すscore, 顔特徴のidであるfeature_id, 顔特徴を特定できるkeyなどが含まれています。

期待通りAliceの特徴がヒットして返ってきましたね。

最後に

Mercury CloudのAPIを使って顔特徴のデータベースの作成、顔特徴の追加、そして顔の検索を行ってみました。

1:Nの顔検索でもAPIでコアな部分を行ってくれるので、複雑な開発は不要なのではないでしょうか。

一つ注意点として挙げられていたものですが、

今後、新しい顔認証のモデルが提供された場合、それを使って検索するには顔特徴は元の画像を使って再度抽出する必要が出てきます。 Mercury Cloudは画像を保存しないので、基幹業務では別の方法で画像を保存しておく方が良いとのことです。