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

安稳与你 提交于 2021-01-01 09:22:24

问题


Problem Background:

I have created an Azure FaceList and I am using my webcam to capture live feed and:

  1. sending the stream to Azure Face Detect
  2. getting Face Rectangle returned by Face Detect
  3. using the returned Face rectangle to add Face Detected from Live Video Stream to my FaceList.

(I need to create Face List in order to solve the problem I explained in my other question which is answered by Nicolas, which is what I am following)

Problem Details:

According to Azure FaceList documentation at https://docs.microsoft.com/en-us/rest/api/cognitiveservices/face/facelist/addfacefromstream ,if there are multiple faces in the image, we need to specify the target Face to add to Azure FaceList.

The Problem is, What if we need to add all the detected faces (multiple faces) in Face List? Suppose there are 2 or more faces in a single frame of video, then how can I add those two Faces to Face List?

I have tried adding the face rectangles returned from Azure Face Detect into a Python List and then iterating Over List indexes, so that each face Rectangle can be passed to Azure FaceList one-by-one. But no use.

Still getting the error:

There are more than one faces in the image

My Code:

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))

From my utils file, code for function facelist_add is as follows:

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

回答1:


When you have several faces in a picture, you have to provide a 'targetFace' in your call to AddFace:

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.

See API documentation for this method: https://westeurope.dev.cognitive.microsoft.com/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395250




回答2:


Thanks to everyone who helped and especially Nicolas R. I just found a mistake and corrected it. Now the program is working like Charm.

Actually, Azure 'Face Detect' returns face Rectangle in top,left,width,height sequence which I was feeding directly to the faceList's targetFace.

Now I just swapped the first two values of Face Rectangle and it becomes left,top,width,height which is what the documentation says, and it's working fine now.

Solution:

I have added a new function that takes the faceRectangle dictionary and swap first two values.

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)

In order to extract values from list, I did following:

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

Request to facelist_add function:

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

I have also changed my facelist_add function a little bit:

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


来源:https://stackoverflow.com/questions/65412610/cognitive-services-how-to-add-multiple-faces-from-a-live-stream-to-azure-facel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!