Mask out face from image with OpenCV

asked 2015-11-23 15:06:43 -0500

Linus gravatar image

updated 2015-11-24 00:53:13 -0500

Hi, I am trying to use OpenCV to extract only the face on a image but I don't want any of the background in my image (I only want the actual face contour). I tried to detect a face and extract the ROI and pass that to a skin detector algorithm but the latter step fails for the most part.

import cv2
import numpy as np
import sys

cascPath = sys.argv[1]
faceCascade = cv2.CascadeClassifier(cascPath)

lower = np.array([0, 48, 80], dtype = "uint8")
upper = np.array([20, 255, 255], dtype = "uint8")

video_capture = cv2.VideoCapture(0)

def face_detect():
    while True:
        # Capture frame-by-frame
        ret, frame = video_capture.read()

        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        faces = faceCascade.detectMultiScale(
            gray,
            scaleFactor=1.1,
            minNeighbors=5,
            minSize=(30, 30),
            flags=cv2.CASCADE_SCALE_IMAGE
        )

        # Draw a rectangle around the faces
        for (x, y, w, h) in faces:
            #face_region = cv2.GetSubRect(image,(x, y, x+w, y+h))
            cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
            face_region = frame[y:y+h, x:x+w]
            converted = cv2.cvtColor(face_region, cv2.COLOR_BGR2HSV)
            skinMask = cv2.inRange(converted, lower, upper)

            # apply a series of erosions and dilations to the mask
            # using an elliptical kernel
            kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 11))
            skinMask = cv2.erode(skinMask, kernel, iterations = 2)
            skinMask = cv2.dilate(skinMask, kernel, iterations = 2)

            # blur the mask to help remove noise, then apply the
            # mask to the frame
            skinMask = cv2.GaussianBlur(skinMask, (3, 3), 0)
            skin = cv2.bitwise_and(face_region, face_region, mask = skinMask)

            cv2.imshow("Face", np.hstack([face_region, skin]))

            # Further processing on only the face without the background.

            #cv2.ellipse(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

        # Display the resulting frame
        cv2.imshow('Video', frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            return

face_detect()
video_capture.release()
cv2.destroyAllWindows()

Is there a better approach to extract the face? Maybe there is a way to select the most common colours and threshold that and apply the mask on to my image.

So I would like to like to segment the face provided by guidelines such as the ones below using OpenCV instead. image description

The result would be something like this. image description

Please let me know if you have any ideas.

edit retag flag offensive close merge delete

Comments

1

@sturkmen Thank you that seems like it could work, although if possible I'd like to extract only the facial part like demonstrated in this picture but with OpenCV.

Linus gravatar imageLinus ( 2015-11-24 00:47:57 -0500 )edit
1

see also http://life-in-a-monospace-typeface.t... i just googled "face swap opencv"

sturkmen gravatar imagesturkmen ( 2015-11-24 01:16:27 -0500 )edit
1

@sturkmen Thanks, but it uses the obsolete API and I use opencv 3.0, however I will have a look at it.

Linus gravatar imageLinus ( 2015-11-24 02:31:39 -0500 )edit