Skip to content

Commit

Permalink
Added __version__ ; Moved GFTT class to feature; Created dedicate…
Browse files Browse the repository at this point in the history
…d `face_utils` sub-module ; Added `FaceAligner` class
  • Loading branch information
jrosebr1 committed Apr 30, 2017
1 parent 1f111c0 commit 9861bee
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 4 deletions.
3 changes: 3 additions & 0 deletions imutils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# author: Adrian Rosebrock
# website: http://www.pyimagesearch.com

# set the version number
__version__ = "0.4.3"

# import the necessary packages
from .convenience import translate
from .convenience import rotate
Expand Down
6 changes: 6 additions & 0 deletions imutils/face_utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# import the necessary packages
from .helpers import FACIAL_LANDMARKS_IDXS
from .helpers import rect_to_bb
from .helpers import shape_to_np
from .helpers import visualize_facial_landmarks
from .facealigner import FaceAligner
75 changes: 75 additions & 0 deletions imutils/face_utils/facealigner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# import the necessary packages
from .helpers import FACIAL_LANDMARKS_IDXS
from .helpers import shape_to_np
import numpy as np
import cv2

class FaceAligner:
def __init__(self, predictor, desiredLeftEye=(0.35, 0.35),
desiredFaceWidth=256, desiredFaceHeight=None):
# store the facial landmark predictor, desired output left
# eye position, and desired output face width + height
self.predictor = predictor
self.desiredLeftEye = desiredLeftEye
self.desiredFaceWidth = desiredFaceWidth
self.desiredFaceHeight = desiredFaceHeight

# if the desired face height is None, set it to be the
# desired face width (normal behavior)
if self.desiredFaceHeight is None:
self.desiredFaceHeight = self.desiredFaceWidth

def align(self, image, gray, rect):
# convert the landmark (x, y)-coordinates to a NumPy array
shape = self.predictor(gray, rect)
shape = shape_to_np(shape)

# extract the left and right eye (x, y)-coordinates
(lStart, lEnd) = FACIAL_LANDMARKS_IDXS["left_eye"]
(rStart, rEnd) = FACIAL_LANDMARKS_IDXS["right_eye"]
leftEyePts = shape[lStart:lEnd]
rightEyePts = shape[rStart:rEnd]

# compute the center of mass for each eye
leftEyeCenter = leftEyePts.mean(axis=0).astype("int")
rightEyeCenter = rightEyePts.mean(axis=0).astype("int")

# compute the angle between the eye centroids
dY = rightEyeCenter[1] - leftEyeCenter[1]
dX = rightEyeCenter[0] - leftEyeCenter[0]
angle = np.degrees(np.arctan2(dY, dX)) - 180

# compute the desired right eye x-coordinate based on the
# desired x-coordinate of the left eye
desiredRightEyeX = 1.0 - self.desiredLeftEye[0]

# determine the scale of the new resulting image by taking
# the ratio of the distance between eyes in the *current*
# image to the ratio of distance between eyes in the
# *desired* image
dist = np.sqrt((dX ** 2) + (dY ** 2))
desiredDist = (desiredRightEyeX - self.desiredLeftEye[0])
desiredDist *= self.desiredFaceWidth
scale = desiredDist / dist

# compute center (x, y)-coordinates (i.e., the median point)
# between the two eyes in the input image
eyesCenter = ((leftEyeCenter[0] + rightEyeCenter[0]) // 2,
(leftEyeCenter[1] + rightEyeCenter[1]) // 2)

# grab the rotation matrix for rotating and scaling the face
M = cv2.getRotationMatrix2D(eyesCenter, angle, scale)

# update the translation component of the matrix
tX = self.desiredFaceWidth * 0.5
tY = self.desiredFaceHeight * self.desiredLeftEye[1]
M[0, 2] += (tX - eyesCenter[0])
M[1, 2] += (tY - eyesCenter[1])

# apply the affine transformation
(w, h) = (self.desiredFaceWidth, self.desiredFaceHeight)
output = cv2.warpAffine(image, M, (w, h),
flags=cv2.INTER_CUBIC)

# return the aligned face
return output
2 changes: 1 addition & 1 deletion imutils/face_utils.py → imutils/face_utils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
("left_eyebrow", (22, 27)),
("right_eye", (36, 42)),
("left_eye", (42, 48)),
("nose", (27, 35)),
("nose", (27, 36)),
("jaw", (0, 17))
])

Expand Down
1 change: 1 addition & 0 deletions imutils/feature/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .helpers import corners_to_keypoints
from .factories import FeatureDetector_create
from .factories import DescriptorExtractor_create
from .gftt import GFTT
2 changes: 1 addition & 1 deletion imutils/gftt.py → imutils/feature/gftt.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import cv2
from .convenience import corners_to_keypoints
from .helpers import corners_to_keypoints


class GFTT:
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

setup(
name='imutils',
packages=['imutils', 'imutils.video', 'imutils.io', 'imutils.feature'],
version='0.4.2',
packages=['imutils', 'imutils.video', 'imutils.io', 'imutils.feature', 'imutils.face_utils'],
version='0.4.3',
description='A series of convenience functions to make basic image processing functions such as translation, rotation, resizing, skeletonization, displaying Matplotlib images, sorting contours, detecting edges, and much more easier with OpenCV and both Python 2.7 and Python 3.',
author='Adrian Rosebrock',
author_email='[email protected]',
Expand Down

0 comments on commit 9861bee

Please sign in to comment.