认知服务 - 如何将实时流中的多张面孔添加到 Azure FaceList? (Python)

Cognitive Services - How to add multiple Faces from a Live Stream to Azure FaceList ? (Python)

问题背景:

我已经创建了一个 Azure FaceList,我正在使用我的网络摄像头捕捉实时动态并且:

  1. 正在将流发送到 Azure 人脸检测
  2. 获取人脸检测
  3. 返回的人脸矩形
  4. 使用返回的人脸矩形将从实时视频流中检测到的人脸添加到我的人脸列表中。

(我需要创建面部列表以解决我在另一个问题 中解释的问题,这就是我正在关注的问题)

问题详情:

根据 https://docs.microsoft.com/en-us/rest/api/cognitiveservices/face/facelist/addfacefromstream 的 Azure FaceList 文档,如果图像中有多个面孔,我们需要指定要添加到 Azure FaceList 的目标面孔。

问题是,如果我们需要将所有检测到的人脸(多张人脸)添加到人脸列表中怎么办?假设一帧视频中有2张或更多张人脸,那么如何将这两张人脸添加到人脸列表中?

我尝试将从 Azure Face Detect 返回的人脸矩形添加到 Python 列表中,然后遍历列表索引,以便可以传递每个人脸矩形到 Azure FaceList 一个一个。但是没用。

仍然收到错误:

There are more than one faces in the image

我的代码:

face_list_id = "newtest-face-list"
vid = cv2.VideoCapture(0)


count = 0


face_ids_live_Detected = []  #This list will store faceIds from detected faces
list_of_face_rectangles = []
face_rect_counter=0

while True:
        ret, frame = vid.read()
        check,buffer = cv2.imencode('.jpg', frame)
        img = cv2.imencode('.jpg', frame)[1].tobytes()
        base64_encoded = base64.b64encode(buffer).decode()
        print(type(img))
        detected_faces = utils.detect_face_stream(endpoint=ENDPOINT, key=KEY, image=img,face_attributes=attributes,recognition_model='recognition_03')
        print('Image num {} face detected {}'.format(count, detected_faces))
        count += 1
        color = (255, 0, 0)
        thickness = 2

        for face in detected_faces:
        
            detected_face_id = face['faceId']
            face_ids_live_Detected.append(detected_face_id)
            

            detected_face_rectangle = face['faceRectangle']
            list_of_face_rectangles.append(detected_face_rectangle)
            print("detected rectangle =",detected_face_rectangle)

            face_rect_for_facelist = list_of_face_rectangles[face_rect_counter]
            face_rect_counter +=1

       frame = cv2.rectangle(frame, *utils.get_rectangle(face), color, thickness)
       cv2.imshow('frame', frame)

       for face_id_live in face_ids_live_Detected:
                        similar_faces = face_client.face.find_similar(face_id=face_id_live, face_list_id=face_list_id)                
                        if not similar_faces:
                                print('No similar faces found !')
                                print('Adding Unknown Face to FaceList...')
                                facelist_result = utils.facelist_add(endpoint=ENDPOINT, key=KEY, face_list_id=face_list_id,data=img,params=face_rect_for_facelist)
                                persisted_face_id = facelist_result['persistedFaceId']
                        else:
                                print('Similar Face Found!')
                                for similar_face in similar_faces:
                                        face_id_similar = similar_face.face_id
                                        print("Confidence: "+str(similar_face.confidence))

从我的utils文件中,函数facelist_add的代码如下:

def facelist_add(endpoint, key, face_list_id, data=None, json=None, headers=None,params=None, targetFace=None):
    # pylint: disable=too-many-arguments
    """Universal interface for request."""
    method = 'POST'
    url = endpoint + '/face/v1.0/facelists/'+face_list_id+'/persistedfaces'

    # Make it possible to call only with short name (without BaseUrl).
    if not url.startswith('https://'):
        url = BaseUrl.get() + url

    params={}

    # Setup the headers with default Content-Type and Subscription Key.
    headers = headers or {}
    if 'Content-Type' not in headers:
        headers['Content-Type'] = 'application/octet-stream'
    headers['Ocp-Apim-Subscription-Key'] = key


    params['detectionModel']='detection_03'
    

    response = requests.request(
        method,
        url,
        params=params,
        data=data,
        json=json,
        headers=headers)

    if response.text:
         result = response.json()
    else:
         result = {}

    return result

当一张图片中有多张脸时,您必须在调用 AddFace 时提供 'targetFace':

A face rectangle to specify the target face to be added into the face list, in the format of "targetFace=left,top,width,height". E.g. "targetFace=10,10,100,100". If there is more than one face in the image, targetFace is required to specify which face to add. No targetFace means there is only one face detected in the entire image.

请参阅 API 文档了解此方法:https://westeurope.dev.cognitive.microsoft.com/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395250

感谢所有提供帮助的人,尤其是 Nicolas R。我刚刚发现一个错误并更正了它。现在该程序运行正常。

实际上,Azure 'Face Detect' returns 面对 top,left,width,height 序列中的矩形,我将其直接提供给 faceList 的 targetFace。

现在我只是交换了 Face Rectangle 的前两个值,它变成了 left,top,width,height 这就是文档说,现在工作正常。

解法:

我添加了一个新函数,它接受 faceRectangle 字典并交换前两个值。

list_of_faceRect_valuesonly=[]

def face_rect_values(faceRect_dict):
        temp_list=[]
        for key,value in faceRect_dict.items():
                temp_list.append(value)
        temp_list[0], temp_list[1] = temp_list[1], temp_list[0]
        list_of_faceRect_valuesonly.append(temp_list)

为了从列表中提取值,我做了以下操作:

face_rect_counter=0
face_rect_for_facelist = list_of_faceRect_valuesonly[face_rect_counter]
face_rect_counter +=1

请求facelist_add函数:

facelist_result = utils.facelist_add(endpoint=ENDPOINT, key=KEY, face_list_id=face_list_id,targetFace=face_rect_for_facelist,data=img)

我也稍微改变了我的facelist_add功能:

def facelist_add(endpoint, key, face_list_id, targetFace=[],data=None ,jsondata=None, headers=None):
    # pylint: disable=too-many-arguments
    """Universal interface for request."""
    method = 'POST'
    url = endpoint + '/face/v1.0/facelists/'+face_list_id+'/persistedfaces'

    # Make it possible to call only with short name (without BaseUrl).
    if not url.startswith('https://'):
        url = BaseUrl.get() + url

    params={}
    

    # Setup the headers with default Content-Type and Subscription Key.
    headers = headers or {}
    if 'Content-Type' not in headers:
        headers['Content-Type'] = 'application/octet-stream'
    headers['Ocp-Apim-Subscription-Key'] = key

    list_of_targetfaces  =[]
    list_of_targetfaces.append(targetFace)


    params={'targetFace':json.dumps(targetFace)}
    params = {'targetFace': ','.join(map(str,targetFace))}

    print("Printing TargetFaces(facelist_add function) ...",params['targetFace'])
    

    params['detectionModel']='detection_03'


    url=url + "?"


    response = requests.post(url,params=params,data=data,headers=headers)
    


    print("Request URL: ", response.url)

    result = None

    # Prevent `response.json()` complains about empty response.
    if response.text:
        result = response.json()
    else:
        result = {}

    return result