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:

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

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

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With