amazon-web-servicesamazon-rekognition

Amazon Face Rekognition bounding box coordinates always same


I've been using Rekognition with the Amazon AWS service to try out a facial recognition workflow. The facial recognition is working well as it only detects it in images with the faces it is supposed to recognise. I have been trying to have a bounding box overlayed on the image when a face is recognised. The problem is that I have been trying it with different images and it always shows a rectangle in the middle of the frame. First I thought it was an error calculating the bounding box but it seems it is always giving me the same coordinates for the bounding box. Attached you can find 2 images displaying the error (red frame is where it draws the bounding box, green is where the face is). The image size is right and the calculations as well.

The problem is that, in all the images it detects the face it is giving me the same bounding box coordinates (same place and size) even when very different positions of a face.

Any idea where the issue may lay?

Here is the code I have been using:

import boto3
import io
import os
from PIL import Image, ImageDraw, ImageFont

rekognition = boto3.client('rekognition', region_name='*region*')
dynamodb = boto3.client('dynamodb', region_name='*region*')

# Folder paths
image_folder = "*input*"
results_folder = "*output*"

# Create the results folder if it doesn't exist
if not os.path.exists(results_folder):
    os.makedirs(results_folder)

# Iterate through each image in the folder
for image_filename in os.listdir(image_folder):
    if image_filename.lower().endswith(('.jpg', '.jpeg', '.png')):
        image_path = os.path.join(image_folder, image_filename)
        
        image = Image.open(image_path)
        draw = ImageDraw.Draw(image)
        font = ImageFont.load_default()  # You can also use a specific font if desired
        
        stream = io.BytesIO()
        image.save(stream, format="JPEG")
        image_binary = stream.getvalue()
        
        response = rekognition.search_faces_by_image(
            CollectionId='*collectionID*',
            Image={'Bytes': image_binary}
        )
        
        for match in response['FaceMatches']:
            print("Processing match:", match['Face']['FaceId'])
            face = dynamodb.get_item(
                TableName='*TableName*',  
                Key={'RekognitionId': {'S': match['Face']['FaceId']}}
            )
            
            if 'Item' in face:
                box = match['Face']['BoundingBox']
                img_width, img_height = image.size
                left = img_width * box['Left']
                top = img_height * box['Top']
                width = img_width * box['Width']
                height = img_height * box['Height']
                print("Bounding Box:", box)
                print("Image Size:", image.size)
                print("Calculated Coordinates:", left, top, width, height)

                # Display calculated coordinates on the image
                draw.text((10, 10), f"Calculated: ({left:.0f}, {top:.0f}, {width:.0f}, {height:.0f})", fill='red', font=font)

                # Draw green rectangle around recognized face
                rectangle_coords = [left, top, left + width, top + height]
                draw.rectangle(rectangle_coords, outline='#00d400', width=2)
                
                # Display name at the bottom
                text = face['Item']['FullName']['S']
                text_width, text_height = draw.textsize(text, font)
                draw.text((left, top + height), text, fill='green', font=font)

        # Save the modified image in the results folder
        result_image_path = os.path.join(results_folder, "result_" + image_filename)
        image.save(result_image_path)
        print("Modified image saved as:", result_image_path)

Coordinates results are always

Bounding Box: {'Width': 0.36104699969291687, 'Height': 0.4926089942455292, 'Left': 0.2809709906578064, 'Top': 0.24185499548912048} Image Size: (1686, 894) Calculated Coordinates: 473.7170902490616 216.2183659672737 608.7252414822578 440.3924408555031

Examle from 1 image Different image with different face position


Solution

  • The problem was in where it would look to get the coordinates of the face. After debugging I found this was the result:

    {
      "SearchedFaceBoundingBox": {
        "Width": 0.08695527911186218,
        "Height": 0.22615334391593933,
        "Left": 0.07250120490789413,
        "Top": 0.22623923420906067
      },
      "SearchedFaceConfidence": 99.98584747314453,
      "FaceMatches": [
        {
          "Similarity": 99.6037368774414,
          "Face": {
            "FaceId": "b7ca6c4a-64d8-41e7-b762-b401b85c0245",
            "BoundingBox": {
              "Width": 0.36104699969291687,
              "Height": 0.4926089942455292,
              "Left": 0.2809709906578064,
              "Top": 0.24185499548912048
            },
            "ImageId": "5e9f8044-9149-311d-9a6c-212a6fe73100",
            "Confidence": 99.9988021850586
          }
        }
      ]
    }
    

    The face bounding box was always the same and realise the SearchedFaceBoundingBox had the right coordinates so I adapted the code:

         for match in response['FaceMatches']:
                print(match['Face']['FaceId'], match['Face']['Confidence'])
                
                # Debug prints
                print("Bounding Box:", match['Face']['BoundingBox'])
                print("Image Size:", image.size)
                
                face = dynamodb.get_item(
                    TableName='TableName',
                    Key={'RekognitionId': {'S': match['Face']['FaceId']}}
                )
                
                if 'Item' in face:
                    print("The face identified is:", face['Item']['FullName']['S'])
                    
                    # Draw green square around recognized face
                    box = match['Face']['BoundingBox']
                    img_width, img_height = image.size
                    left = img_width * box['Left']
                    top = img_height * box['Top']
                    width = img_width * box['Width']
                    height = img_height * box['Height']
                    print("Drawing Rectangle:", left, top, left + width, top + height)
                    draw.rectangle([left, top, left + width, top + height], outline='green', width=2)
                    
                    # Display name at the bottom
                    text = face['Item']['FullName']['S']
                    text_width, text_height = draw.textsize(text, font)
                    print("Text Position:", left, top + height)
                    draw.text((left, top + height), text, fill='green', font=font)
                
                else:
                    print('no match found in person lookup')