def getindices(ftl_face, sq, padw=padw, detw=detw): # get mask region using boundary, chin landmarks and nose landmarks # boundary region: left -> right, upper -> lower WH = ftl_face.shape[0] boundary = sq.align(detw) left, right, upper, lower = np.array(boundary) + padw indices = np.array([(x, y) for x in range(left, right) for y in range(upper, lower)]) # get landmarks of frontalized face det = detector(ftl_face, 1)[0] shape = predictor(ftl_face, det) ldmk = np.asarray([( shape.part(n).x, shape.part(n).y, ) for n in range(shape.num_parts)], np.float32) chin_xp, chin_fp = ldmk[3:14, 0], ldmk[3:14, 1] chin_line = np.interp(np.arange(WH), chin_xp, chin_fp) nose_xp, nose_fp = ldmk[31:36, 0], ldmk[31:36, 1] nose_line = np.interp(np.arange(WH), nose_xp, nose_fp) # filter the position which is out of chin line and nose line check = np.logical_and(indices[:, 1] < chin_line[indices[:, 0]], indices[:, 1] > nose_line[indices[:, 0]]) return indices[check.nonzero()]
def process_proxy(rsize, ksize=(17, 17), sigma=1e2, k=1): # process teeth proxies to get their landmarks and high-pass filters F, S = {}, {} for mode in ('upper', 'lower'): pxyfile, = glob.glob('reference/proxy_%s_*.png' % mode) img = cv2.imread(pxyfile) # detect face and landmarks det = detector(img, 1)[0] shape = predictor(img, det) ldmk = np.asarray([(shape.part(n).x, shape.part(n).y) for n in range(48, shape.num_parts)], np.float32) # normalize landmarks origin = np.array([det.left(), det.top()]) size = np.array([det.width(), det.height()]) ldmk = (ldmk - origin) / size # restrained in [0, 0] ~ [1, 1] # resize texture txtr = img[origin[1]:origin[1] + size[1], origin[0]:origin[0] + size[0]] txtr = cv2.resize(txtr, (rsize, rsize)) # generate hgih-pass filter (only one channel) norm_txtr = txtr.astype(np.float) / 255 smooth_txtr = cv2.GaussianBlur(txtr, ksize, sigma) / 255 filt = (norm_txtr - smooth_txtr) * k + 0.5 filt[filt < 0] = 0 filt[filt > 1] = 1 # add landmarks and filter into dict S and F respectively F[mode] = filt S[mode] = ldmk return F, S
def util2(mp4_path, save_path, startfr=0, endfr=None): # frontalize every frame from a video and save to somewhere from new_facefrontal import facefrontal cap = cv2.VideoCapture(mp4_path) cap.set(cv2.CAP_PROP_POS_FRAMES, startfr) cnt = startfr endfr = cap.get(cv2.CAP_PROP_FRAME_COUNT) if endfr is None else endfr print('Start preprocessing...') while cap.isOpened(): if cnt == endfr: break print("%s: %04d/%04d" % (save_path, cnt + 1, endfr)) cnt += 1 _, img = cap.read() img = facefrontal(img, detector, predictor) if img is None: continue dets = detector(img, 1) if len(dets) != 1: continue cv2.imwrite('%s%04d.png' % (save_path, cnt), img) print('Done')
def facefrontal(img, detector, predictor): ''' ### parameters img: original image to be frontalized \\ detector: face detector generated by dlib.get_frontal_face_detector() \\ predictor: landmark extractor generated by dlib.shape_predictor(...) ### retval newimg: (320, 320, 3), frontalized image ''' dets = detector(img, 1) # only 0 or 1 face in each frame if (len(dets) == 0): return None det = dets[0] shape = predictor(img, det) p2d = np.asarray([( shape.part(n).x, shape.part(n).y, ) for n in range(shape.num_parts)], np.float32) rawfront, symfront = fronter.frontalization(img, det, p2d) newimg = symfront.astype('uint8') # cv2.imshow('newimg', newimg) # cv2.waitKey(0) return newimg
def preprocess(mp4_path, save_path, rsize, startfr=0, endfr=None): ''' ### parameters mp4_path: path of mp4 file \\ sq: Squre instance which defines the boundary of lower face texture rsize: width (height) of clipped texture in every target video frame ### retval savepath: path that saves landmarks and textures ''' landmarks = [] textures = [] cap = cv2.VideoCapture(mp4_path) cap.set(cv2.CAP_PROP_POS_FRAMES, startfr) cnt = startfr endfr = cap.get(cv2.CAP_PROP_FRAME_COUNT) if endfr is None else endfr print('Start preprocessing...') while cap.isOpened(): if cnt == endfr: break print("%04d/%04d" % (cnt, endfr - 1)) cnt += 1 ret, img_ = cap.read() img = facefrontal(img_, detector, predictor) if img is None: continue dets = detector(img, 1) if len(dets) != 1: continue det = dets[0] shape = predictor(img, det) ldmk = np.asarray([(shape.part(n).x, shape.part(n).y) for n in range(48, shape.num_parts)], np.float32) # normalization according to det.shape & reshape into 40-D features origin = np.array([det.left(), det.top()]) size = np.array([det.width(), det.height()]) ldmk = (ldmk - origin) / size # restrained in [0, 0] ~ [1, 1] # validate landmarks using statistics in the dataset if np.sum(np.logical_or(ldmk < boundL, ldmk > boundU)) > 0: continue landmarks.append(ldmk.flatten()) # resize texture into a square txtr = img[origin[1]:origin[1] + size[1], origin[0]:origin[0] + size[0]] txtr = cv2.resize(txtr, (rsize, rsize)) # mask & inpaint for clothes region txtr = mask_inpaint(txtr) textures.append(txtr) landmarks = np.array(landmarks) textures = np.array(textures) # filter frames which are not locally smooth approx = (landmarks[2:, :] + landmarks[:-2, :]) / 2 L2 = np.linalg.norm(landmarks[1:-1, :] - approx, ord=2, axis=1) check = (L2 <= 0.1).nonzero() landmarks = landmarks[1:-1][check].reshape((-1, 20, 2)) textures = textures[1:-1][check] np.savez(save_path, landmarks=landmarks, textures=textures)