1、获取人脸的roi的mask区域,主要通过获取边缘点的凸包,然后填充凸边缘即可达到相应的mask,其代码代码如下:
def mask_from_points(size, points, erode_flag=1):
#其中points是(68,2)的检测到人脸关键点坐标矩阵
radius = 10 # 腐蚀的核大小
kernel = np.ones((radius, radius), np.uint8)
mask = np.zeros(size, np.uint8)
cv2.fillConvexPoly(mask, cv2.convexHull(points), 255)
if erode_flag:
mask = cv2.erode(mask, kernel, iterations=1)
return mask
2、当进行一些图像融合的时候,需要解决两张图像之间的颜色的差距,这个可以使用类似局部颜色矫正的方法来进行两张图的颜色合并,示例代码如下:
def correct_colours(im1, im2, landmarks1):
#这里使用左右眼睛的中心距离作为高斯滤波的核大小。其中这个核要越大越好。这样子就不容易受边缘的过渡影响。
COLOUR_CORRECT_BLUR_FRAC = 0.75
LEFT_EYE_POINTS = list(range(42, 48))
RIGHT_EYE_POINTS = list(range(36, 42))
blur_amount = COLOUR_CORRECT_BLUR_FRAC * np.linalg.norm(
np.mean(landmarks1[LEFT_EYE_POINTS], axis=0) -
np.mean(landmarks1[RIGHT_EYE_POINTS], axis=0))
blur_amount = int(blur_amount)
if blur_amount % 2 == 0:
blur_amount += 1
blur_amount=61
#其中这里的im1_blur、im2_blur就相当于掩膜
im1_blur = cv2.GaussianBlur(im1, (blur_amount, blur_amount), 0)
im2_blur = cv2.GaussianBlur(im2, (blur_amount, blur_amount), 0)
# 避免出现除于0的情况
im2_blur = im2_blur.astype(int)
im2_blur += 128 * (im2_blur <= 1)
result = im2.astype(np.float64) * im1_blur.astype(np.float64) / im2_blur.astype(np.float64)
result = np.clip(result, 0, 255).astype(np.uint8)
return result
再上面的roi颜色融合完成后,后面就可以把这个roi进行贴图到原图上可以使用opencv自带的seamlessClone函数来平滑边缘。其代码为:
def fast_face_swap(self, dst_img, dst_face_rect: dlib.rectangle):
success = 1
failed = 0
dst_points = face_points_detection(dst_img, dst_face_rect)
if not check_points(dst_img, dst_points):
logging.error("part of Face")
return (failed, dst_img)
dst_mask = mask_from_points(
dst_img.shape[:2], dst_points, erode_flag=1)
r = cv2.boundingRect(dst_points)
(x, y, w, h) = r
if y + h > dst_img.shape[0] or x + w > dst_img.shape[1]:
return (failed, dst_img)
dst_roi = dst_img[y:y + h, x:x + w]
dst_mask = dst_mask[y:y + h, x:x + w]
dst_points -= (x, y)
dst_only_face = apply_mask(dst_roi, dst_mask)
warped_src_face = warp_image_3d(
self.src_only_face, self.src_points[:48], dst_points[:48], dst_roi.shape[:2])
#进行对应roi区域进行颜色融合
new_src_face = correct_colours(
dst_only_face, warped_src_face, dst_points)
center = (int(x + w / 2), int(y + h / 2))
#进行roi区域贴合到原图上
output = cv2.seamlessClone(
new_src_face, dst_img, dst_mask, center, cv2.NORMAL_CLONE)
return (success, output)
其中warp_image_3d()函数主要是通过把48个人脸外围点包围成的roi进行分割成很多小的三角形。然后对每一个三角形区域进行求其旋转矩阵,对每个小块进行仿射变换,最后把原图变换成跟模板图一样的形状区域。
注意:其进行颜色融合的主要方法是参考了:局部颜色矫正的算法(Local Color Correction Using Non-Linear Masking)
3、MSL移动最小二乘变形算法变形图像: