Python cropped face image using dlib

Viewed 1593

I want to adjust the margin of cropped face image. My current code can detect and crop face. However, the cropped image is too tight as shown in the below output image.

Input image:

enter image description here

Below is my code:

import face_recognition
import cv2

img = face_recognition.load_image_file("test.png")
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

face_locations = face_recognition.face_locations(img_rgb)

for top, right, bottom, left in face_locations:
    # Draw a box around the face
    cv2.rectangle(img, (left, top), (right, bottom), (0, 0, 255), 2)

    crop_img = img_rgb[top:bottom, left:right]
    cv2.imwrite('test_crop.png', crop_img)
2 Answers

UPDATE: It will not work correctly for out of bound bounding boxes after scaling.

Code:

Use the scale_factor to control the new rectangle size. Also a different formula can be used for M. Using abs may not be necessary.

import face_recognition
import cv2


img = face_recognition.load_image_file("test.png")
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_rgb_copy = img_rgb.copy()


## Define scale factor and window size
scale_factor = 1.1
sz1 = img_rgb.shape[1] * 2
sz2 = img_rgb.shape[0] * 2


face_locations = face_recognition.face_locations(img_rgb)

for top, right, bottom, left in face_locations:
    # Draw a box around the face
    #cv2.rectangle(img, (left, top), (right, bottom), (0, 0, 255), 2)

    crop_img = img_rgb[top:bottom, left:right]
    #cv2.imwrite('test_crop.png', crop_img)



    ## Calculate center points and rectangle side length
    width = right - left
    height = bottom - top
    cX = left + width // 2
    cY = top + height // 2
    M = (abs(width) + abs(height)) / 2


    ## Get the resized rectangle points
    newLeft = max(0, int(cX - scale_factor * M))
    newTop = max(0, int(cY - scale_factor * M))
    newRight = min(img_rgb.shape[1], int(cX + scale_factor * M))
    newBottom = min(img_rgb.shape[0], int(cY + scale_factor * M))


    ## Draw the circle and bounding boxes
    cv2.circle(img_rgb_copy, (cX, cY), radius=0, color=(0, 0, 255), thickness=2)
    cv2.rectangle(img_rgb_copy, (left, top), (right, bottom), (0, 0, 255), 2)
    cv2.rectangle(img_rgb_copy, (newLeft, newTop), (newRight, newBottom), (255, 0, 0), 2)


    ## Show the original image in window resized to double
    cv2.namedWindow('image', cv2.WINDOW_NORMAL)
    cv2.resizeWindow('image', sz1, sz2)
    cv2.imshow("image", img_rgb_copy)
    cv2.waitKey(0)


cv2.destroyAllWindows()

Image:

enter image description here

Method:

Get the center point (cX, cY) of given region and from that get new left corner of image by subtracting same value from both (cX - M,cY - M). So the right corner will be (cX + M, cY + M). You can use a scale factor such as, M * p instead of M, where p will control how large or small the new region will be.

Center Point:

width = right - left
height = bottom - top

centerX = left + (width / 2)
centerY = top + (height / 2)

M = (abs(width) + abs(height)) / 2

0 <= p < 1, for smaller crop than given in a side
p > 1, for larger crop margin

Also the new crop may be out of bounds in image. To solve it something like, newTop = max(0, newTop), newRight = min(imageWidth, newRight) can be done and similar for others. You can find a demo here,

https://www.desmos.com/calculator/bgn9dobkjt

enter image description here

DeepFace wraps many face detection libraries. Besides, it applies face alignment in the background. You can detect faces in a line of code.

#!pip install deepface
from deepface import DeepFace
backends = ['opencv', 'ssd', 'dlib', 'mtcnn']
for backend in backends:
   detected_face = DeepFace.detectFace("img.jpg", detector_backend = backend)
Related