Get ROI from face landmark points cv2 dlib

1.9k views Asked by At

Am using following code to draw facial landmark points using dlib , on to the frames captured from webcam in realtime, now what am looking for is to get the ROI that bounds all the points complying the face , the code is as follows:

import cv2
import dlib
import numpy
from imutils.video import FPS
from imutils.video import WebcamVideoStream
import imutils

PREDICTOR_PATH = "./shape_predictor_68_face_landmarks.dat"
predictor = dlib.shape_predictor(PREDICTOR_PATH)
cascade_path = 'cascade/haarcascade_frontalface_default.xml'
cascade = cv2.CascadeClassifier(cascade_path)

webcam = WebcamVideoStream(src=0).start()
fps = FPS().start()

while True:
    im = webcam.read()
    im = imutils.resize(im, width=400)

    faces = cascade.detectMultiScale(im, 1.3, 5)
    if len(faces) != 0:
        for (x, y, w, h) in faces.astype(long):
            rect = dlib.rectangle(x, y, x + w, y + h)
            #cv2.imwrite('face.png', rect)
            get_landmarks = numpy.matrix([[p.x, p.y] for p in predictor(im, rect).parts()])

        for idx, point in enumerate(get_landmarks):
            pos = (point[0, 0], point[0, 1])
            cv2.putText(im, str(idx), pos,
                        fontFace=cv2.FONT_HERSHEY_SCRIPT_SIMPLEX,
                        fontScale=0.4,
                        color=(0, 0, 255))
           # cv2.drawContours(im, [pos], -1, (0, 255, 0), 2)
#            hullIndex = cv2.convexHull(pos, returnPoints=False)
#            cv2.imwrite('face.png', hullIndex)
            cv2.circle(im, pos, 3, color=(0, 255, 255))
    cv2.imshow('Result', im)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    fps.update()

cv2.destroyAllWindows()

I want to dump the facial landmark points into image file. but am unable to understand , how I can extract ROI from these landmark points and then dump to file using

cv2.imwrite('face.png', hullIndex)

, but here I don't want the rectangle drwaned using

faces = cascade.detectMultiScale(im, 1.3, 5)

, I want only the shape that circumfencec the facial landmark points, the output of the above code looks like below.

enter image description here

So, just dump only points that circumferences the facial edge points.

1

There are 1 answers

7
ZdaR On BEST ANSWER

After getting the 68 facial landmarks from the predictor, You may simply iterate over all the points and update the minX, minY, maxX, maxY which after the iteration would yield the bounding rect exactly enclosing all the facial landmarks.

You may also use cv2.boundingRect(points) but you need to transform all the points to a numpy array before passing to this method.

But I would recommend you the first solution and it is fairly easy to implement as

minX, minY = 10000000, 10000000
maxX, maxY = 0, 0
for point in get_landmarks:
    if point[0] < minX:
        minX = point[0]
    elif point[0] > maxX:
        maxX = point[0]
    elif point[1] < minY:
        minY = point[1]
    elif point[1] > maxY:
        maxY = point[1]

bounding_rect = [minX, minY, maxX - minX, maxY - minY]