tools.py注释
import os
import cv2
import torch
import numpy as np
from PIL import Image
from dlib import cnn_face_detection_model_v1 as face_detect_model
def center_crop(im, length):
w, h = im.size
left = w//2 - length//2
right = w//2 + length//2
top = h//2 - length//2
bottom = h//2 + length//2
return im.crop((left, top, right, bottom)), (left, top)
def remove_boundary(img):
"""
Remove boundary artifacts that FAL causes.
"""
w, h = img.size
left = w//80
top = h//50
right = w*79//80
bottom = h*24//25
return img.crop((left, top, right, bottom))
def resize_shorter_side(img, min_length):
"""
Resize the shorter side of img to min_length while
preserving the aspect ratio.
"""
ow, oh = img.size
mult = 8
if ow < oh:
if ow == min_length and oh % mult == 0:
return img, (ow, oh)
w = min_length
h = int(min_length * oh / ow)
else:
if oh == min_length and ow % mult == 0:
return img, (ow, oh)
h = min_length
w = int(min_length * ow / oh)
return img.resize((w, h), Image.BICUBIC), (w, h)
def flow_resize(flow, sz):
oh, ow, _ = flow.shape
w, h = sz
u_ = cv2.resize(flow[:,:,0], (w, h))
v_ = cv2.resize(flow[:,:,1], (w, h))
u_ *= w / float(ow)
v_ *= h / float(oh)
return np.dstack((u_,v_))
def warp(im, flow, alpha=1, interp=cv2.INTER_CUBIC):
height, width, _ = flow.shape
cart = np.dstack(np.meshgrid(np.arange(width), np.arange(height)))
pixel_map = (cart + alpha * flow).astype(np.float32)
warped = cv2.remap(
im,
pixel_map[:, :, 0],
pixel_map[:, :, 1],
interp,
borderMode=cv2.BORDER_REPLICATE)
return warped
cnn_face_detector = None
#人脸检测
def face_detection(
img_path,
verbose=False,
model_file='utils/dlib_face_detector/mmod_human_face_detector.dat'):
"""
Detects faces using dlib cnn face detection, and extend the bounding box
to include the entire face.
"""
#利用双线性插值缩小图片
def shrink(img, max_length=2048):
ow, oh = img.size
if max_length >= max(ow, oh):
return img, 1.0
if ow > oh:
mult = max_length / ow
else:
mult = max_length / oh
w = int(ow * mult)
h = int(oh * mult)
return img.resize((w, h), Image.BILINEAR), mult
# 函数img.resize((width, height),Image.ANTIALIAS)
# 第二个参数:
# Image.NEAREST :低质量
# Image.BILINEAR:双线性
# Image.BICUBIC :三次样条插值
# Image.ANTIALIAS:高质量
global cnn_face_detector#global声明全局变量,是在函数内部使用,当你想在函数内部给一个在外部定义的变量赋值时就要用global先声明一下
if cnn_face_detector is None:
cnn_face_detector = face_detect_model(model_file)#调用训练好的model进行人脸检测
img = Image.open(img_path).convert('RGB')
w, h = img.size
img_shrinked, mult = shrink(img)
im = np.asarray(img_shrinked)
if len(im.shape) != 3 or im.shape[2] != 3:#?
return []
crop_ims = []
dets = cnn_face_detector(im, 0)
for k, d in enumerate(dets): #rect
top = d.rect.top() / mult
bottom = d.rect.bottom() / mult
left = d.rect.left() / mult
right = d.rect.right() / mult
wid = right - left
left = max(0, left - wid // 2.5)
top = max(0, top - wid // 1.5)
right = min(w - 1, right + wid // 2.5)
bottom = min(h - 1, bottom + wid // 2.5)
if d.confidence > 1:
if verbose:
print("%d-th face detected: (%d, %d, %d, %d)" %
(k, left, top, right, bottom))
crop_im = img.crop((left, top, right, bottom))
crop_ims.append((crop_im, (left, top, right, bottom)))
return crop_ims
def mkdirs(paths):#文件夹
if isinstance(paths, list) and not isinstance(paths, str):#isinstance() 函数来判断一个对象是否是一个已知的类型,
# 类似 type(),type() 不会认为子类是一种父类类型,不考虑继承关系。
# isinstance() 会认为子类是一种父类类型,考虑继承关系
#如果对象的类型与参数二的类型(classinfo)相同则返回True,否则返回False
#是list而不是str
for path in paths:
mkdir(path)
else:
mkdir(paths)
def mkdir(path):#创建文件
if not os.path.exists(path):#不存在该目录
os.makedirs(path)#递归创建目录