diff --git a/bob/pad/face/test/test.py b/bob/pad/face/test/test.py index 799d8efb2b6a0506776dfd07e4b10516b6fd8c83..10043dfa44fa0d9f4a6af5c6fc76edfc88852ace 100644 --- a/bob/pad/face/test/test.py +++ b/bob/pad/face/test/test.py @@ -41,11 +41,41 @@ import random -def test_detect_face_landmarks_in_image(): +def test_detect_face_landmarks_in_image_mtcnn(): + + img = load(datafile('testimage.jpg', 'bob.bio.face.test')) + assert len(img) == 3 + annotations = face_detection_utils.detect_face_landmarks_in_image(img, method = 'mtcnn') + assert len(annotations['landmarks']) == 68 + assert len(annotations['left_eye']) == 2 + assert len(annotations['right_eye']) == 2 + assert len(annotations['topleft']) == 2 + assert len(annotations['bottomright']) == 2 + + #assert len(annotations['left_eye']) == (176, 220) + + + +def test_detect_face_landmarks_in_video_mtcnn(): + + img = load(datafile('testimage.jpg', 'bob.bio.face.test')) + assert len(img) == 3 + frame_container= bob.bio.video.FrameContainer() + frame_container.add(1,img) + frame_container.add(2,img) + + annotations = face_detection_utils.detect_face_landmarks_in_video(frame_container, method = 'mtcnn') + assert len(annotations) == 2 + assert len(annotations['1']['landmarks']) == 68 + + + + +def test_detect_face_landmarks_in_image_dlib(): img = load(datafile('testimage.jpg', 'bob.bio.face.test')) assert len(img) == 3 - annotations = face_detection_utils.detect_face_landmarks_in_image(img) + annotations = face_detection_utils.detect_face_landmarks_in_image(img, method = 'dlib') assert len(annotations['landmarks']) == 68 assert len(annotations['left_eye']) == 2 assert len(annotations['right_eye']) == 2 @@ -56,7 +86,7 @@ def test_detect_face_landmarks_in_image(): -def test_detect_face_landmarks_in_video(): +def test_detect_face_landmarks_in_video_dlib(): img = load(datafile('testimage.jpg', 'bob.bio.face.test')) assert len(img) == 3 @@ -64,7 +94,7 @@ def test_detect_face_landmarks_in_video(): frame_container.add(1,img) frame_container.add(2,img) - annotations = face_detection_utils.detect_face_landmarks_in_video(frame_container) + annotations = face_detection_utils.detect_face_landmarks_in_video(frame_container, method = 'dlib') assert len(annotations) == 2 assert len(annotations['1']['landmarks']) == 68 diff --git a/bob/pad/face/utils/face_detection_utils.py b/bob/pad/face/utils/face_detection_utils.py index 0ba1f2308344618aaba65a889722d90acc2731ed..7b01c4c26a3d767f4554655c9c092521e7102450 100644 --- a/bob/pad/face/utils/face_detection_utils.py +++ b/bob/pad/face/utils/face_detection_utils.py @@ -11,6 +11,43 @@ import importlib import numpy as np + +def getEyePos(lm): + + """ + This function returns the locations of left and right eyes + + **Parameters:** + + ``lm`` : :py:class:`array` + A numpy array containing the coordinates of facial landmarks, (68X2) + + + **Returns:** + + ``right_eye`` + A tuple containing the location of right eye, + + ``left_eye`` + A tuple containing the location of left eye + + """ + + # Mean position of eye corners as eye centers , casted to int() + + left_eye_t = (lm[36,:] + lm[39,:])/2.0 + right_eye_t = (lm[42,:] + lm[45,:])/2.0 + + right_eye = (int(left_eye_t[1]),int(left_eye_t[0])) + left_eye = (int(right_eye_t[1]),int(right_eye_t[0])) + + return right_eye,left_eye + + + + + + #============================================================================== def detect_face_in_image(image, method = "dlib"): """ @@ -99,100 +136,113 @@ def detect_faces_in_video(frame_container, method = "dlib"): return annotations -def getEyePos(lm): + +def detect_face_landmarks_in_image(image, method = "dlib"): """ - This function returns the locations of left and right eyes + This function detects a face in the input image. Two oprions for face detector , but landmark detector is always the same **Parameters:** - ``lm`` : :py:class:`array` - A numpy array containing the coordinates of facial landmarks, (68X2) + ``image`` : 3D :py:class:`numpy.ndarray` + A color image to detect the face in. + ``method`` : :py:class:`str` + A package to be used for face detection. Options supported by this + package: "dlib" (dlib is a dependency of this package). If bob.ip.mtcnn + is installed in your system you can use it as-well (bob.ip.mtcnn is NOT + a dependency of this package). **Returns:** - ``right_eye`` - A tuple containing the location of right eye, + ``annotations`` : :py:class:`dict` + A dictionary containing annotations of the face bounding box, eye locations and facial landmarks. + Dictionary must be as follows ``{'topleft': (row, col), 'bottomright': (row, col), 'left_eye': (row, col), 'right_eye': (row, col), 'landmarks': [(col1,row1), (col2,row2), ...]}``. + If no annotations found an empty dictionary is returned. + Where (rowK,colK) is the location of Kth facial landmark (K=0,...,67). + """ - ``left_eye`` - A tuple containing the location of left eye + ### Face detector - """ + try: + face_detection_module = importlib.import_module("bob.ip."+ method) - # Mean position of eye corners as eye centers , casted to int() + except ImportError: - left_eye_t = (lm[36,:] + lm[39,:])/2.0 - right_eye_t = (lm[42,:] + lm[45,:])/2.0 + print("No module named bob.ip." + method + " trying to use default method!") - right_eye = (int(left_eye_t[1]),int(left_eye_t[0])) - left_eye = (int(right_eye_t[1]),int(right_eye_t[0])) + try: + face_detection_module = importlib.import_module("bob.ip.dlib") + method = "dlib" + except ImportError: + raise ImportError("No module named bob.ip.dlib") + + + if not hasattr(face_detection_module, 'FaceDetector'): + raise AttributeError("bob.ip." + method + " module has no attribute FaceDetector!") + + + #### Landmark detector + + try: + landmark_detection_module = importlib.import_module("bob.ip.facelandmarks") + except ImportError: + raise ImportError("No module named bob.ip.facelandmarks!!") + + if not hasattr(landmark_detection_module, 'detect_landmarks_on_boundingbox'): + raise AttributeError("bob.ip.facelandmarksmodule has no attribute detect_landmarks_on_boundingbox!") + + + face_detector = face_detection_module.FaceDetector() - return right_eye,left_eye + data = face_detector.detect_single_face(image) -def detect_face_landmarks_in_image(image, method = "dlib"): - """ - This function detects a face and facial landmarks in the input image. + annotations = {} - **Parameters:** + if ( data is not None ) and ( not all([x is None for x in data]) ): - ``image`` : 3D :py:class:`numpy.ndarray` - A color image to detect the face in. + bounding_box = data[0] - ``method`` : :py:class:`str` - A package to be used for face detection. Options supported by this - package: "dlib" (dlib is a dependency of this package). + #bounding_box = bounding_box.scale(0.9, True) - **Returns:** + lm=landmark_detection_module.detect_landmarks_on_boundingbox(image, bounding_box) - ``annotations`` : :py:class:`dict` - A dictionary containing the annotations for an image. - Dictionary must be as follows ``{'topleft': (row, col), 'bottomright': (row, col), 'left_eye': (row, col), 'right_eye': (row, col), 'landmarks': [(row1,col1), (row2,col2), ...]}`` - Where (rowK,colK) is the location of Kth facial landmark (K=0,...,67). - If no annotations found an empty dictionary is returned. - """ + if lm is not None: - try: - face_landmark_detection_module = importlib.import_module("bob.ip.facelandmarks"); - except ImportError: - raise ImportError("No module named bob.ip.facelandmarks") + lm=np.array(lm) - if not hasattr(face_landmark_detection_module, 'detect_landmarks'): - raise AttributeError("bob.ip.facelandmarks module has no attribute detect_landmarks") + lm=np.vstack((lm[:,1],lm[:,0])).T - key_points = face_landmark_detection_module.detect_landmarks(image, 1); + #print("LM",lm) - annotations = {} + right_eye,left_eye = getEyePos(lm) - try: - kp = key_points[0] - except: - kp = None - if kp is not None: + points = [] + + for i in range(lm.shape[0]): + + points.append((int(lm[i,0]),int(lm[i,1]))) - lm = np.vstack((kp.landmarks[:,1],kp.landmarks[:,0])).T + annotations['topleft'] = bounding_box.topleft - right_eye,left_eye = getEyePos(lm) + annotations['bottomright'] = bounding_box.bottomright - points = [] + annotations['landmarks'] = points - for i in range(lm.shape[0]): - points.append((int(lm[i,0]),int(lm[i,1]))) + annotations['left_eye'] = left_eye - annotations['topleft'] = kp.bounding_box.topleft - annotations['bottomright'] = kp.bounding_box.bottomright - annotations['landmarks'] = points # list of landmarks - annotations['left_eye'] = left_eye - annotations['right_eye'] = right_eye + annotations['right_eye'] = right_eye return annotations + + def detect_face_landmarks_in_video(frame_container, method = "dlib"): """ This function detects a face and face landmarks in each farme of the input video. @@ -204,16 +254,17 @@ def detect_face_landmarks_in_video(frame_container, method = "dlib"): ``method`` : :py:class:`str` A package to be used for face detection. Options supported by this - package: "dlib" (dlib is a dependency of this package). + package: "dlib" (dlib is a dependency of this package) and "mtcnn". + If its found it will be used else defaults to "dlib" **Returns:** ``annotations`` : :py:class:`dict` A dictionary containing the annotations for each frame in the video. Dictionary structure: ``annotations = {'1': frame1_dict, '2': frame1_dict, ...}``. - Where ``frameN_dict = {'topleft': (row, col), 'bottomright': (row, col), 'left_eye': (row, col), 'right_eye': (row, col), 'landmarks': [(row1,col1), (row2,col2), ...]}`` + Where ``frameN_dict = {'topleft': (row, col), 'bottomright': (row, col), 'left_eye': (row, col), 'right_eye': (row, col), 'landmarks': [(col1,row1), (col2,row2), ...]}`` is the dictionary defining the coordinates of the face bounding box in frame N. - Where (rowK,colK) is the location of Kth facial landmark (K=0,...,67). + Where (colK,rowK) is the location of Kth facial landmark (K=0,...,67). If no annotations found an empty dictionary is returned. """