hylee's picture
init
d84f784
import cv2
import os, glob, csv, shutil
import numpy as np
import dlib
import math
from shapely.geometry import Point
from shapely.geometry import Polygon
import sys
def getfeats(featpath):
trans_points = np.empty([68,2],dtype=np.int64)
with open(featpath, 'r') as csvfile:
reader = csv.reader(csvfile, delimiter=' ')
for ind,row in enumerate(reader):
trans_points[ind,:] = row
return trans_points
def getinternal(lm1,lm2):
lminternal = []
if abs(lm1[1]-lm2[1]) > abs(lm1[0]-lm2[0]):
if lm1[1] > lm2[1]:
tmp = lm1
lm1 = lm2
lm2 = tmp
for y in range(lm1[1]+1,lm2[1]):
x = int(round(float(y-lm1[1])/(lm2[1]-lm1[1])*(lm2[0]-lm1[0])+lm1[0]))
lminternal.append((x,y))
else:
if lm1[0] > lm2[0]:
tmp = lm1
lm1 = lm2
lm2 = tmp
for x in range(lm1[0]+1,lm2[0]):
y = int(round(float(x-lm1[0])/(lm2[0]-lm1[0])*(lm2[1]-lm1[1])+lm1[1]))
lminternal.append((x,y))
return lminternal
def mulcross(p,x_1,x):#p-x_1,x-x_1
vp = [p[0]-x_1[0],p[1]-x_1[1]]
vq = [x[0]-x_1[0],x[1]-x_1[1]]
return vp[0]*vq[1]-vp[1]*vq[0]
def shape_to_np(shape, dtype="int"):
# initialize the list of (x, y)-coordinates
coords = np.zeros((shape.num_parts, 2), dtype=dtype)
# loop over all facial landmarks and convert them
# to a 2-tuple of (x, y)-coordinates
for i in range(0, shape.num_parts):
coords[i] = (shape.part(i).x, shape.part(i).y)
# return the list of (x, y)-coordinates
return coords
def get_68lm(imgfile,savepath5,savepath68, detector, predictor):
image = cv2.imread(imgfile)
rgbImg = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
rects = detector(rgbImg, 1)
for (i, rect) in enumerate(rects):
landmarks = predictor(rgbImg, rect)
landmarks = shape_to_np(landmarks)
f = open(savepath68,'w')
for i in range(len(landmarks)):
lm = landmarks[i]
print(lm[0], lm[1], file=f)
f.close()
ff = open(savepath5, 'w')
lm = (landmarks[36]+landmarks[39])/2
print(int(lm[0]), int(lm[1]), file=ff)
lm = (landmarks[45]+landmarks[42])/2
print(int(lm[0]), int(lm[1]), file=ff)
lm = landmarks[30]
print(lm[0], lm[1], file=ff)
lm = landmarks[48]
print(lm[0], lm[1], file=ff)
lm = landmarks[54]
print(lm[0], lm[1], file=ff)
ff.close()
def get_partmask(imgfile,part,lmpath,savefile):
img = cv2.imread(imgfile)
mask = np.zeros(img.shape, np.uint8)
lms = getfeats(lmpath)
if os.path.exists(savefile):
return
if part == 'nose':
# 27,31....,35 -> up, left, right, lower5 -- eight points
up = [int(round(1.2*lms[27][0]-0.2*lms[33][0])),int(round(1.2*lms[27][1]-0.2*lms[33][1]))]
lower5 = [[0,0]]*5
for i in range(31,36):
lower5[i-31] = [int(round(1.1*lms[i][0]-0.1*lms[27][0])),int(round(1.1*lms[i][1]-0.1*lms[27][1]))]
ratio = 2.5
left = [int(round(ratio*lower5[0][0]-(ratio-1)*lower5[1][0])),int(round(ratio*lower5[0][1]-(ratio-1)*lower5[1][1]))]
right = [int(round(ratio*lower5[4][0]-(ratio-1)*lower5[3][0])),int(round(ratio*lower5[4][1]-(ratio-1)*lower5[3][1]))]
loop = [up,left,lower5[0],lower5[1],lower5[2],lower5[3],lower5[4],right]
elif part == 'eyel':
height = max(lms[41][1]-lms[37][1],lms[40][1]-lms[38][1])
width = lms[39][0]-lms[36][0]
ratio = 0.1
gap = int(math.ceil(width*ratio))
ratio2 = 0.6
gaph = int(math.ceil(height*ratio2))
ratio3 = 1.5
gaph2 = int(math.ceil(height*ratio3))
upper = [[lms[17][0]-2*gap,lms[17][1]],[lms[17][0]-2*gap,lms[17][1]-gaph],[lms[18][0],lms[18][1]-gaph],[lms[19][0],lms[19][1]-gaph],[lms[20][0],lms[20][1]-gaph],[lms[21][0]+gap*2,lms[21][1]-gaph]]
lower = [[lms[39][0]+gap,lms[40][1]+gaph2],[lms[40][0],lms[40][1]+gaph2],[lms[41][0],lms[41][1]+gaph2],[lms[36][0]-2*gap,lms[41][1]+gaph2]]
loop = upper + lower
loop.reverse()
elif part == 'eyer':
height = max(lms[47][1]-lms[43][1],lms[46][1]-lms[44][1])
width = lms[45][0]-lms[42][0]
ratio = 0.1
gap = int(math.ceil(width*ratio))
ratio2 = 0.6
gaph = int(math.ceil(height*ratio2))
ratio3 = 1.5
gaph2 = int(math.ceil(height*ratio3))
upper = [[lms[22][0]-2*gap,lms[22][1]],[lms[22][0]-2*gap,lms[22][1]-gaph],[lms[23][0],lms[23][1]-gaph],[lms[24][0],lms[24][1]-gaph],[lms[25][0],lms[25][1]-gaph],[lms[26][0]+gap*2,lms[26][1]-gaph]]
lower = [[lms[45][0]+2*gap,lms[46][1]+gaph2],[lms[46][0],lms[46][1]+gaph2],[lms[47][0],lms[47][1]+gaph2],[lms[42][0]-gap,lms[42][1]+gaph2]]
loop = upper + lower
loop.reverse()
elif part == 'mouth':
height = lms[62][1]-lms[51][1]
width = lms[54][0]-lms[48][0]
ratio = 1
ratio2 = 0.2#0.1
gaph = int(math.ceil(ratio*height))
gapw = int(math.ceil(ratio2*width))
left = [(lms[48][0]-gapw,lms[48][1])]
upper = [(lms[i][0], lms[i][1]-gaph) for i in range(48,55)]
right = [(lms[54][0]+gapw,lms[54][1])]
lower = [(lms[i][0], lms[i][1]+gaph) for i in list(range(54,60))+[48]]
loop = left + upper + right + lower
loop.reverse()
pl = Polygon(loop)
for i in range(mask.shape[0]):
for j in range(mask.shape[1]):
if part != 'mouth' and part != 'jaw':
p = [j,i]
flag = 1
for k in range(len(loop)):
if mulcross(p,loop[k],loop[(k+1)%len(loop)]) < 0:#y downside... >0 represents counter-clockwise, <0 clockwise
flag = 0
break
else:
p = Point(j,i)
flag = pl.contains(p)
if flag:
mask[i,j] = [255,255,255]
if not os.path.exists(os.path.dirname(savefile)):
os.mkdir(os.path.dirname(savefile))
cv2.imwrite(savefile,mask)
if __name__ == '__main__':
imgfile = 'example/img_1701_aligned.png'
lmfile = 'example/img_1701_aligned_68lm.txt'
get_68lm(imgfile,lmfile)
for part in ['eyel','eyer','nose','mouth']:
savepath = 'example/img_1701_aligned_'+part+'mask.png'
get_partmask(imgfile,part,lmfile,savepath)