# -*- coding: utf-8 -*-
import cv2
import os
import dlib
import numpy as np
# 需要自己去网上下载 shape_predictor_68_face_landmarks.dat 文件
predictor_path = "./shape_predictor_68_face_landmarks.dat"
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(predictor_path)
# 手动设置裁剪框的大小, 分别表示left, top, right, bottom边框扩大率
rescaleBB = [1.185974, 1.0, 1.135600, 1.17]
def save_crop_images(file_list, save_root_path):
with open(file_list, 'r') as ins:
for image_path in ins:
image_path = image_path.strip('\n')
print '> crop image', image_path
img = cv2.imread(image_path)
dets = detector(img, 1)
if len(dets) == 0:
print '> Could not detect the face, skipping the image ...',image_path
continue
if len(dets) > 1:
print '> Process only the first detected face !'
detected_face = dets[0]
imcrop = cropByFaceDet(img, detected_face)
parent_dir, img_name = get_dir_name(image_path)
save_path = os.path.join(save_root_path, parent_dir)
if not os.path.exists(save_path):
os.makedirs(save_path)
cv2.imwrite(os.path.join(save_path, img_name), imcrop)
def get_dir_name(img_path):
tmp = img_path.split('/')
return tmp[-2], tmp[-1]
def cropImg(img, tlx, tly, brx, bry, rescale):
l = float(tlx)
t = float(tly)
ww = float(brx - l)
hh = float(bry - t)
# Approximate LM tight BB
h = img.shape[0]
w = img.shape[1]
# cv2.rectangle(img, (int(l), int(t)), (int(brx), int(bry)), \
# (0, 255, 255), 2)
cx = l + ww/2
cy = t + hh/2
tsize = max(ww, hh)/2
l = cx - tsize
t = cy - tsize
# Approximate expanded bounding box
bl = int(round(cx - rescale[0]*tsize))
bt = int(round(cy - rescale[1]*tsize))
br = int(round(cx + rescale[2]*tsize))
bb = int(round(cy + rescale[3]*tsize))
nw = int(br - bl)
nh = int(bb - bt)
imcrop = np.zeros((nh, nw, 3), dtype='uint8')
ll = 0
if bl < 0:
ll = -bl
bl = 0
rr = nw
if br > w:
rr = w+nw - br
br = w
tt = 0
if bt < 0:
tt = -bt
bt = 0
bbb = nh
if bb > h:
bbb = h+nh - bb
bb = h
imcrop[tt:bbb,ll:rr,:] = img[bt:bb,bl:br,:]
return imcrop
def cropByFaceDet(img, detected_face):
return cropImg(img,detected_face.left(),detected_face.top(),\
detected_face.right(),detected_face.bottom(), rescaleBB)
if __name__ == '__main__':
file_list = 'inputs.txt'
save_crop_images(file_list, 'crops')
扩充训练数据,对原始图片进行旋转,添加噪声等操作
使用多线程加快处理速度
# -*- coding: utf-8 -*-
import cv2
import os
import dlib
import numpy as np
import random
from math import *
from multiprocessing import Pool
# 需要自己去网上下载 shape_predictor_68_face_landmarks.dat 文件
predictor_path = "./shape_predictor_68_face_landmarks.dat"
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(predictor_path)
# 手动设置裁剪框的大小, 分别表示left, top, right, bottom边框扩大率
rescaleBB = [1.185974, 1.0, 1.135600, 1.17]
def save_crop_images(args):
image_path, save_root_path = args
print '> crop image', image_path
img = cv2.imread(image_path.strip('\n'))
dets = detector(img, 1)
if len(dets) == 0:
print '> Could not detect the face, skipping the image ...',image_path
return
if len(dets) > 1:
print '> Process only the first detected face !'
detected_face = dets[0]
parent_dir, img_name = get_dir_name(image_path)
save_path = os.path.join(save_root_path, parent_dir)
if not os.path.exists(save_path):
os.makedirs(save_path)
imcrop = cropByFaceDet(img, detected_face)
im_blur = blurImage(imcrop)
cv2.imwrite(os.path.join(save_path, img_name), imcrop)
cv2.imwrite(os.path.join(save_path, 'blur_'+img_name), im_blur)
for i in range(10):
degree = random.randrange(0,360,10)
im_rotate = rotateImage(imcrop, degree)
cv2.imwrite(os.path.join(save_path, 'rot_'+str(degree)+'_'+img_name), im_rotate)
for i in range(5):
degree = random.randrange(0,360,10)
im_rotate = rotateImage(im_blur, degree)
cv2.imwrite(os.path.join(save_path, 'rot_'+str(degree)+'_blur_'+img_name), im_rotate)
def get_dir_name(img_path):
tmp = img_path.split('/')
return tmp[-2], tmp[-1]
def cropImg(img, tlx, tly, brx, bry, rescale):
l = float(tlx)
t = float(tly)
ww = float(brx - l)
hh = float(bry - t)
# Approximate LM tight BB
h = img.shape[0]
w = img.shape[1]
# cv2.rectangle(img, (int(l), int(t)), (int(brx), int(bry)), \
# (0, 255, 255), 2)
cx = l + ww/2
cy = t + hh/2
tsize = max(ww, hh)/2
l = cx - tsize
t = cy - tsize
# Approximate expanded bounding box
bl = int(round(cx - rescale[0]*tsize))
bt = int(round(cy - rescale[1]*tsize))
br = int(round(cx + rescale[2]*tsize))
bb = int(round(cy + rescale[3]*tsize))
nw = int(br - bl)
nh = int(bb - bt)
imcrop = np.zeros((nh, nw, 3), dtype='uint8')
ll = 0
if bl < 0:
ll = -bl
bl = 0
rr = nw
if br > w:
rr = w+nw - br
br = w
tt = 0
if bt < 0:
tt = -bt
bt = 0
bbb = nh
if bb > h:
bbb = h+nh - bb
bb = h
imcrop[tt:bbb,ll:rr,:] = img[bt:bb,bl:br,:]
return imcrop
def cropByFaceDet(img, detected_face):
return cropImg(img,detected_face.left(),detected_face.top(),\
detected_face.right(),detected_face.bottom(), rescaleBB)
def rotateImage(img, degree=60):
rows, cols, channel = img.shape
# 为了旋转之后不裁剪原图,计算旋转后的尺寸
rows_new = int(cols*fabs(sin(radians(degree))) + rows*fabs(cos(radians(degree))))
cols_new= int(rows*fabs(sin(radians(degree))) + cols*fabs(cos(radians(degree))))
# 旋转60度的仿射矩阵
M = cv2.getRotationMatrix2D((cols/2, rows/2), degree, 1)
M[0,2] += (cols_new - cols)/2
M[1,2] += (rows_new - rows)/2
im = cv2.warpAffine(img, M, (cols_new, rows_new), borderValue=(255,255,255)) # 旋转60度,得到新图片
return im
def blurImage(img):
return cv2.GaussianBlur(img, (5,5), 0)
if __name__ == '__main__':
file_list = 'inputs.txt'
images_list = open(file_list, 'r').readlines()
# for arg in zip(images_list, 'crop'):
# save_crop_images(arg)
pool = Pool(5)
pool.map(save_crop_images, zip(images_list,['crop',]*len(images_list)))
pool.close()
pool.join()
print 'end...'
# cv2.waitKey(0)
# cv2.destroyAllWindows()