Cropping faces from an image using OpenCV in Python

Question:

I’m currently trying to crop faces from an image.

I want the code to work no matter how many faces are in the image.

An example of the input image:

Image with faces

I’d like to crop the faces so I can run a facial keypoint detection algorithm on them (previously made).

The end result will look something like this:

Image after facial keypoint detection

My code is currently:

# Load in color image for face detection
image = cv2.imread('images/obamas4.jpg')

# Convert the image to RGB colorspace
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

# Make a copy of the original image to draw face detections on
image_copy = np.copy(image)

# Convert the image to gray 
gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

# Detect faces in the image using pre-trained face dectector
faces = face_cascade.detectMultiScale(gray_image, 1.25, 6)

# Print number of faces found
print('Number of faces detected:', len(faces))

# Get the bounding box for each detected face
for f in faces:
    x, y, w, h = [ v for v in f ]
    cv2.rectangle(image_copy, (x,y), (x+w, y+h), (255,0,0), 3)
    # Define the region of interest in the image  
    face_crop = gray_image[y:y+h, x:x+w]
    
# Display the image with the bounding boxes
fig = plt.figure(figsize = (9,9))
axl = fig.add_subplot(111)
axl.set_xticks([])
axl.set_yticks([])

ax1.set_title("Obamas with Face Detection")
axl.imshow(image_copy)

# Display the face crops
fig = plt.figure(figsize = (9,9))
axl = fig.add_subplot(111)
axl.set_xticks([])
axl.set_yticks([])

axl.set_title("Obamas Face Crops")
axl.imshow(face_crop)

The output looks like this:

enter image description here

Right now it only outputs the last face detected in the image. I’m certain I’m missing something simple like a for loop.

I’d like to be able to run my facial keypoint detection algorithm on all of the gray cropped face images.

Thank you for your help!

Asked By: Daniel Bourke

||

Answers:

The problem is in your code, face_crop is storing only the last face detected.

So make it as a list and append all faces to it. Then use a for loop to display all faces. Like this:

face_crop = []
for f in faces:
    x, y, w, h = [ v for v in f ]
    cv2.rectangle(image_copy, (x,y), (x+w, y+h), (255,0,0), 3)
    # Define the region of interest in the image  
    face_crop.append(gray_image[y:y+h, x:x+w])

for face in face_crop:
    cv2.imshow('face',face)
    cv2.waitKey(0)

I used cv2.imshow() to display the images. You can modify this to use plt.imshow()

Hope this helps!

Answered By: janu777