Todos los productos
Search
Centro de documentos

Intelligent Media Management:Face clustering

Última actualización: Sep 05, 2026

La agrupación de rostros organiza en conjuntos las imágenes que contienen caras similares dentro de un dataset. Cada clúster representa a una persona distinta, lo que permite localizar todas las fotografías de un individuo específico a partir de un solo grupo.

Casos de uso comunes:

  • Álbumes faciales en unidades de nube: organización automática de fotos por persona para generar álbumes personalizados.

  • Videovigilancia residencial: registro de los rostros de los miembros de la familia. Si aparece una cara desconocida, el sistema no logra asignarla a un clúster existente y envía una alerta. Esto facilita la identificación temprana de personas o situaciones de riesgo y ayuda a garantizar la seguridad de su hogar.

  • Gestión de clientes en retail: deduplicación de imágenes de clientes para obtener conteos precisos de tráfico y análisis del comportamiento de compra orientados a campañas de marketing dirigidas.

Funcionamiento

La agrupación de rostros sigue un flujo de trabajo de API de tres pasos:

1. Index images         CreateBinding, IndexFileMeta, or BatchIndexFileMeta
        |
        v
2. Cluster faces        CreateFigureClusteringTask
        |
        v
3. Query results        QueryFigureClusters  -->  SimpleQuery (images per cluster)
  1. Indexar imágenes en un dataset. Utilice CreateBinding para la vinculación automática, o bien IndexFileMeta / BatchIndexFileMeta para la indexación manual. Cree el dataset con CreateDataset.

  2. Ejecutar la agrupación de rostros. Llame a CreateFigureClusteringTask para agrupar las caras del dataset. Esta operación es incremental, ya que solo procesa las imágenes nuevas desde la última ejecución.

  3. Consultar clústeres e imágenes. Use QueryFigureClusters para listar todos los clústeres y, posteriormente, emplee SimpleQuery para recuperar todas las imágenes de un clúster específico.

Requisitos previos

Antes de empezar, asegúrese de que:

  • Las imágenes estén indexadas en un dataset mediante CreateBinding, IndexFileMeta o BatchIndexFileMeta

  • El dataset contenga como mínimo 3 imágenes de la misma persona

  • Al menos 3 de dichas imágenes cumplan con los requisitos de rostro en alta definición que se enumeran a continuación

Requisitos para rostros en alta definición

Criterio

Umbral

Área del rostro

Mayor que 75 x 75 píxeles

HeadPose

Valor absoluto de cada elemento (Pitch, Roll, Yaw) menor que 30

FaceQuality

Mayor que 0.8

Nota

Llame a GetFileMeta para comprobar los valores de ángulo y calidad facial de las imágenes indexadas.

Una vez creado un clúster, es posible que se añadan al mismo grupo rostros que no alcancen estos umbrales. Para más detalles, consulte Preguntas frecuentes sobre gestión de imágenes.

Creación de una tarea de agrupación de rostros

Llame a CreateFigureClusteringTask para agrupar los rostros de las imágenes indexadas en un dataset. Esta operación únicamente genera clústeres y no modifica las imágenes originales.

Importante

La información de la tarea se conserva durante 7 días después de su inicio. Pasado ese periodo, los datos dejan de estar disponibles. Utilice uno de los siguientes métodos para recuperar los resultados:

Ejemplo de solicitud

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

Ejemplo de respuesta

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

Una respuesta exitosa incluye un TaskId que confirma la creación de la tarea de agrupación.

Código de ejemplo (Python)

# -*- 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:
        """
        Initialize the IMM client with an AccessKey pair.
        @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
        )
        # Set the endpoint. Replace cn-beijing with your region.
        config.endpoint = f'imm.cn-beijing.aliyuncs.com'
        return imm20200930Client(config)

    @staticmethod
    def main() -> None:
        # Read AccessKey pair from environment variables.
        # Use a RAM user instead of the Alibaba Cloud account for security.
        # For details, see https://www.alibabacloud.com/help/document_detail/2361894.html
        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)
        # Build the clustering request.
        create_figure_clustering_task_request = imm_20200930_models.CreateFigureClusteringTaskRequest(
            # IMM project name
            project_name='test-project',
            # Dataset name
            dataset_name='test-dataset'
        )
        runtime = util_models.RuntimeOptions()
        try:
            response = client.create_figure_clustering_task_with_options(
                create_figure_clustering_task_request, runtime)
            print(response.body.to_map())
        except Exception as error:
            UtilClient.assert_as_string(error.message)
            print(error)

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

Consulta de clústeres de rostros

Una vez finalizada la agrupación, llame a QueryFigureClusters para listar todos los clústeres de un dataset. La respuesta incluye los siguientes metadatos para cada clúster:

Campo

Descripción

ObjectId

ID del clúster

FaceCount

Número de rostros en el clúster

ImageCount

Número de imágenes en el clúster

Gender

Género estimado

AverageAge, MinAge, MaxAge

Estadísticas de edad

Cover

Imagen de portada con atributos faciales detallados

Ejemplo de solicitud

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

Ejemplo de respuesta

{
    "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-*****"
}

En este ejemplo, el dataset contiene 2 clústeres. El clúster Cluster-7bdbcedb-bd79-42e7-a1e2-b29a48532bd6 incluye 16 imágenes, mientras que el clúster Cluster-856be781-bf5a-46d7-8494-8d7c44f5e282 contiene 5 imágenes.

Código de ejemplo (Python)

# -*- 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:
        """
        Initialize the IMM client with an AccessKey pair.
        @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
        )
        # Set the endpoint. Replace cn-beijing with your region.
        config.endpoint = f'imm.cn-beijing.aliyuncs.com'
        return imm20200930Client(config)

    @staticmethod
    def main() -> None:
        # Read AccessKey pair from environment variables.
        # Use a RAM user instead of the Alibaba Cloud account for security.
        # For details, see https://www.alibabacloud.com/help/document_detail/2361894.html
        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)
        # Build the query request.
        query_figure_clusters_request = imm_20200930_models.QueryFigureClustersRequest(
            # IMM project name
            project_name='test-project',
            # Dataset name
            dataset_name='test-dataset'
        )
        runtime = util_models.RuntimeOptions()
        try:
            response = client.query_figure_clusters_with_options(query_figure_clusters_request, runtime)
            print(response.body.to_map())
        except Exception as error:
            UtilClient.assert_as_string(error.message)
            print(error)

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

Consulta de imágenes en un clúster

Después de obtener la información de los clústeres, llame a SimpleQuery con el ID del clúster para listar todas sus imágenes. El siguiente ejemplo recupera las imágenes del clúster Cluster-7bdbcedb-bd79-42e7-a1e2-b29a48532bd6.

Ejemplo de solicitud

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

Ejemplo de respuesta

Nota

El clúster contiene numerosas imágenes. El siguiente ejemplo muestra los datos correspondientes a una sola imagen.

{
    "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-****"
}

Este resultado indica que el clúster incluye una imagen ubicada en oss://bucket1/1.jpg.

Código de ejemplo (Python)

# -*- 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:
        """
        Initialize the IMM client with an AccessKey pair.
        @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
        )
        # Set the endpoint. Replace cn-beijing with your region.
        config.endpoint = f'imm.cn-beijing.aliyuncs.com'
        return imm20200930Client(config)

    @staticmethod
    def main() -> None:
        # Read AccessKey pair from environment variables.
        # Use a RAM user instead of the Alibaba Cloud account for security.
        # For details, see https://www.alibabacloud.com/help/document_detail/2361894.html
        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)
        # Build the query request.
        request = imm_20200930_models.SimpleQueryRequest()
        params = {
            # Filter by cluster ID
            "Query": {"Field": "Figures.FigureClusterId", "Operation": "eq", "Value": "Cluster-7bdbcedb-bd79-42e7-a1e2-b29a48532bd6"},
            # IMM project name
            "ProjectName": "test-project",
            # Dataset name
            "DatasetName": "test-dataset",
            # Return up to 100 results
            "MaxResults": 100
        }
        request.from_map(params)
        runtime = util_models.RuntimeOptions()
        try:
            response = client.simple_query_with_options(request, runtime)
            print(response.body.to_map())
        except Exception as error:
            UtilClient.assert_as_string(error.message)
            print(error)

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

Mejores prácticas

Selección de la frecuencia de agrupación

CreateFigureClusteringTask es una operación incremental, por lo que no es necesario llamarla después de indexar cada imagen. Se recomiendan dos enfoques:

Enfoque

Funcionamiento

Cuándo utilizarlo

Sondeo programado

Llamar a CreateFigureClusteringTask en cada dataset a intervalos regulares (por ejemplo, cada 5 minutos).

Configuraciones sencillas con bajo volumen de indexación

Basado en eventos con cola de retardo (recomendado)

Cada vez que se llama a IndexFileMeta, insertar el DatasetName en una cola de retardo. Recuperar periódicamente los nombres de los datasets y ejecutar CreateFigureClusteringTask al menos 10 segundos después de la última llamada a IndexFileMeta para dicho dataset.

Entornos de producción con indexación frecuente

Consideración de la latencia asíncrona

La indexación de metadatos es asíncrona. Diseñe la lógica de su aplicación tomando en cuenta estos retrasos típicos:

Operación

Latencia típica

IndexFileMeta

~10 segundos

CreateFigureClusteringTask

Hasta 180 segundos (generalmente unos pocos segundos)

SimpleQuery (después de operaciones asíncronas)

Esperar al menos 10 segundos tras la finalización

Importante

CreateFigureClusteringTask depende de IndexFileMeta para detectar rostros. Si se suscribe a los resultados de IndexFileMeta mediante Simple Message Queue (formerly MNS), espere al menos 10 segundos después de que finalice IndexFileMeta antes de llamar a CreateFigureClusteringTask. De esta forma se asegura de que la información facial más reciente esté disponible.

Preguntas frecuentes

¿Por qué la agrupación de rostros no genera ningún clúster?

El dataset no cumple con los requisitos mínimos. Debe haber al menos 3 imágenes de la misma persona y, de ellas, como mínimo 3 deben tener:

  • Un área facial mayor que 75 x 75 píxeles

  • Valores de HeadPose (Pitch, Roll, Yaw) con un valor absoluto menor que 30 cada uno

  • FaceQuality mayor que 0.8

Una vez creado un clúster, es posible que se añadan rostros adicionales que no cumplan con estos umbrales.

¿Cómo obtengo el ID del clúster?

Llame a QueryFigureClusters y revise el campo ObjectId dentro de cada entrada del arreglo FigureClusters.

¿Cómo consulto las imágenes de un clúster específico?

Llame a SimpleQuery con el siguiente parámetro Query y reemplace el ID del clúster con el valor obtenido de QueryFigureClusters:

{
    "Field": "Figures.FigureClusterId",
    "Operation": "eq",
    "Value": "Cluster-7bdbcedb-bd79-42e7-a1e2-b29a48532bd6"
}

¿Por qué los clústeres generados no se pueden buscar de inmediato?

La indexación y la agrupación son procesos asíncronos. Después de que finalicen IndexFileMeta y CreateFigureClusteringTask, espere al menos 10 segundos antes de consultar los resultados con SimpleQuery.

¿Cómo se manejan las imágenes con múltiples rostros?

Cada rostro de una imagen se evalúa de forma independiente. Si una imagen contiene varias caras, cada una puede asignarse a un clúster diferente según sus características.

¿Por qué SimpleQuery devuelve rostros de otros clústeres al filtrar por FigureClusterId?

SimpleQuery devuelve resultados a nivel de imagen, por lo que se incluyen todos los rostros y etiquetas de una imagen coincidente. Para encontrar el rostro específico que pertenece al clúster, itere sobre el arreglo Figures en cada resultado y compare el valor de FigureClusterId. Esto proporciona la posición, expresión, edad y otros atributos del rostro correspondiente.

¿Cómo obtengo resultados de CreateFacesSearchingTask sin configurar notificaciones?

La operación CreateFacesSearchingTask devuelve resultados únicamente a través de canales de notificación (Simple Message Queue, ApsaraMQ for RocketMQ o EventBridge). GetTask recupera información sobre el estado de la tarea, pero no incluye los resultados de la búsqueda.

Operaciones relacionadas

Operación

Descripción

CreateDataset

Crear un dataset

CreateBinding

Vincular un origen de datos de OSS a un dataset para indexación automática

IndexFileMeta

Indexar metadatos de archivos en un dataset

BatchIndexFileMeta

Indexar metadatos de archivos por lotes

CreateFigureClusteringTask

Crear una tarea de agrupación de rostros

QueryFigureClusters

Consultar todos los clústeres de rostros en un dataset

SimpleQuery

Consultar archivos según condiciones (por ejemplo, filtrar por ID de clúster)

GetFileMeta

Obtener metadatos de archivos, incluida la calidad y el ángulo facial

GetTask

Obtener el estado y la información de una tarea

ListTasks

Listar tareas en un proyecto