python︱利用dlib和opencv实现简单换脸、人脸对齐、关键点定位与画图

这是一个利用dlib进行关键点定位 + opencv处理的人脸对齐、换脸、关键点识别的小demo。原文来自于《Switching Eds: Face swapping with Python, dlib, and OpenCV》 该博文的github地址中有所有的code。这边我将我抽取的code放在自己的github之中,可以来这下载: https://github.com/mattzheng/Face_Swapping

有人将其进行中文翻译也有将其进行一定改编有以下两个案例:

变脸贴图:

从这几张:

组合变成这几张:

因为原文里面内容丰富,我觉得可以提取出很多有用的小模块,于是乎: .

提取一:关键点定位与画图

import cv2
import dlib
import numpy
import sys
import matplotlib.pyplot as plt
SCALE_FACTOR = 1 # 图像的放缩比

def read_im_and_landmarks(fname):
    im = cv2.imread(fname, cv2.IMREAD_COLOR)
    im = cv2.resize(im, (im.shape[1] * SCALE_FACTOR,
                         im.shape[0] * SCALE_FACTOR))
    s = get_landmarks(im)

    return im, s

def annotate_landmarks(im, landmarks):
    '''
    人脸关键点,画图函数
    '''
    im = im.copy()
    for idx, point in enumerate(landmarks):
        pos = (point[0, 0], point[0, 1])
        cv2.putText(im, str(idx), pos,
                    fontFace=cv2.FONT_HERSHEY_SCRIPT_SIMPLEX,
                    fontScale=0.4,
                    color=(0, 0, 255))
        cv2.circle(im, pos, 3, color=(0, 255, 255))
    return im

然后实践就是载入原图:

im1, landmarks1 = read_im_and_landmarks('02.jpg')  # 底图
im1 = annotate_landmarks(im1, landmarks1)

%matplotlib inline
plt.subplot(111)
plt.imshow(im1)

.

提取二:人脸对齐

需要一张模板图来作为靠拢的对象图。

# 人脸对齐函数
def face_Align(Base_path,cover_path):
    im1, landmarks1 = read_im_and_landmarks(Base_path)  # 底图
    im2, landmarks2 = read_im_and_landmarks(cover_path)  # 贴上来的图

    if len(landmarks1) == 0 & len(landmarks2) == 0 :
        raise ImproperNumber("Faces detected is no face!")
    if len(landmarks1) > 1 & len(landmarks2) > 1 :
        raise ImproperNumber("Faces detected is more than 1!")

    M = transformation_from_points(landmarks1[ALIGN_POINTS],
                                   landmarks2[ALIGN_POINTS])
    warped_im2 = warp_im(im2, M, im1.shape)
    return warped_im2

这里的步骤是:

  • 提取模板图、对齐图的landmarks;
  • 通过transformation_from_points计算对齐图向模板图的转移矩阵M,变换矩阵是根据以下公式计算出来的;
  • warp_im,将 im2 的掩码进行变化,使之与 im1 相符

实践的话就是:

FEATHER_AMOUNT = 19  # 匹配的时候,特征数量,现在是以11个点为基准点  11  15  17 

Base_path = '01.jpg'
cover_path = '02.jpg'
warped_mask = face_Align(Base_path,cover_path)

.

提取三:换脸

主要函数:

def Switch_face(Base_path,cover_path):
    im1, landmarks1 = read_im_and_landmarks(Base_path)  # 底图
    im2, landmarks2 = read_im_and_landmarks(cover_path)  # 贴上来的图

    if len(landmarks1) == 0 & len(landmarks2) == 0 :
        raise ImproperNumber("Faces detected is no face!")
    if len(landmarks1) > 1 & len(landmarks2) > 1 :
        raise ImproperNumber("Faces detected is more than 1!")

    M = transformation_from_points(landmarks1[ALIGN_POINTS],
                                   landmarks2[ALIGN_POINTS])
    mask = get_face_mask(im2, landmarks2)
    warped_mask = warp_im(mask, M, im1.shape)
    combined_mask = numpy.max([get_face_mask(im1, landmarks1), warped_mask],
                              axis=0)
    warped_im2 = warp_im(im2, M, im1.shape)
    warped_corrected_im2 = correct_colours(im1, warped_im2, landmarks1)

    output_im = im1 * (1.0 - combined_mask) + warped_corrected_im2 * combined_mask
    return output_im

主要步骤:

  • 提取模板图、对齐图的landmarks;
  • M,通过transformation_from_points计算对齐图向模板图的转移矩阵M;
matrix([[   0.62876962,    0.20978991, -101.32973923],
        [  -0.20978991,    0.62876962,   79.11235991],
        [   0.        ,    0.        ,    1.        ]])
  • mask,得到基于对齐图的掩膜,get_face_mask函数,获取 im2 的面部掩码,mask长成这样:
  • warped_mask ,warp_im函数,将 im2 的掩码进行变化,使之与 im1 相符,跟上面的mask张一样(一个鼻子)
  • combined_mask ,将二者的掩码进行连通(跟warped_mask 长一样)
  • warped_im2 ,warp_im函数,第二次,将第二幅图像调整到与第一幅图像相符(对齐图片,斜了点)
  • warped_corrected_im2 ,correct_colours函数,将 im2 的皮肤颜色进行修正,使其和 im1 的颜色尽量协调(类似下图)
  • output_im 组合图像,获得结果

实践:

FEATHER_AMOUNT = 23

Base_path = '03.jpg'
cover_path = '02.jpg'
output_im = Switch_face(Base_path,cover_path)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏落影的专栏

iOS开发-OpenGLES进阶教程3

教程 OpenGLES入门教程1-Tutorial01-GLKit OpenGLES入门教程2-Tutorial02-shader入门 OpenGLES入门...

3327
来自专栏AI研习社

问答 | 对于输入图像为 180 × 180 pixel 的卷积神经网络,我应该取多少个训练实例比较合适?

问:对于输入图像为 180 × 180 pixel 的卷积神经网络,我应该取多少个训练实例比较合适?

543
来自专栏MixLab科技+设计实验室

【图像处理篇】自动识别手写数字web应用05

往期的4篇已经把Docker+Keras+Flask+JS的全栈+深度学习介绍完整了: 自己动手做一个识别手写数字的web应用01 自己动手做一个识别手写数字的...

3226
来自专栏Java与Android技术栈

模拟油画和铅笔画的滤镜效果

然后使用油画风格的滤镜OilPaintFilter看看效果,OilPaintFilter的使用方式就一句话:)

511
来自专栏IT派

python代码实现图片噪声去除

今天来给大家分享下怎么做图片的噪声去除。平时其实大家上网都能遇到这样的场景,就是输入讨厌验证码,怎么都输不对。验证码现在可以说是千奇百怪、分外妖娆,为啥要做成这...

833
来自专栏偏前端工程师的驿站

CSS3魔法堂:CSS3滤镜及Canvas、SVG和IE滤镜替代方案详解

一、前言                                  IE特有的滤镜常常作为CSS3各种新特性的降级处理补充,而Adobe转向HTML5后...

20610
来自专栏小鹏的专栏

tf12: 判断男声女声

本帖训练一个简单的神经网络模型,用来判断声音是男是女。 本帖数据集取自voice-gender项目,这个项目使用了n种分类模型,并比较了准确率,但是它没有使...

2049
来自专栏量子位

AI跟Bob Ross学画画,杂乱色块秒变风景油画 | PyTorch教程+代码

王新民 编译整理 量子位 出品 | 公众号 QbitAI 正在研究机器学习的全栈码农Dendrick Tan在博客上发布了一份教程+代码:用PyTorch实现将...

3245
来自专栏walterlv - 吕毅的博客

分享一个算法,计算能在任何背景色上清晰显示的前景色

发布于 2017-11-04 14:51 更新于 2018-02...

381
来自专栏calmound

ZOJ 3728 Collision

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5074 题意:两个圆,小圆为实体,具有碰...

2655

扫码关注云+社区