Commit 4571f03e authored by 任婷婷's avatar 任婷婷

first commit

parent 5d924fe3
10.jpg

130 KB

100.jpg

59.1 KB

import cv2
import dlib
import numpy as np
TEMPLATE = np.float32([
(0.0792396913815, 0.339223741112), (0.0829219487236, 0.456955367943),
(0.0967927109165, 0.575648016728), (0.122141515615, 0.691921601066),
(0.168687863544, 0.800341263616), (0.239789390707, 0.895732504778),
(0.325662452515, 0.977068762493), (0.422318282013, 1.04329000149),
(0.531777802068, 1.06080371126), (0.641296298053, 1.03981924107),
(0.738105872266, 0.972268833998), (0.824444363295, 0.889624082279),
(0.894792677532, 0.792494155836), (0.939395486253, 0.681546643421),
(0.96111933829, 0.562238253072), (0.970579841181, 0.441758925744),
(0.971193274221, 0.322118743967), (0.163846223133, 0.249151738053),
(0.21780354657, 0.204255863861), (0.291299351124, 0.192367318323),
(0.367460241458, 0.203582210627), (0.4392945113, 0.233135599851),
(0.586445962425, 0.228141644834), (0.660152671635, 0.195923841854),
(0.737466449096, 0.182360984545), (0.813236546239, 0.192828009114),
(0.8707571886, 0.235293377042), (0.51534533827, 0.31863546193),
(0.516221448289, 0.396200446263), (0.517118861835, 0.473797687758),
(0.51816430343, 0.553157797772), (0.433701156035, 0.604054457668),
(0.475501237769, 0.62076344024), (0.520712933176, 0.634268222208),
(0.565874114041, 0.618796581487), (0.607054002672, 0.60157671656),
(0.252418718401, 0.331052263829), (0.298663015648, 0.302646354002),
(0.355749724218, 0.303020650651), (0.403718978315, 0.33867711083),
(0.352507175597, 0.349987615384), (0.296791759886, 0.350478978225),
(0.631326076346, 0.334136672344), (0.679073381078, 0.29645404267),
(0.73597236153, 0.294721285802), (0.782865376271, 0.321305281656),
(0.740312274764, 0.341849376713), (0.68499850091, 0.343734332172),
(0.353167761422, 0.746189164237), (0.414587777921, 0.719053835073),
(0.477677654595, 0.706835892494), (0.522732900812, 0.717092275768),
(0.569832064287, 0.705414478982), (0.635195811927, 0.71565572516),
(0.69951672331, 0.739419187253), (0.639447159575, 0.805236879972),
(0.576410514055, 0.835436670169), (0.525398405766, 0.841706377792),
(0.47641545769, 0.837505914975), (0.41379548902, 0.810045601727),
(0.380084785646, 0.749979603086), (0.477955996282, 0.74513234612),
(0.523389793327, 0.748924302636), (0.571057789237, 0.74332894691),
(0.672409137852, 0.744177032192), (0.572539621444, 0.776609286626),
(0.5240106503, 0.783370783245), (0.477561227414, 0.778476346951)])
TPL_MIN, TPL_MAX = np.min(TEMPLATE, axis=0), np.max(TEMPLATE, axis=0)
MINMAX_TEMPLATE = (TEMPLATE - TPL_MIN) / (TPL_MAX - TPL_MIN)
class AlignDlib:
#: Landmark indices.
INNER_EYES_AND_BOTTOM_LIP = [39, 42, 57]
OUTER_EYES_AND_NOSE = [36, 45, 33]
def __init__(self, facePredictor):
"""
Instantiate an 'AlignDlib' object.
:param facePredictor: The path to dlib's
:type facePredictor: str
"""
assert facePredictor is not None
self.detector = dlib.get_frontal_face_detector()
self.predictor = dlib.shape_predictor(facePredictor)
def getAllFaceBoundingBoxes(self, rgbImg):
"""
Find all face bounding boxes in an image.
:param rgbImg: RGB image to process. Shape: (height, width, 3)
:type rgbImg: numpy.ndarray
:return: All face bounding boxes in an image.
:rtype: dlib.rectangles
"""
assert rgbImg is not None
try:
return self.detector(rgbImg, 1)
except Exception as e:
print("Warning: {}".format(e))
# In rare cases, exceptions are thrown.
return []
def getLargestFaceBoundingBox(self, rgbImg, skipMulti=False):
"""
Find the largest face bounding box in an image.
:param rgbImg: RGB image to process. Shape: (height, width, 3)
:type rgbImg: numpy.ndarray
:param skipMulti: Skip image if more than one face detected.
:type skipMulti: bool
:return: The largest face bounding box in an image, or None.
:rtype: dlib.rectangle
"""
assert rgbImg is not None
#print('rgbimg {}'.format(rgbImg))
faces = self.getAllFaceBoundingBoxes(rgbImg)
#print('faces {}'.format(faces))
if (not skipMulti and len(faces) > 0) or len(faces) == 1:
return max(faces, key=lambda rect: rect.width() * rect.height())
else:
return None
def findLandmarks(self, rgbImg, bb):
"""
Find the landmarks of a face.
:param rgbImg: RGB image to process. Shape: (height, width, 3)
:type rgbImg: numpy.ndarray
:param bb: Bounding box around the face to find landmarks for.
:type bb: dlib.rectangle
:return: Detected landmark locations.
:rtype: list of (x,y) tuples
"""
assert rgbImg is not None
assert bb is not None
points = self.predictor(rgbImg, bb)
return list(map(lambda p: (p.x, p.y), points.parts()))
def align(self, imgDim, rgbImg, bb=None,
landmarks=None, landmarkIndices=INNER_EYES_AND_BOTTOM_LIP,
skipMulti=False):
r"""align(imgDim, rgbImg, bb=None, landmarks=None, landmarkIndices=INNER_EYES_AND_BOTTOM_LIP)
Transform and align a face in an image.
:param imgDim: The edge length in pixels of the square the image is resized to.
:type imgDim: int
:param rgbImg: RGB image to process. Shape: (height, width, 3)
:type rgbImg: numpy.ndarray
:param bb: Bounding box around the face to align. \
Defaults to the largest face.
:type bb: dlib.rectangle
:param landmarks: Detected landmark locations. \
Landmarks found on `bb` if not provided.
:type landmarks: list of (x,y) tuples
:param landmarkIndices: The indices to transform to.
:type landmarkIndices: list of ints
:param skipMulti: Skip image if more than one face detected.
:type skipMulti: bool
:return: The aligned RGB image. Shape: (imgDim, imgDim, 3)
:rtype: numpy.ndarray
"""
assert imgDim is not None
assert rgbImg is not None
assert landmarkIndices is not None
#pad
im = rgbImg
row, col= im.shape[:2]
bottom= im[row-2:row, 0:col]
mean= cv2.mean(bottom)[0]
bordersize=500
border=cv2.copyMakeBorder(im, top=bordersize, bottom=bordersize, left=bordersize, right=bordersize, borderType= cv2.BORDER_CONSTANT, value=[mean,mean,mean] )
#cv2.imwrite('/srv/apps/gmface/border.jpg',border)
if bb is None:
bb = self.getLargestFaceBoundingBox(rgbImg, skipMulti)
if bb is None:
return
if landmarks is None:
landmarks = self.findLandmarks(rgbImg, bb)
npLandmarks = np.float32(landmarks)
npLandmarkIndices = np.array(landmarkIndices)
H = cv2.getAffineTransform(npLandmarks[npLandmarkIndices],
imgDim * MINMAX_TEMPLATE[npLandmarkIndices])
#thumbnail = cv2.warpAffine(rgbImg, H, (rgbImg.shape[1], rgbImg.shape[0]))
border_warp = cv2.warpAffine(border, H, (rgbImg.shape[1], rgbImg.shape[0]))
#cv2.imwrite('/srv/apps/gmface/nail.jpg',thumbnail)
#cv2.imwrite('/srv/apps/gmface/border_warp.jpg',border_warp)
#return thumbnail
return border_warp
# coding:utf-8
# author:Thierry
from abc import abstractmethod
class BasePart(object):
CATEGORIES = []
@abstractmethod
def attrs(self):
pass
@abstractmethod
def get_vector(self):
pass
def __init__(self, **kwargs):
#self.roll_rand = roll_rand
for attr in self.attrs():
setattr(self, attr, kwargs[attr])
# coding: utf-8
# author: gushitong
from __future__ import division
import math
import numpy as np
from base_part import BasePart
from sklearn import preprocessing
class Chin(BasePart):
"""
下巴模型
"""
CATEGORIES = ['sharp', 'round', 'square']
def __init__(self,**kwargs):
super(Chin,self).__init__(**kwargs)
self.contour_left1=self.p_0
self.contour_left6=self.p_12
self.contour_left7=self.p_13
self.contour_left8=self.p_14
self.contour_left9=self.p_15
self.contour_chin=self.p_16
self.contour_right1=self.p_32
self.contour_right6=self.p_20
self.contour_right7=self.p_19
self.contour_right8=self.p_18
self.contour_right9=self.p_17
def get_vector(self):
result=[]
result=self.chin_baseline_angle()
angle=self.chin_bottom_angle()
result.append(angle)
normalized= preprocessing.normalize(result).reshape(1,-1)
return result
def attrs(self):
return (
'p_0',
'p_12',
'p_13',
'p_14',
'p_15',
'p_16',
'p_17',
'p_18',
'p_19',
'p_20',
'p_32',
)
@property
def base_slope(self):
"""
base slope: 基准斜率
:return:
"""
return (self.slope_abs(self.contour_left1, self.contour_chin) +
self.slope_abs(self.contour_right1, self.contour_chin)) / 2
def slope_abs(self, point1, point2):
"""
absolute value of slope.
:param point1:
:param point2:
:return:
"""
return math.atan(abs((point1['y'] - point2['y']) / (point1['x'] - point2['x'])))
def slopes(self):
"""将相关的点拟合成抛物线,计算曲率"""
slopes = []
for i in range(6, 10):
s1 = self.slope_abs(getattr(self, 'contour_left' + str(i)), self.contour_chin)
s2 = self.slope_abs(getattr(self, 'contour_right' + str(i)), self.contour_chin)
slopes.append((s1 + s2) / (2 * self.base_slope))
return slopes
def chin_slopes(self):
slopes_l=[]
slopes_r=[]
slopes=[]
for i in range(6,9):
s1 = self.slope_abs(getattr(self, 'contour_left' + str(i)), self.contour_chin)
s2 = self.slope_abs(getattr(self, 'contour_right' + str(i)), self.contour_chin)
slopes_l.append(s1)
slopes_r.append(s2)
slopes=slopes_l+slopes_r
return slopes
def chin_baseline_angle(self):
#baseline
base=self.slope_abs(self.p_15,self.p_17)
left=self.slope_abs(self.p_13,self.p_16)
right=self.slope_abs(self.p_19,self.p_16)
angle_left=abs((left-base)/(1+left*base))
angle_right=abs((right-base)/(1+right*base))
return [angle_left,angle_right]
def chin_bottom_angle(self):
left=self.slope_abs(self.p_13,self.p_16)
right=self.slope_abs(self.p_19,self.p_16)
angle=abs((left-right)/(1+left*right))
return angle
def face_chin_width_ratio(self):
face_w=np.sqrt((self.p_0['x']-self.p_16['x'])**2+(self.p_0['y']-self.p_16['y'])**2)
chin_w=np.sqrt((self.p_4['x']-self.p_12['x'])**2+(self.p_4['y']-self.p_12['y'])**2)
#face_w=distance(self.p_0,self.p_16)
#chin_w=distance(self.p_4,self.p_12)
ratio=chin_w/face_w
#ratio=(face_w/chin_w-1)
return ratio
# coding:utf-8
# author:Thierry
from __future__ import division
import math
from sklearn import preprocessing
from base_part import BasePart
import numpy as np
class Contour(BasePart):
def __init__(self,**kwargs):
super(Contour,self).__init__(**kwargs)
self.contour_left1=self.p_0
self.contour_left2=self.p_2
self.contour_left3=self.p_4
self.contour_left4=self.p_6
self.contour_left5=self.p_8
self.contour_left6=self.p_10
self.contour_left7=self.p_12
self.contour_left8=self.p_14
self.contour_left9=self.p_15
self.contour_chin=self.p_16
self.contour_right1=self.p_32
self.contour_right2=self.p_30
self.contour_right3=self.p_28
self.contour_right4=self.p_26
self.contour_right5=self.p_24
self.contour_right6=self.p_22
self.contour_right7=self.p_20
self.contour_right8=self.p_18
self.contour_right9=self.p_17
def attrs(self):
return (
'p_0',
'p_1',
'p_2',
'p_3',
'p_4',
'p_5',
'p_6',
'p_7',
'p_8',
'p_9',
'p_10',
'p_11',
'p_12',
'p_13',
'p_14',
'p_15',
'p_16',
'p_17',
'p_18',
'p_20',
'p_22',
'p_24',
'p_26',
'p_28',
'p_30',
'p_32'
)
def get_vector(self):
result=self.slopes()
result+=self.face_chin_angle_plus()
#result.append(self.width_height_ratio())
#result.append(self.chin_bottom_angle())
normalized= preprocessing.normalize(result).reshape(1,-1)
return normalized
@property
def base_slope(self):
"""
base slope: 基准斜率
:return:
"""
return (self.slope_abs(self.contour_left1, self.contour_chin) +
self.slope_abs(self.contour_right1, self.contour_chin)) / 2
def slope_abs(self, point1, point2):
"""
absolute value of slope.
:param point1:
:param point2:
:return:
"""
return math.atan(abs((point1['y'] - point2['y']) / (point1['x'] - point2['x'])))
def slopes(self):
"""将相关的点拟合成抛物线,计算曲率"""
slopes = []
for i in range(3, 10):
s1 = self.slope_abs(getattr(self, 'contour_left' + str(i)), self.contour_chin)
s2 = self.slope_abs(getattr(self, 'contour_right' + str(i)), self.contour_chin)
slopes.append((s1 + s2) / (2 * self.base_slope))
return slopes
def distance(self,pt1,pts):
dist=np.sqrt(np.square(pt1['x']-pt2['x'])+np.square(pt1['y']-pt2['y']))
def face_chin_width_ratio(self):
face_w=np.sqrt((self.p_0['x']-self.p_16['x'])**2+(self.p_0['y']-self.p_16['y'])**2)
chin_w=np.sqrt((self.p_4['x']-self.p_12['x'])**2+(self.p_4['y']-self.p_12['y'])**2)
ratio=chin_w/face_w
return ratio
def width_height_ratio(self):
center={}
center['x']=0.5*(self.p_19['x']+self.p_24['x'])
center['y']=0.5*(self.p_19['y']+self.p_24['y'])
face_w=np.sqrt((self.p_0['x']-self.p_16['x'])**2+(self.p_0['y']-self.p_16['y'])**2)
face_h=np.sqrt((self.p_8['x']-center['x'])**2+(self.p_8['y']-center['y'])**2)
return face_w/face_h
def chin_slopes(self):
s1 = self.slope_abs(self.contour_left4, self.contour_left7)
s2 = self.slope_abs(self.contour_right4, self.contour_right7)
s3 = self.slope_abs(self.contour_left8, self.contour_chin)
s4 = self.slope_abs(self.contour_right8, self.contour_chin)
slopes=[s1,s2,s3,s4]
return slopes
def face_chin_angle(self):
BA = [
self.p_4['x'] - self.p_0['x'],
self.p_4['y'] - self.p_0['y']
]
BC = [
self.p_4['x'] - self.p_7['x'],
self.p_4['y'] - self.p_7['y']
]
cosin_0 = (
(BA[0] * BC[0] + BA[1] * BC[1]) /
(math.sqrt(BA[0] ** 2 + BA[1] ** 2) * math.sqrt(BC[0] ** 2) + BC[1] ** 2)
)
BA_R = [
self.p_16['x'] - self.p_12['x'],
self.p_16['y'] - self.p_12['y']
]
BC_R = [
self.p_16['x'] - self.p_9['x'],
self.p_16['y'] - self.p_9['y']
]
cosin_1 = (
(BA_R[0] * BC_R[0] + BA_R[1] * BC_R[1]) /
(math.sqrt(BA_R[0] ** 2 + BA_R[1] ** 2) * math.sqrt(BC_R[0] ** 2) + BC_R[1] ** 2)
)
return [cosin_0,cosin_1]
def face_chin_angle_plus(self):
k1=self.slope_abs(self.p_1,self.p_4)
k2=self.slope_abs(self.p_7,self.p_4)
angle1=abs((k2-k1)/(1+k1*k2))
k3=self.slope_abs(self.p_15,self.p_12)
k4=self.slope_abs(self.p_9,self.p_12)
angle2=abs((k4-k3)/(1+k3*k4))
k5=self.slope_abs(self.p_6,self.p_7)
k6=self.slope_abs(self.p_9,self.p_10)
angle3=abs((k5-k6)/(1+k5*k6))
return [angle1,angle2,angle3]
def chin_bottom_angle(self):
left=self.slope_abs(self.p_7,self.p_8)
right=self.slope_abs(self.p_9,self.p_8)
angle=abs((left-right)/(1+left*right))
return angle
# coding:utf-8
# author:Thierry
import math
from base_part import BasePart
import array
from sklearn import preprocessing
def dotproduct(v1, v2):
return sum((a*b) for a, b in zip(v1, v2))
def length(v):
return math.sqrt(dotproduct(v, v))
class Eye(BasePart):
def __init__(self,**kwargs):
super(Eye,self).__init__(**kwargs)
self.left_eye_bottom=self.p_66
self.left_eye_right_corner=self.p_64
self.left_eye_left_corner=self.p_60
self.left_eye_top=self.p_62
def attrs(self):
return (
'p_60', #left eye
'p_61',
'p_62',
'p_63',
'p_64',
'p_65',
'p_66',
'p_67',
'p_68', #right eye
'p_69',
'p_70',
'p_71',
'p_72',
'p_73',
'p_74',
'p_75',
'p_96', #pupil
'p_97'
)
def get_vector(self):
v = [self.inner_angle(),
self.top_inner_outer_rand(),
self.inner_top_bottom_rand(),
self.aspect_ratio()
]
normalized= preprocessing.normalize(v).reshape(1,-1)
return normalized
def inner_angle(self):
'''
inner corner angle
'''
a = [self.p_63['x'],self.p_63['y']]
b = [self.p_64['x'],self.p_64['y']]
v1 = [x-y for x,y in zip(a,b)]
c = [self.p_65['x'],self.p_65['y']]
d = [self.p_64['x'],self.p_64['y']]
v2 = [x-y for x,y in zip(c,d)]
angle = math.acos(dotproduct(v1, v2) / (length(v1) * length(v2)))
return angle
def delta_height(self):
return (self.p_60['y'] - self.p_64['y'])
def inner_upper_rand(self):
"""
内外眼角上挑的弧度(值越大,越趋近丹凤眼)
"""
adjacent = self.left_eye_right_corner['x'] - self.left_eye_left_corner['x']
opposite = self.left_eye_right_corner['y'] - self.left_eye_left_corner['y']
#print('a',adjacent,'opp',opposite)
return math.atan2(opposite, adjacent) - self.roll_rand
def top_inner_outer_rand(self):
"""
眼顶部中心和内外眼角的夹角
"""
# 顶部内夹角
inner_opposite = self.left_eye_right_corner['x'] - self.left_eye_top['x']
inner_adjacent = self.left_eye_right_corner['y'] - self.left_eye_top['y']
inner_rand = math.atan2(inner_opposite, inner_adjacent)
# 顶部外夹角
outer_opposite = self.left_eye_top['x'] - self.left_eye_left_corner['x']
outer_adjacent = self.left_eye_left_corner['y'] - self.left_eye_top['y']
outer_rand = math.atan2(outer_opposite, outer_adjacent)
return inner_rand + outer_rand
def bottom_inner_outer_rand(self):
"""
眼底部的和内外眼角的夹角
"""
# 底部内夹角
inner_opposite = self.left_eye_right_corner['x'] - self.left_eye_bottom['x']
inner_adjacent = self.left_eye_bottom['y'] - self.left_eye_right_corner['y']
inner_rand = math.atan2(inner_opposite, inner_adjacent)
# 底部外夹角
outer_opposite = self.left_eye_bottom['x'] - self.left_eye_left_corner['x']
outer_adjacent = self.left_eye_bottom['y'] - self.left_eye_left_corner['y']
outer_rand = math.atan2(outer_opposite, outer_adjacent)
return inner_rand + outer_rand
def inner_top_bottom_rand(self):
"""
内眼角和顶部底部的夹角
"""
# 内眼角与顶部夹角
top_opposite = self.left_eye_right_corner['y'] - self.left_eye_top['y']
top_adjacent = self.left_eye_right_corner['x'] - self.left_eye_top['x']
top_rand = math.atan2(top_opposite, top_adjacent)
# 内眼角与底部夹角
bottom_opposite = self.left_eye_bottom['y'] - self.left_eye_right_corner['y']
bottom_adjacent = self.left_eye_right_corner['x'] - self.left_eye_bottom['x']
bottom_rand = math.atan2(bottom_opposite, bottom_adjacent)
return top_rand + bottom_rand
def outer_top_bottom_rand(self):
"""
外眼角和顶部底部的夹角
"""
# 外眼角与顶部夹角
top_opposite = self.left_eye_left_corner['y'] - self.left_eye_top['y']
top_adjacent = self.left_eye_top['x'] - self.left_eye_left_corner['x']
top_rand = math.atan2(top_opposite, top_adjacent)
# 外眼角与底部夹角
bottom_opposite = self.left_eye_bottom['y'] - self.left_eye_left_corner['y']
bottom_adjacent = self.left_eye_bottom['x'] - self.left_eye_left_corner['x']
bottom_rand = math.atan2(bottom_opposite, bottom_adjacent)
return top_rand + bottom_rand
def aspect_ratio(self):
"""
宽高比(值越大,越圆)
"""
return float(self._width()) / float(self._height())
def _height(self):
return self.left_eye_bottom['y'] - self.left_eye_top['y']
def _width(self):
return self.left_eye_right_corner['x'] - self.left_eye_left_corner['x']
# coding: utf-8
# from __future__ import division
import math
from base_part import BasePart
from sklearn import preprocessing
class EyeBrow(BasePart):
"""
眉毛模型
"""
CATEGORIES = ['pingzhi', 'xiachui', 'liuye', 'gongxing', 'shangtiao']
def __init__(self,**kwargs):
super(EyeBrow,self).__init__(**kwargs)
self.left_eyebrow_left_corner=self.p_33
self.left_eyebrow_upper_left_quarter=self.p_36
self.left_eyebrow_lower_left_quarter=self.p_39
self.left_eyebrow_lower_middle=self.p_40
self.left_eyebrow_right_corner=self.p_37
self.left_eyebrow_lower_right_quarter=self.p_34
self.left_eyebrow_upper_right_quarter=self.p_41
self.left_eyebrow_upper_middle=self.p_35
self.right_eyebrow_left_corner=self.p_42
self.right_eyebrow_right_corner=self.p_46
self.right_eyebrow_upper_middle=self.p_44
self.right_eyebrow_upper_right_quarter=self.p_43
self.left_0=self.p_33
self.left_1=self.p_34
self.left_2=self.p_35
self.left_3=self.p_36
self.left_4=self.p_37
self.right_0=self.p_42
self.right_1=self.p_43
self.right_2=self.p_44
self.right_3=self.p_45
self.right_4=self.p_46
def attrs(self):
return (
'p_33',
'p_34',
'p_35',
'p_36',
'p_37',
'p_41',
'p_42',
'p_43',
'p_44',
'p_45',
'p_46',
'p_39',
'p_40',
)
def _q_length_ratio(self):
"""眉峰 占据 整个眉长的比例."""
al = self.left_eyebrow_right_corner['x'] - self.left_eyebrow_left_corner['x']
bl = self.left_eyebrow_right_corner['x'] - self.left_eyebrow_upper_left_quarter['x']
ar = self.right_eyebrow_right_corner['x'] - self.right_eyebrow_left_corner['x']
br = self.right_eyebrow_left_corner['x'] - self.right_eyebrow_upper_right_quarter['x']
a = abs(al) + abs(ar)
b = abs(bl) + abs(br)
return b / a
def _q_length_ratio_plus(self):
"""眉峰 占据 整个眉长的比例."""
left_high={}
right_high={}
if self.p_18['y']>self.p_19['y']:
left_high['x']=self.p_18['x']
else:
left_high['x']=self.p_19['x']
if self.p_24['y']>self.p_25['y']:
right_high['x']=self.p_24['x']
else:
right_high['x']=self.p_25['x']
al = self.p_21['x'] - left_high['x']
bl = left_high['x'] - self.p_17['x']
ratio_left= al/bl
ar = right_high['x'] - self.p_22['x']
br = self.p_26['x'] - right_high['x']
ratio_right=ar/br
return ratio_left
def _corner_upper_middle_angle(self):
"""
left upper middle: B as origin
left corner: A
right corner: C
return: cosin <ABC>
"""
BA = [
self.left_eyebrow_left_corner['x'] - self.left_eyebrow_upper_middle['x'],
self.left_eyebrow_left_corner['y'] - self.left_eyebrow_upper_middle['y']
]
BC = [
self.left_eyebrow_right_corner['x'] - self.left_eyebrow_upper_middle['x'],
self.left_eyebrow_right_corner['y'] - self.left_eyebrow_upper_middle['y']
]
cosin = (
(BA[0] * BC[0] + BA[1] * BC[1]) /
(math.sqrt(BA[0] ** 2 + BA[1] ** 2) * math.sqrt(BC[0] ** 2) + BC[1] ** 2)
)
return cosin
def _corner_upper_q_slope(self):
y = self.right_eyebrow_left_corner['y'] - self.right_eyebrow_upper_right_quarter['y']
x = self.right_eyebrow_upper_right_quarter['x'] - self.right_eyebrow_left_corner['x']
if x==0:
return 100
return y / x
def _corner_upper_q_slope_plus(self):
yr = self.p_26['y'] - self.p_25['y']
xr = self.p_26['x'] - self.p_25['x']
if xr!=0:
ratio_r=yr/xr
else:
ratio_r=100
yl = self.p_18['y'] - self.p_17['y']
xl = self.p_18['x'] - self.p_17['x']
if xl!=0:
ratio_l=yl/xl
else:
ratio_l=100
return ratio_l,ratio_r
def head_middle_end_angle(self):
s1=slope_abs(self.left_2,self.left_0)
s2=slope_abs(self.left_4,self.left_2)
s3=slope_abs(self.right_2,self.right_0)
s4=slope_abs(self.right_4,self.right_2)
return s1,s2,s3,s4
def slope_abs(self, point1, point2):
"""
absolute value of slope.
:param point1:
:param point2:
:return:
"""
return math.atan(abs((point1['y'] - point2['y']) / (point1['x'] - point2['x'])))
def eyebrow_slopes(self):
slopes=[]
slopes_l=[]
slopes_r=[]
for i in range(0,5):
if i!= 2:
s1 = self.slope_abs(getattr(self, 'left_' + str(i)), self.left_2)
s2 = self.slope_abs(getattr(self, 'right_' + str(i)), self.right_2)
slopes_l.append(s1)
slopes_r.append(s2)
slopes=slopes_l+slopes_r
return slopes
def eyebrow_raw_points(self):
return[self.left_0,self.left_1,self.left_2,self.left_3,self.left_4,self.right_0,self.right_1,self.right_2,self.right_3,self.right_4]
def get_vector(self):
result= self.eyebrow_slopes()
angle= self._corner_upper_middle_angle()
result.append(angle)
result= preprocessing.normalize(result).reshape(1,-1)
return result
# coding:utf-8
from glob import glob
import scipy.io as sio
from skimage.io import imread, imsave
from skimage.transform import rescale, resize
from time import time
import argparse
import os
import math
import json
from django.conf import settings
import requests
import io
from PIL import Image
import numpy as np
import random
from eye96 import Eye
from nose96 import Nose
from eyebrow96 import EyeBrow
from chin96 import Chin
from contour96 import Contour
from lip96 import Lip
import dlib
import numpy
from align import AlignDlib
import caffe
import cv2
BASE_DIR='/home/gmface'
PREDICTOR_PATH = os.path.join(BASE_DIR, 'models','shape_predictor_68_face_landmarks.dat')
ROLL_MODEL_PATH = os.path.join(BASE_DIR, 'models','cnn_cccdd_30k.tf')
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(PREDICTOR_PATH)
class TooManyFaces(Exception):
pass
class NoFaces(Exception):
pass
class Face_folder(object):
PARTS = {'eye': Eye, 'nose': Nose, 'eyebrow': EyeBrow, 'chin': Chin, 'contour': Contour, 'lip': Lip}
def __init__(self, image_url,img_path):
self.face_raw = None
if img_path:
self.img_path=img_path
self.img=cv2.imread(img_path)
#print('self.img',self.img)
elif image_url:
#print('url',image_url)
image_url = image_url.strip()
result = requests.get(image_url)
if result.ok:
img = Image.open(io.BytesIO(result.content))
img = img.convert('RGB')
self.img = np.array(img)
h,w,c=self.img.shape
#print(h,w)
if h<70 or w<70:
raise NoFaces
#print('img {}'.format(self.img))
else:
raise NoFaces
else:
raise NoFaces
@classmethod
def get_vector(cls,image_url,img_path,part,net):
"""
get part vector.
:return:
"""
face = Face_folder(image_url,img_path)
face.build_landmark(net)
face.build_part()
return getattr(face, part).get_vector()
def get_aligned_face_landmarks(self,net):
img= self.img
align = AlignDlib(PREDICTOR_PATH)
bb_aligned=None
alignedFace=None
if img is not None:
#print('img{}'.format(img))
cv2.imwrite('source.jpg',img)
h,w,c = img.shape
#img = cv2.resize(img,(int(w*0.2),int(h*0.2)))
#h,w = img.shape[:2]
#cv2.imwrite('res.jpg',img)
#detector = dlib.get_frontal_face_detector()
#detpath = 'models/mmod_human_face_detector.dat'
#detector = dlib.face_detection_model_v1(detpath)
#detector = dlib.cnn_face_detection_model_v1(detpath)
#bb = detector(img)
bb = align.getLargestFaceBoundingBox(img)
if bb == None:
center = (w/2,h/2)
angle90 = 270
scale = 1.0
M = cv2.getRotationMatrix2D(center, angle90, scale)
rotated90 = cv2.warpAffine(img, M, (h, w))
#img = cv2.flip(img,1)
#img = cv2.flip(img,1)
cv2.imwrite('flip.jpg',rotated90)
faces = detector(img,1)
#print('faces',faces)
bb = faces[0]
#print('face len',len(faces))
bb = align.getLargestFaceBoundingBox(rotated90)
#print('bb',bb)
alignedFace = align.align(
112,
img,
bb,
landmarkIndices=AlignDlib.OUTER_EYES_AND_NOSE)
#print('aligned face{}'.format(alignedFace))
#print('ali size',alignedFace.shape)
alignedFace = cv2.resize(alignedFace,(640,640))
#cv2.imwrite('/srv/apps/gmface/align.jpg',alignedFace)
#cv2.imwrite('/srv/apps/gmface/org.jpg',img)
rects=detector(alignedFace,1)
#print('rects {}'.format(rects))
else:
print("input img is empty")
if len(rects)>1:
raise TooManyFaces
if len(rects)==0:
raise NoFaces
landmarks = net.loadimageAndlandmark98(alignedFace)
lk_dict={}
im = alignedFace.copy()
for i, p in enumerate(landmarks):
d={}
d['x']=p[0]
d['y']=p[1]
points={}
name='p_'+str(i)
points[name]=d
lk_dict.update(points)
pos = (int(p[0]), int(p[1]))
cv2.putText(im, str(i), pos,
fontFace=cv2.FONT_HERSHEY_SCRIPT_SIMPLEX,
fontScale=0.4,
color=(0, 0, 255))
cv2.circle(im, pos, 3, color=(0, 255, 255))
#cv2.imwrite('3.jpg',im)
#print('lk_dict {}'.format(lk_dict))
return alignedFace,lk_dict
def get_face_landmarks(self):
img= self.img
if img is not None:
rgbImg = cv2.cvtColor(bgrImg, cv2.COLOR_BGR2RGB)
rects=detector(img,1)
else:
print("input img is empty")
if len(rects)>1:
raise TooManyFaces
if len(rects)==0:
raise NoFaces
lk_dict={}
for i, p in enumerate(predictor(img,rects[0]).parts()):
d={}
d['x']=p.x
d['y']=p.y
points={}
name='p_'+str(i)
points[name]=d
lk_dict.update(points)
face=rects[0]
return face,lk_dict
def build_landmark(self,net):
"""build landmark using dlib"""
h,w,c=self.img.shape
if h!=w:
self.img = cv2.resize(self.img, (h,h), interpolation=cv2.INTER_CUBIC)
face,landmarks = self.get_aligned_face_landmarks(net)
self.landmark = landmarks
def build_part(self):
""" build part """
if self.landmark is not None:
for attr, part in self.PARTS.items():
setattr(self, attr, part(**self.landmark))
# coding: utf-8
# author: gushitong
from __future__ import division
import math
from sklearn import preprocessing
from base_part import BasePart
def dist(point1, point2):
return math.sqrt((point1['y'] - point2['y']) ** 2 + (point1['x'] - point2['x']) ** 2)
class Lip(BasePart):
CATEGORIES = ['thin', 'standard', 'thick']
def __init__(self,**kwargs):
super(Lip,self).__init__(**kwargs)
self.mouth_lower_lip_top=self.p_94
self.mouth_lower_lip_bottom=self.p_85
self.mouth_left_corner=self.p_76
self.mouth_upper_lip_top=self.p_79
self.mouth_upper_lip_bottom=self.p_90
self.mouth_right_corner=self.p_82
def get_vector(self):
result=self.angle()
top,bottom=self.thickness()
result.append(top)
result.append(bottom)
normalized= preprocessing.normalize(result).reshape(1,-1)
return normalized
def attrs(self):
return (
'p_76',
'p_79',
'p_82',
'p_85',
'p_90',
'p_94'
)
def counteract(self):
a = getattr(self, 'mouth_lower_lip_bottom')
b = getattr(self, 'mouth_lower_lip_top')
c = getattr(self, 'mouth_left_corner')
d = getattr(self, 'mouth_right_corner')
e = getattr(self, 'mouth_upper_lip_bottom')
f = getattr(self, 'mouth_upper_lip_top')
a['y'] += (c['y'] - b['y'])
b['y'] = c['y']
e['y'] = d['y']
f['y'] -= (e['y'] - d['y'])
return a, b, c, d, e, f
def thickness(self):
width=self.p_82['x']-self.p_76['x']
top=(self.p_90['y']-self.p_79['y'])/width
bottom=(self.p_85['y']-self.p_94['y'])/width
return top,bottom
def angle(self):
"""
利用余弦定理计算四个唇角
:return:
"""
a, b, c, d, e, f = self.counteract()
l1, l2, l3, l4, l5 = dist(a, b), dist(a, c), dist(a, d), dist(b, c), dist(b, d)
l6, l7, l8, l9, l10 = dist(e, f), dist(e, c), dist(e, d), dist(f, c), dist(f, d)
bottom_left_lip_angle = math.degrees(math.acos((l2**2 + l4**2 - l1**2)/(2*l2*l4)))
bottom_right_lip_angle = math.degrees(math.acos((l3**2 + l5**2 - l1**2)/(2*l3*l5)))
top_left_lip_angle = math.degrees(math.acos((l7**2 + l9**2 - l6**2)/(2*l7*l9)))
top_right_lip_angle = math.degrees(math.acos((l8**2 + l10**2 - l6**2)/(2*l8*l10)))
return [
(bottom_left_lip_angle + bottom_right_lip_angle) / 2,
(top_left_lip_angle + top_right_lip_angle) / 2
]
import math
import cv2
from face import Face_folder,NoFaces,TooManyFaces
from numpy import array
import argparse
import caffe
import numpy as np
from align import AlignDlib
import os
parser = argparse.ArgumentParser(description='face part classify')
parser.add_argument('-p', '--parts', help="input part")
if __name__ == '__main__':
args = parser.parse_args()
part = args.parts
caffe.set_mode_cpu()
net = caffe.LandMark('/opt/LAB/models/rel.prototxt','/opt/LAB/models/model.bin','/opt/LAB/models/shape_predictor_68_face_landmarks.dat')
url1 = "http://lab-1258538551.cos.ap-beijing.myqcloud.com/tmp/2019070404.jpg"
url2 = "http://lab-1258538551.cos.ap-beijing.myqcloud.com/tmp/2019070408.jpg"
imgpath1 = '100.jpg'
imgpath2 = '10.jpg'
img1 = cv2.imread(imgpath1)
img2 = cv2.imread(imgpath2)
v1 = array(Face_folder.get_vector(None,imgpath1,part,net))
v2 = array(Face_folder.get_vector(None,imgpath2,part,net))
print('v1',v1)
print('v2',v2)
# coding:utf-8
# author:Thierry
from base_part import BasePart
import math
from sklearn import preprocessing
class Nose(BasePart):
"""
鼻部模型
"""
CATEGORIES = ['normal', 'wide']
def __init__(self,**kwargs):
super(Nose,self).__init__(**kwargs)
self.left_eye_right_corner=self.p_64
self.nose_left=self.p_55
self.right_eye_left_corner=self.p_68
self.nose_right=self.p_59
def attrs(self):
return (
'p_54',
'p_55',
'p_59',
'p_64',
'p_68',
)
def get_vector(self):
v = [self._wing_root_ratio(),
self.wings_angle]
normalized= preprocessing.normalize(v).reshape(1,-1)
return normalized
def dotproduct(v1, v2):
return sum((a*b) for a, b in zip(v1, v2))
def length(v):
return math.sqrt(dotproduct(v, v))
def wings_angle(self):
'''
the angle between the wings
'''
v1 = [self.p_55['x'],self.p_55['y']] - [self.p_54['x'],self.p_54['y']]
v2 = [self.p_59['x'],self.p_59['y']] - [self.p_54['x'],self.p_54['y']]
return math.acos(dotproduct(v1, v2) / (length(v1) * length(v2)))
def _wing_root_ratio(self):
return self._wing_width() / self._root_width()
def _root_width(self):
"""
内眼角的宽度
"""
return self.left_eye_right_corner['x'] - self.right_eye_left_corner['x']
def _wing_width(self):
"""
鼻翼的宽度
"""
return self.nose_right['x'] - self.nose_left['x']
python main2.py --part eyebrow
#python main1.py --part eyebrow
#python main.py --part eye
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment