Python图像处理【24】面部变形(face morphing)

面部变形

    • 0. 前言
    • 1. 网格变形算法
    • 2. 实现面部变形
    • 小结
    • 系列链接

0. 前言

面部变形 (face morphing) 的目的是在计算图像中两个面部之间的平均值,它并不是计算两张图像的平均值,而是计算面部区域的平均值。可以将该过程分解为以下两步:

  • 对齐两个面部图像(使用仿射变换)
  • 应用交叉溶解(利用 alpha 融合执行图像线性组合)创建输出图像

但是该方法通常无法正确应用,我们通常需要使用(局部)特征匹配。例如,要执行面部变形,可以在关键点之间(例如鼻子与鼻子,眼睛与眼睛)进行匹配,这称为局部(非参数)扭曲。

1. 网格变形算法

使用网格变形算法实现面部变形的步骤如下:

  • 定义对应关系:面部变形算法使用两个面部共同的一组特征点将源面部转换为目标面部,这些特征点可以手动创建,也可以使用面部特征检测算法自动生成的面部特征点,我们需要找到对齐面部之间的点对应关系(例如,使用两个面部上相同的关键点顺序以一致的方式标记特征点)
  • Delaunay 三角剖分:需要提供用于变形的点的三角剖分;Delaunay 三角剖分不会输出过细的三角形
  • 计算中间(变形)面部:在计算整个变形序列之前,计算源和目的地图像的中间面部,这需要计算平均形状,即两个面部中每个关键点位置的平均值
  • 计算变形图像 M 中特征点的位置:对于源图像中的每个三角形,计算将三角形的三个角映射到变形图像中三角形的对应角的仿射变换,然后使用刚刚计算的仿射变换将三角形内的所有像素变换到变形图像
  • 最后,使用 alpha 混合算法将两个图像混合在一起,得到最终变形图像

面部标志 (Facial landmarks) 是面部关键点/特征,用于标记/识别关键面部属性,并定位/表示面部的突出区域,如左/右眼、左/右眉毛、鼻子、嘴巴和下颌线等。面部关键点检测已经成功地应用于面部对齐、头部姿态估计、面部交换、眨眼检测等。

2. 实现面部变形

(1) 首先导入所有必需的库:

from scipy.spatial import Delaunay
from skimage.io import imread
import scipy.misc
import cv2
import dlib
import numpy as np
from matplotlib import pyplot as plt

(2) 使用 dlib 库的面部检测器和形状预测器,通过实现函数 extract_landmarks() 自动计算面部关键点。该函数获取输入图像,使用布尔标志指示是否添加边界点,并需要 dlib 库的 shape_predictor 模型的路径(即 dat 文件的路径,该文件是序列化的预训练的面部特征点提取器模型)。函数使用 dlibshape_predictor() 函数(内部使用回归树集合)来估算 68 个关键点的位置 (x,y)

def extract_landmarks(img, add_boundary_points=True, predictor_path = 'models/shape_predictor_68_face_landmarks.dat'):detector = dlib.get_frontal_face_detector()predictor = dlib.shape_predictor(predictor_path)try:#points = stasm.search_single(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY))dets = detector(img, 1)points = np.zeros((68, 2))for k, d in enumerate(dets):print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(k, d.left(), d.top(), d.right(), d.bottom()))# Get the landmarks/parts for the face in box d.shape = predictor(img, d)for i in range(68):points[i, 0] = shape.part(i).xpoints[i, 1] = shape.part(i).yexcept Exception as e:print('Failed finding face points: ', e)return []points = points.astype(np.int32)return points

可以在 GitCode 中下载 shape_predictor_68_face_landmarks.dat 文件。

(3) 使用函数 extract_landmarks() 提取源和目标面部图像的关键点:

src_path = '1.png'
dst_path = '2.png'src_img = imread(src_path)
dst_img = imread(dst_path)src_points = extract_landmarks(src_img)
dst_points = extract_landmarks(dst_img)

(4) 使用函数 weighted_average_points() 计算两组点和两个图像的 alpha 混合结果:

def weighted_average_points(start_points, end_points, percent=0.5):if percent <= 0:return end_pointselif percent >= 1:return start_pointselse:return np.asarray(start_points*percent + end_points*(1-percent), np.int32)

(5) 实现函数 bilinear_interpolate() 对每个图像通道进行插值:

def bilinear_interpolate(img, coords):int_coords = np.int32(coords)x0, y0 = int_coordsdx, dy = coords - int_coords# 4 Neighour pixelsq11 = img[y0, x0]q21 = img[y0, x0+1]q12 = img[y0+1, x0]q22 = img[y0+1, x0+1]btm = q21.T * dx + q11.T * (1 - dx)top = q22.T * dx + q12.T * (1 - dx)inter_pixel = top * dy + btm * (1 - dy)return inter_pixel.T

(6) 实现函数 get_grid_coordinates() 生成输入点感兴趣区域 (region of interest, ROI) 内所有可能 (x,y) 网格坐标的数组:

def get_grid_coordinates(points):xmin = np.min(points[:, 0])xmax = np.max(points[:, 0]) + 1ymin = np.min(points[:, 1])ymax = np.max(points[:, 1]) + 1return np.asarray([(x, y) for y in range(ymin, ymax)for x in range(xmin, xmax)], np.uint32)

(7) 实现函数 process_warp()result_imgROI 内扭曲 src_img 中的每个三角形:

def process_warp(src_img, result_img, tri_affines, dst_points, delaunay):roi_coords = get_grid_coordinates(dst_points)# indices to vertices. -1 if pixel is not in any triangleroi_tri_indices = delaunay.find_simplex(roi_coords)for simplex_index in range(len(delaunay.simplices)):coords = roi_coords[roi_tri_indices == simplex_index]num_coords = len(coords)out_coords = np.dot(tri_affines[simplex_index], np.vstack((coords.T, np.ones(num_coords))))x, y = coords.Tresult_img[y, x] = bilinear_interpolate(src_img, out_coords)return None

(8) 实现生成器函数 gen_triangular_affine_matrics() 计算从 dest_pointssrc_points 的每个三角形顶点 (x,y) 的仿射变换矩阵:

def get_triangular_affine_matrices(vertices, src_points, dest_points):ones = [1, 1, 1]for tri_indices in vertices:src_tri = np.vstack((src_points[tri_indices, :].T, ones))dst_tri = np.vstack((dest_points[tri_indices, :].T, ones))mat = np.dot(src_tri, np.linalg.inv(dst_tri))[:2, :]yield mat

(9) 实现函数 warp_image() 获取源/目标图像和相应的关键点,并使用定义的函数计算变形的输出图像和关键点的相应 Delaunay 三角测量:

def warp_image(src_img, src_points, dest_points, dest_shape, dtype=np.uint8):num_chans = 3src_img = src_img[:, :, :3]rows, cols = dest_shape[:2]result_img = np.zeros((rows, cols, num_chans), dtype)delaunay = Delaunay(dest_points)tri_affines = np.asarray(list(get_triangular_affine_matrices(delaunay.simplices, src_points, dest_points)))process_warp(src_img, result_img, tri_affines, dest_points, delaunay)return result_img, delaunay

(10) 绘制源和目标人脸图像以及面部标志(由形状预测器预测):

fig = plt.figure(figsize=(20,10))
plt.subplot(121)
plt.imshow(src_img)
for i in range(68):plt.plot(src_points[i,0], src_points[i,1], 'r.', markersize=20)
plt.title('Source image', size=10)
plt.axis('off')
plt.subplot(122)
plt.imshow(dst_img)
for i in range(68):plt.plot(dst_points[i,0], dst_points[i,1], 'g.', markersize=20)
plt.title('Destination image', size=10)
plt.axis('off')
plt.suptitle('Facial Landmarks computed for the images', size=12)
fig.subplots_adjust(wspace=0.01, left=0.1, right=0.9)
plt.show()

面部关键点

(11) 计算 alpha 值增加的变形图像,获得具有不同混合比例的变形图像,以观察从源图像到目标图像的平滑过渡:

fig = plt.figure(figsize=(20,20))
i = 1
for percent in np.linspace(1, 0, 9):points = weighted_average_points(src_points, dst_points, percent)src_face, src_d = warp_image(src_img, src_points, points, (600,600))end_face, end_d = warp_image(dst_img, dst_points, points, (600,600))average_face = weighted_average_points(src_face, end_face, percent)plt.subplot(3, 3, i)plt.imshow(average_face)plt.title('alpha=' + str(percent), size=10)plt.axis('off')i += 1
plt.suptitle('Face morphing', size=12)
fig.subplots_adjust(top=0.92, bottom=0, left=0.075, right=0.925, wspace=0.01, hspace=0.05)
plt.show()

面部变形过程

(12) 可视化具有使用 Delaunay 三角测量获得的三角剖分面部,并将面部标志作为三角形的顶点:

fig = plt.figure(figsize=(20,10))
plt.subplot(121)
plt.imshow(src_img)
plt.triplot(src_points[:,0], src_points[:,1], src_d.simplices.copy())
plt.plot(src_points[:,0], src_points[:,1], 'o', color='red')
plt.title('Source image', size=10)
plt.axis('off')
plt.subplot(122)
plt.imshow(dst_img)
plt.triplot(dst_points[:,0], dst_points[:,1], end_d.simplices.copy())
plt.plot(dst_points[:,0], dst_points[:,1], 'o')
plt.title('Destination image', size=10)
plt.axis('off')
plt.suptitle('Delaunay triangulation of the images', size=12)
fig.subplots_adjust(wspace=0.01, left=0.1, right=0.9)
plt.show()

三角剖分结果

小结

面部图像处理是提取和分析人类面部信息的研究领域,人脸是图像处理中的最重要的对象之一。因此,在过去的几十年中,面部图像的自动处理和识别已经得到了研究人员的极大关注。在本节中,我们学习了如何使用 dlib 库执行面部变形操作。

系列链接

Python图像处理【1】图像与视频处理基础
Python图像处理【2】探索Python图像处理库
Python图像处理【3】Python图像处理库应用
Python图像处理【4】图像线性变换
Python图像处理【5】图像扭曲/逆扭曲
Python图像处理【6】通过哈希查找重复和类似的图像
Python图像处理【7】采样、卷积与离散傅里叶变换
Python图像处理【8】使用低通滤波器模糊图像
Python图像处理【9】使用高通滤波器执行边缘检测
Python图像处理【10】基于离散余弦变换的图像压缩
Python图像处理【11】利用反卷积执行图像去模糊
Python图像处理【12】基于小波变换执行图像去噪
Python图像处理【13】使用PIL执行图像降噪
Python图像处理【14】基于非线性滤波器的图像去噪
Python图像处理【15】基于非锐化掩码锐化图像
Python图像处理【16】OpenCV直方图均衡化
Python图像处理【17】指纹增强和细节提取
Python图像处理【18】边缘检测详解
Python图像处理【19】基于霍夫变换的目标检测
Python图像处理【20】图像金字塔
Python图像处理【21】基于卷积神经网络增强微光图像
Python图像处理【22】基于卷积神经网络的图像去雾
Python图像处理【23】分布式图像处理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/638184.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

web渗透xxe漏洞

xxe xml external entity 外部实体注入&#xff0c;用户输入恶意 xml 被后台解析了恶意语句 owasptop10-- 不安全的配置 xml 是什么&#xff1f;&#xff1f; XML 指可扩展标记语言&#xff08; EXtensible Markup Language &#xff09;。 XML 是一种很像 HTML 的标记…

了解网卡、光猫、路由器

了解网卡、光猫、路由器 一、网卡二、光猫三、路由器四、光猫和路由器的联系和区别五、家庭正常上网的简单流程六、企业正常上网的简单流程 一、网卡 网卡&#xff1a;用来允许计算机在计算机网络上进行通讯的计算机硬件 一般来说&#xff0c;笔记本都有两种网卡&#xff0c;有…

【数值计算方法】 4.2 / Newton-Cotes公式

本质&#xff1a;具有等距节点的插值求积公式就是NC公式

OpenCV——Niblack局部阈值二值化方法

目录 一、Niblack算法1、算法概述2、参考文献二、代码实现三、结果展示OpenCV——Niblack局部阈值二值化方法由CSDN点云侠原创,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、Niblack算法 1、算法概述 Niblack 算法是一种典型的局部阈值…

设计模式-观察者模式(Observer)

1. 概念 观察者模式&#xff08;Observer Pattern&#xff09;一种行为型设计模式。它定义了对象之间的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都会得到通知并自动更新。 2. 原理结构图 主题&#xff08;Subject&#xff09;&#xff…

【C语言】操作符相关编程题

目录 题目一&#xff1a; 题目二&#xff1a; 题目三&#xff1a; 题目三&#xff1a; 题目四&#xff1a; 题目五&#xff1a; 题目六&#xff1a; 题目七&#xff1a; 题目八&#xff1a; 题目一&#xff1a; 题目&#xff1a;不创建临时变量&#xff0c;交换两个数…

SpringMvc的核心组件和执行流程

一、 springmvc的核心组件及作用 1.DispatcherServlet:前置控制器&#xff0c;是整个流程控制的核心&#xff0c;用来控制其他组件的执行&#xff0c;降低了其他组件的耦合性 2.Handler:控制器&#xff0c;完成具体的业务逻辑&#xff0c;当DispatcherServlet接收到请求后&am…

C语言 字符函数和字符串函数

目录 1. 字符分类函数2. 字符转换函数3. strlen - 计算长度4. strcpy - 复制內容5. strcat - 追加內容6. strcmp - 比较大小7.strncpy - 指定复制8. strncat - 指定追加9. strncmp - 指定比较10. strstr - 查找子字符串11. strtok - 查找记号12. strerror - 错误码 正文开始 1…

深度图转点云

一、理论分析 二、其他分析 1、相机内参 相机内参主要是四个参数fx,fy,u0,v0。要明白相机内参就是相机内部参数&#xff0c;是参考像素坐标系而言&#xff0c;有了这个前提&#xff0c;这四个参数也就很好理解了。 &#xff08;1&#xff09;首先&#xff0c;。其中F是相机的…

使用easyexcel将csv转为excel

一.背景 供应商系统下载的csv文件不支持域控&#xff08;主要是第三方wps服务不能对csv文件加密&#xff0c;但是可以对office系列产品进行权限访问的加密控制&#xff09;。因此思路就改为现将csv文件转为excel文件&#xff0c;然后对excel文件进行加域控制。本文主要介绍如何…

mysql基础20——数据备份

数据备份 数据备份有2种 一种是物理备份 一种是逻辑备份 物理备份 物理备份 通过把数据文件复制出来 达到备份的目的 用得比较少 逻辑备份 逻辑备份 把描述数据库结构和内容的信息保存起来 达到备份的目的 是免费的 数据备份工具 mysqldump &#xff08;3种模式&#x…

【leetcode面试经典150题】66. 分隔链表(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…