| 6 | import cv2 |
| 7 | |
| 8 | class FaceAligner: |
| 9 | def __init__(self, predictor, desiredLeftEye=(0.35, 0.35), |
| 10 | desiredFaceWidth=256, desiredFaceHeight=None): |
| 11 | # store the facial landmark predictor, desired output left |
| 12 | # eye position, and desired output face width + height |
| 13 | self.predictor = predictor |
| 14 | self.desiredLeftEye = desiredLeftEye |
| 15 | self.desiredFaceWidth = desiredFaceWidth |
| 16 | self.desiredFaceHeight = desiredFaceHeight |
| 17 | |
| 18 | # if the desired face height is None, set it to be the |
| 19 | # desired face width (normal behavior) |
| 20 | if self.desiredFaceHeight is None: |
| 21 | self.desiredFaceHeight = self.desiredFaceWidth |
| 22 | |
| 23 | def align(self, image, gray, rect): |
| 24 | # convert the landmark (x, y)-coordinates to a NumPy array |
| 25 | shape = self.predictor(gray, rect) |
| 26 | shape = shape_to_np(shape) |
| 27 | |
| 28 | #simple hack ;) |
| 29 | if (len(shape)==68): |
| 30 | # extract the left and right eye (x, y)-coordinates |
| 31 | (lStart, lEnd) = FACIAL_LANDMARKS_68_IDXS["left_eye"] |
| 32 | (rStart, rEnd) = FACIAL_LANDMARKS_68_IDXS["right_eye"] |
| 33 | else: |
| 34 | (lStart, lEnd) = FACIAL_LANDMARKS_5_IDXS["left_eye"] |
| 35 | (rStart, rEnd) = FACIAL_LANDMARKS_5_IDXS["right_eye"] |
| 36 | |
| 37 | leftEyePts = shape[lStart:lEnd] |
| 38 | rightEyePts = shape[rStart:rEnd] |
| 39 | |
| 40 | # compute the center of mass for each eye |
| 41 | leftEyeCenter = leftEyePts.mean(axis=0).astype("int") |
| 42 | rightEyeCenter = rightEyePts.mean(axis=0).astype("int") |
| 43 | |
| 44 | # compute the angle between the eye centroids |
| 45 | dY = rightEyeCenter[1] - leftEyeCenter[1] |
| 46 | dX = rightEyeCenter[0] - leftEyeCenter[0] |
| 47 | angle = np.degrees(np.arctan2(dY, dX)) - 180 |
| 48 | |
| 49 | # compute the desired right eye x-coordinate based on the |
| 50 | # desired x-coordinate of the left eye |
| 51 | desiredRightEyeX = 1.0 - self.desiredLeftEye[0] |
| 52 | |
| 53 | # determine the scale of the new resulting image by taking |
| 54 | # the ratio of the distance between eyes in the *current* |
| 55 | # image to the ratio of distance between eyes in the |
| 56 | # *desired* image |
| 57 | dist = np.sqrt((dX ** 2) + (dY ** 2)) |
| 58 | desiredDist = (desiredRightEyeX - self.desiredLeftEye[0]) |
| 59 | desiredDist *= self.desiredFaceWidth |
| 60 | scale = desiredDist / dist |
| 61 | |
| 62 | # compute center (x, y)-coordinates (i.e., the median point) |
| 63 | # between the two eyes in the input image |
| 64 | eyesCenter = ((leftEyeCenter[0] + rightEyeCenter[0]) // 2, |
| 65 | (leftEyeCenter[1] + rightEyeCenter[1]) // 2) |
nothing calls this directly
no outgoing calls
no test coverage detected
searching dependent graphs…