Face clustering

更新时间:
复制 MD 格式

The face clustering feature of Intelligent Media Management (IMM) allows you to cluster images that contain similar faces in a dataset. The feature is suitable for scenarios such as person albums in cloud drives, stranger detection in home surveillance, and customer management in the New Retail industry. After you perform face clustering, you can query all images that contain the face of a specific person in a cluster.

Scenarios

Person albums in cloud drives

Face clustering groups photos by face in a cloud drive and generates albums of individual persons.

Home surveillance

Face clustering records faces of family members. The face of a stranger cannot be grouped into any existing face clusters and triggers an alert. This helps you identify and handle dangerous persons and events at the earliest opportunity and ensure the safety of your family members.

Customer management in New Retail

Face clustering can be used to deduplicate photos of customers and obtain accurate customer traffic, which can be used to analyze customer purchase preferences for precise marketing.

Prerequisites

  • The metadata of images to be grouped is indexed into the corresponding dataset. You can automatically index metadata by calling the CreateBinding to bind a bucket to a dataset, or manually index metadata by calling the IndexFileMeta or BatchIndexFileMeta operation.CreateDataset

  • At least three face images of the same person that meet the following requirements are contained in the dataset:

  • The face area of an image must be greater than 75 × 75 pixels.

  • The absolute value of each of the three elements in the HeadPose parameter must be less than 30.

  • The value of the FaceQuality parameter must be greater than 0.8.

  • Note
    • You can call the GetFileMeta operation to query the head pose and face quality.

    • After a face cluster is created, faces that do not meet the preceding requirements may also be added to the same cluster. For FAQ about face clustering, see FAQ about image management.

Create a face clustering task

Call the CreateFigureClusteringTask operation to create a face clustering task to cluster faces of different persons in images by person. The following example shows how to perform face clustering on images in the test-dataset dataset.

Note

The operation generates only clusters and does not change the images.

Important

The task information is retained for seven days after the task starts. Task information cannot be obtained after the seven-day window ends. You can use one of the following methods to query task information:

Sample request

{
    "ProjectName": "test-project",
    "DatasetName": "test-dataset"
}

Sample response

{
    "TaskId": "CreateFigureClusteringTask-ba5784b8-f61e-485d-8ea0-****",
    "RequestId": "42F4F8FD-006D-0EF0-8F2A-****",
    "EventId": "140-1L5dh6eSUErqdxV1ZvJ****"
}
Note

If the response is similar to the preceding content, the face clustering task is created.

Sample code

# -*- coding: utf-8 -*-

import os
from alibabacloud_imm20200930.client import Client as imm20200930Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_imm20200930 import models as imm_20200930_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_util.client import Client as UtilClient


class Sample:
    def __init__(self):
        pass

    @staticmethod
    def create_client(
        access_key_id: str,
        access_key_secret: str,
    ) -> imm20200930Client:
        """
        Use your AccessKey ID and AccessKey secret to initialize the client. 
        @param access_key_id:
        @param access_key_secret:
        @return: Client
        @throws Exception
        """
        config = open_api_models.Config(
            access_key_id=access_key_id,
            access_key_secret=access_key_secret
        )
        # Specify the endpoint. 
        config.endpoint = f'imm.cn-beijing.aliyuncs.com'
        return imm20200930Client(config)

    @staticmethod
    def main() -> None:
        # The AccessKey pair of an Alibaba Cloud account has permissions on all API operations. Using these credentials to perform operations is a high-risk operation. We recommend that you use a RAM user to call API operations or perform routine O&M. 
        # For security reasons, we recommend that you do not embed your AccessKey pair in your project code. 
        # In this example, the AccessKey pair is obtained from the environment variables to implement identity verification for API access. For information about how to configure environment variables, visit https://www.alibabacloud.com/help/en/imm/developer-reference/configure-environment-variables. 
        imm_access_key_id = os.getenv("AccessKeyId")
        imm_access_key_secret = os.getenv("AccessKeySecret")
        # Initialize the client. 
        client = Sample.create_client(imm_access_key_id, imm_access_key_secret)
        # Construct a request. 
        create_figure_clustering_task_request = imm_20200930_models.CreateFigureClusteringTaskRequest(
            # Specify the name of the IMM project. 
            project_name='test-project',
            # Specify the name of the dataset.
            dataset_name='test-dataset'
        )
        runtime = util_models.RuntimeOptions()
        try:
            # Print the response.
            response = client.create_figure_clustering_task_with_options(
                create_figure_clustering_task_request, runtime)
            print(response.body.to_map())
        except Exception as error:
            # Print the error message if necessary. 
            UtilClient.assert_as_string(error.message)
            print(error)


if __name__ == '__main__':
    Sample.main()

Query face clusters

After a face clustering task is created, you can call the QueryFigureClusters operation to query the information about clusters, such as the number of clusters and the number of images in each cluster. The following example shows how to query the information about face clusters in the test-dataset dataset.

Sample request

{
    "ProjectName": "test-project",
    "DatasetName": "test-dataset"
}

Sample response

{
    "FigureClusters": [
        {
            "AverageAge": 27.125,
            "Cover": {
                "Addresses": [],
                "AudioCovers": [],
                "AudioStreams": [],
                "CroppingSuggestions": [],
                "Figures": [
                    {
                        "Attractive": 0.9980000257492065,
                        "Beard": "none",
                        "BeardConfidence": 0.9959999918937683,
                        "Boundary": {
                            "Height": 270,
                            "Left": 573,
                            "Top": 104,
                            "Width": 202
                        },
                        "FaceQuality": 1.0,
                        "FigureId": "d7365ab8-1378-4bec-83cb-eccad8d11e0b",
                        "FigureType": "face",
                        "Glasses": "none",
                        "GlassesConfidence": 0.9990000128746033,
                        "Hat": "none",
                        "HatConfidence": 1.0,
                        "HeadPose": {
                            "Pitch": -0.7369999885559082,
                            "Roll": 2.5399999618530273,
                            "Yaw": 9.138999938964844
                        },
                        "Mask": "none",
                        "MaskConfidence": 0.7269999980926514,
                        "Mouth": "open",
                        "MouthConfidence": 0.9959999918937683,
                        "Sharpness": 1.0
                    }
                ],
                "ImageHeight": 683,
                "ImageWidth": 1024,
                "Labels": [],
                "OCRContents": [],
                "ObjectId": "170ffdeb36cec846f4214c78a0f3a0d4b7e37d0305370216ae780f7b8c72f871",
                "Subtitles": [],
                "URI": "oss://bucket1/photos/2.jpg",
                "VideoStreams": []
            },
            "CreateTime": "2022-07-12T16:41:19.336825716+08:00",
            "DatasetName": "dataset1",
            "FaceCount": 16,
            "Gender": "female",
            "ImageCount": 16,
            "MaxAge": 30.0,
            "MinAge": 23.0,
            "ObjectId": "Cluster-7bdbcedb-bd79-42e7-a1e2-b29a48532bd6",
            "ObjectType": "figure-cluster",
            "OwnerId": "*****",
            "ProjectName": "test-project",
            "UpdateTime": "2022-09-19T17:08:59.374781532+08:00",
            "VideoCount": 0
        },
        {
            "AverageAge": 24.200000762939453,
            "Cover": {
                "Addresses": [],
                "AudioCovers": [],
                "AudioStreams": [],
                "CroppingSuggestions": [],
                "Figures": [
                    {
                        "Attractive": 0.9990000128746033,
                        "Beard": "none",
                        "BeardConfidence": 0.9990000128746033,
                        "Boundary": {
                            "Height": 266,
                            "Left": 301,
                            "Top": 218,
                            "Width": 196
                        },
                        "FaceQuality": 0.8859999775886536,
                        "FigureId": "f58bbdce-f3d1-4674-be6b-43d4b47c08e1",
                        "FigureType": "face",
                        "Glasses": "none",
                        "GlassesConfidence": 1.0,
                        "Hat": "none",
                        "HatConfidence": 1.0,
                        "HeadPose": {
                            "Pitch": 13.963000297546387,
                            "Roll": -12.21399974822998,
                            "Yaw": -6.2210001945495605
                        },
                        "Mask": "none",
                        "MaskConfidence": 0.7490000128746033,
                        "Mouth": "open",
                        "MouthConfidence": 0.9940000176429749,
                        "Sharpness": 1.0
                    }
                ],
                "ImageHeight": 1024,
                "ImageWidth": 683,
                "Labels": [],
                "OCRContents": [],
                "ObjectId": "b9c80e51aa95072413e2a0a6e5262644bc3cba14a4754f54f3fa9850c4d244f1",
                "Subtitles": [],
                "URI": "oss://bucket1/photos/11.jpg",
                "VideoStreams": []
            },
            "CreateTime": "2022-09-19T17:08:59.374932448+08:00",
            "DatasetName": "test-dataset",
            "FaceCount": 5,
            "Gender": "female",
            "ImageCount": 5,
            "MaxAge": 26.0,
            "MinAge": 22.0,
            "ObjectId": "Cluster-856be781-bf5a-46d7-8494-8d7c44f5e282",
            "ObjectType": "figure-cluster",
            "OwnerId": "*****",
            "ProjectName": "test-project",
            "UpdateTime": "2022-09-19T17:08:59.374932448+08:00",
            "VideoCount": 0
        }
    ],
    "NextToken": "",
    "TotalCount": 2,
    "RequestId": "42B3DD92-FE0D-09B7-B582-*****"
}
Note

The response shows that images that contain faces are grouped into 2 clusters: Cluster-7bdbcedb-bd79-42e7-a1e2-b29a48532bd6 that contains 16 images and Cluster-856be781-bf5a-46d7-8494-8d7c44f5e282 that contains 5 images.

Sample code

# -*- coding: utf-8 -*-

import os
from alibabacloud_imm20200930.client import Client as imm20200930Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_imm20200930 import models as imm_20200930_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_util.client import Client as UtilClient


class Sample:
    def __init__(self):
        pass

    @staticmethod
    def create_client(
        access_key_id: str,
        access_key_secret: str,
    ) -> imm20200930Client:
        """
        Use your AccessKey ID and AccessKey secret to initialize the client. 
        @param access_key_id:
        @param access_key_secret:
        @return: Client
        @throws Exception
        """
        config = open_api_models.Config(
            access_key_id=access_key_id,
            access_key_secret=access_key_secret
        )
        # Specify the endpoint. 
        config.endpoint = f'imm.cn-beijing.aliyuncs.com'
        return imm20200930Client(config)

    @staticmethod
    def main() -> None:
        # The AccessKey pair of an Alibaba Cloud account has permissions on all API operations. Using these credentials to perform operations is a high-risk operation. We recommend that you use a RAM user to call API operations or perform routine O&M. 
        # For security reasons, we recommend that you do not embed your AccessKey pair in your project code. 
        # In this example, the AccessKey pair is obtained from the environment variables to implement identity verification for API access. For information about how to configure environment variables, visit https://www.alibabacloud.com/help/en/imm/developer-reference/configure-environment-variables. 
        imm_access_key_id = os.getenv("AccessKeyId")
        imm_access_key_secret = os.getenv("AccessKeySecret")
        # Initialize the client. 
        client = Sample.create_client(imm_access_key_id, imm_access_key_secret)
        # Construct a request. 
        query_figure_clusters_request = imm_20200930_models.QueryFigureClustersRequest(
            # Specify the name of the IMM project. 
            project_name='test-project',
            # Specify the dataset name. 
            dataset_name='test-dataset'
        )
        runtime = util_models.RuntimeOptions()
        try:
            # Print the response of the API operation. 
            response = client.query_figure_clusters_with_options(query_figure_clusters_request, runtime)
            print(response.body.to_map())
        except Exception as error:
            # Print the error message if necessary. 
            UtilClient.assert_as_string(error.message)
            print(error)


if __name__ == '__main__':
    Sample.main()

Query images in a face cluster

You can call the SimpleQuery operation to query images in a specific cluster. The following example shows how to query images in the Cluster-7bdbcedb-bd79-42e7-a1e2-b29a48532bd6 cluster that belongs to the test-dataset dataset:

Sample request

{
    "ProjectName": "test-project",
    "DatasetName": "test-dataset",
    "Query": "{\"Field\": \"Figures.FigureClusterId\", \"Operation\": \"eq\", \"Value\": \"Cluster-7bdbcedb-bd79-42e7-a1e2-b29a48532bd6\"}",
    "MaxResults": 100
}

Sample responses

Note

The cluster includes many images. The following content demonstrates the information about only one image.

{
    "Aggregations": [],
    "Files": [
        {
            "Addresses": [],
            "AudioCovers": [],
            "AudioStreams": [],
            "ContentMd5": "ViAbCBHAZgNU4zvs5****==",
            "ContentType": "image/jpeg",
            "CreateTime": "2022-07-12T15:57:47.792615815+08:00",
            "CroppingSuggestions": [],
            "DatasetName": "test-dataset",
            "ETag": "\"56201B0811C0660354E33BECE4C****\"",
            "EXIF": "****",
            "Figures": [
                {
                    "FaceQuality": 1.0,
                    "FigureClusterId": "Cluster-7bdbcedb-bd79-42e7-a1e2-b29a48532bd6",
                    "FigureConfidence": 1.0,
                    "FigureId": "cd9139bf-f339-4ec2-b5fd-****",
                    "FigureType": "face",
                    "Glasses": "none",
                    "GlassesConfidence": 0.9990000128746033,
                    "Hat": "none",
                    "HatConfidence": 1.0,
                    "HeadPose": {
                        "Pitch": -0.8999999761581421,
                        "Roll": 1.1660000085830688,
                        "Yaw": 7.932000160217285
                    },
                    "Mask": "none",
                    "MaskConfidence": 0.6830000281333923,
                    "Mouth": "close",
                    "MouthConfidence": 0.7879999876022339,
                    "Sharpness": 1.0,
                    ...
                }
            ],
            "FileHash": "\"56201B0811C0660354E33BECE****\"",
            "FileModifiedTime": "2022-07-12T15:56:41+08:00",
            "Filename": "3.jpg",
            "ImageHeight": 1024,
            "ImageScore": {
                "OverallQualityScore": 0.7490000128746033
            },
            "ImageWidth": 683,
            "Labels": [
                {
                    "CentricScore": 0.8349999785423279,
                    "LabelConfidence": 1.0,
                    "LabelLevel": 2,
                    "LabelName": "\u7167\u7247\u62cd\u6444",
                    "Language": "zh-Hans",
                    "ParentLabelName": "\u827a\u672f\u54c1"
                },
                ...
            ],
            "MediaType": "image",
            "OCRContents": [],
            "OSSCRC64": "3400224321778591044",
            "OSSObjectType": "Normal",
            "OSSStorageClass": "Standard",
            "OSSTaggingCount": 0,
            "ObjectACL": "default",
            "ObjectId": "d132a61122c659f6fc1b42ecee1662aff358c7f1720027bead225****",
            "ObjectType": "file",
            "Orientation": 1,
            "OwnerId": "****",
            "ProduceTime": "2014-02-21T00:03:36+08:00",
            "ProjectName": "test-project",
            "Size": 187674,
            "Subtitles": [],
            "URI": "oss://bucket1/1.jpg",
            "UpdateTime": "2022-07-12T16:41:19.336736388+08:00",
            "VideoStreams": []
        },
        ...
    ],
    "NextToken": "",
    "RequestId": "84E4D242-8D15-0312-B976-****"
}
Note

The preceding excerpt of the response shows information about the oss://bucket1/1.jpg image in the cluster.

Sample code

# -*- coding: utf-8 -*-

import os
from alibabacloud_imm20200930.client import Client as imm20200930Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_imm20200930 import models as imm_20200930_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_util.client import Client as UtilClient


class Sample:
    def __init__(self):
        pass

    @staticmethod
    def create_client(
        access_key_id: str,
        access_key_secret: str,
    ) -> imm20200930Client:
        """
        Use your AccessKey ID and AccessKey secret to initialize the client. 
        @param access_key_id:
        @param access_key_secret:
        @return: Client
        @throws Exception
        """
        config = open_api_models.Config(
            access_key_id=access_key_id,
            access_key_secret=access_key_secret
        )
        # Specify the endpoint. 
        config.endpoint = f'imm.cn-beijing.aliyuncs.com'
        return imm20200930Client(config)

    @staticmethod
    def main() -> None:
        # The AccessKey pair of an Alibaba Cloud account has permissions on all API operations. Using these credentials to perform operations is a high-risk operation. We recommend that you use a RAM user to call API operations or perform routine O&M. 
        # For security reasons, we recommend that you do not embed your AccessKey pair in your project code. 
        # In this example, the AccessKey pair is obtained from the environment variables to implement identity verification for API access. For information about how to configure environment variables, visit https://www.alibabacloud.com/help/en/imm/developer-reference/configure-environment-variables. 
        imm_access_key_id = os.getenv("AccessKeyId")
        imm_access_key_secret = os.getenv("AccessKeySecret")
        # Initialize the client. 
        client = Sample.create_client(imm_access_key_id, imm_access_key_secret)
        # Construct a request. 
        request = imm_20200930_models.SimpleQueryRequest()
        params = {
            # Set the query conditions. 
            "Query": {"Field": "Figures.FigureClusterId", "Operation": "eq", "Value": "Cluster-7bdbcedb-bd79-42e7-a1e2-b29a48532bd6"},
            # Specify the name of the IMM project. 
            "ProjectName": "test-project",
            # Specify the dataset name. 
            "DatasetName": "test-dataset",
            # Specify that up to 100 query results can be returned. 
            "MaxResults": 100
        }
        request.from_map(params)
        runtime = util_models.RuntimeOptions()
        try:
            # Print the response of the API operation. 
            response = client.simple_query_with_options(request, runtime)
            print(response.body.to_map())
        except Exception as error:
            # Print the error message if necessary. 
            UtilClient.assert_as_string(error.message)
            print(error)


if __name__ == '__main__':
    Sample.main()

FAQ

Why do face groups fail to be created?

The failure occurs because the conditions to create face groups are not met. For accuracy of face grouping, the following conditions must be met to create face groups:

  • Images are indexed into the specified dataset by using the IndexFileMeta operation.

  • At least three face images of the same person that meet the following requirements are contained in the dataset:

    • The face size is greater than 75 × 75 pixels.

    • The absolute value of each of the three elements in the HeadPose parameter is less than 30.

    • The value of the FaceQuality parameter is greater than 0.8.

After a face group is created, faces that do not meet the preceding requirements may also be added to the same group.

How do I query the images in a face image group?

To query the images in a face image group, call the SimpleQuery operation and specify the ID of the face image group for the Query parameter.

Note

To query the ID of a face image group, call the QueryFigureClusters operation and obtain the value of ObjectId from the FigureClusters parameter in the response.

{
  "Field ": "Figures.FigureClusterId ",
  "Operation ": "eq ",
  "Value ": "Face group ID"
}

Why does a created face image group fail to be found?

Metadata indexing is asynchronous. It takes some time to index image metadata into the specified dataset, meaning that you can find the face image group only after the required time elapses . When you design the logic of your application, consider delay-related data consistency issues.

  • Image metadata indexing: The IndexFileMeta operation takes approximately 10 seconds to index images.

  • Face grouping: The CreateFigureClusteringTask operation takes up to 180 seconds to group face images. The actual time varies based on the number of images indexed at a time and is several seconds in most scenarios.

    Important

    The CreateFigureClusteringTask operation depends on the IndexFileMeta operation to achieve face detection. If you use Simple Message Queue (SMQ) to obtain the response to an IndexFileMeta request, wait for at least 10 seconds before you call the CreateFigureClusteringTask operation so that the call to the CreateFigureClusteringTask operation can obtain the latest face information.

  • After the asynchronous IndexFileMeta operation and CreateFigureClusteringTask operation are complete, wait for 10 seconds before you call the SimpleQuery operation to obtain the latest results.

Do I need to call the CreateFigureClusteringTask operation every time I index the metadata of an image?

No, you do not need to call the CreateFigureClusteringTask operation every time the metadata of an image is indexed. After you index the metadata of multiple face images, you can call the CreateFigureClusteringTask operation to perform batch clustering of the indexed face images. The following solutions are recommended:

  • Solution 1: Call the CreateFigureClusteringTask operation on each dataset at regular intervals, such as every 5 minutes.

  • Solution 2: Each time you call the IndexFileMeta operation, add the corresponding dataset to a delayed queue. Regularly obtain the value of DatasetName from the queue to query datasets that contain incremental images. Call the CreateFigureClusteringTask operation 10 seconds after your last call to the IndexFileMeta operation. This solution is recommended.

What happens if an image in a face clustering task contains faces of different persons?

If an image contains faces of different persons, each face may be added to a group. This is because face clustering is performed based on face features.

Why does the SimpleQuery operation return faces that do not belong to the specified face group?

SimpleQuery returns results at the image level. All faces and labels in an image are returned. To query face information about a face image group (a person), such as the face position, expression, and age, traverse the Figures field in all results and retrieve results in which the value of FigureClusterId is the same as that specified for FigureClusterId in your request.

Is there another way to obtain the result of the CreateFacesSearchingTask operation other than using Notification?

No, there is not another way other than Notification for obtain the result of the CreateFacesSearchingTask operation. GetTask can only queries the operation, but not the result of the operation.