导读

因为目前公开的口罩人脸数据比较少,如果想训练一个口罩人脸识别模型,必须依赖大量的人脸数据。为了收集到更多的口罩人脸数据,我们只能利用已有的公开人脸数据上通过程序来模拟人脸带口罩。这篇文章向大家介绍一个简单版本使用python来给正常人脸带上口罩的思路和代码

原理介绍

想要给人脸戴口罩,就必须要用到人脸关键点的信息,通过关键点信息,我们就能知道应该将口罩放在哪个位置

  • 人脸关键点检测

这里我们使用的是68个人脸关键点,关键点的位置在人脸上的分布如下图所示

后面我们只需要用到其中四个关键点,用来计算口罩的位置,鼻梁第28点下巴的第2、9、16点

  • 根据关键点计算口罩的size

我们需要根据上面提到的四个关键点来计算口罩的widthheight口罩的宽利用点2和点16的欧式距离,口罩的高用点28和点9的欧式距离

实际使用中,建议将口罩分为左右两部分,因为有时候头部会向左或右偏转,分成两部分计算效果会好些。口罩的高度计算不变,计算左半部分口罩的宽利用点2直线(由点28和点9组成)的距离,同理可知右半部分口罩的宽计算。

  • 口罩角度的调整

因为人脸可能是歪的,利用点28和点9组成的直线结合垂直线计算偏转角度(人脸是正的,点28和点9组成的直线是垂直水平线),通过偏转角度来选择口罩

  • 口罩位置的确定

利用点28和点9来确定口罩所处位置的中心点,针对头会左右旋转的问题,需要对口罩的中心位置的确定进行微调,具体细节实现可以参考代码。

代码实现

环境准备
  • python版本:3.7
  • 第三方库安装
#安装OpenCV
pip install opencv-python
#安装numpy
pip install numpy
#安装PIL
pip install pillow
#安装pytorch,pytorch (>=1.0)
#建议安装cuda版本的pytorch
#安装教程:https://pytorch.org/get-started/previous-versions/
#安装人脸关键点检测face_alignment
pip install face-alignment
  • 关键点模型下载不了的问题

如果在使用face-alignment的时候无法下载模型文件,可以直接从下面的地址进行下载:
https://www.adrianbulat.com/downloads/python-fan/2DFAN-4.pth.tar
https://www.adrianbulat.com/downloads/python-fan/3DFAN-4.pth.tar
https://www.adrianbulat.com/downloads/python-fan/depth.pth.tar
将下载好的模型解压后得到pth模型文件,对linux系统,将解压后得到的pth文件放到~/.face_alignment/data目录下

口罩mask的提取

需要注意的是,准备的口罩mask最好是png(RGBA)透明背景的图片。否则在将口罩mask复制到人脸上时会遮盖多余的部分,影响效果。
我这里实现了一个从纯色背景的口罩jpg图片中,提取出一个透明背景的png口罩图片,代码如下

import cv2
import numpy as npimg = cv2.imread("mask_images/mask.jpg")
#将图片分割为三个通道
b_channel,g_channel,r_channel = cv2.split(img)
alpha_channel = np.zeros(b_channel.shape,dtype=b_channel.dtype)
gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
blur_img = cv2.GaussianBlur(gray_img,(3,3),cv2.BORDER_DEFAULT)
canny_img = cv2.Canny(blur_img,50,150)
contours,hierarchy = cv2.findContours(canny_img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
#获取面积最大的轮廓
contour = max(contours,key=cv2.contourArea)
#获取最大轮廓的凸包
hull = cv2.convexHull(contour)
#初始化一个alpha通道
alpha_channel = cv2.drawContours(alpha_channel,[hull],-1,255,-1)
png_img = cv2.merge((b_channel,g_channel,r_channel,alpha_channel))
#获取最大轮廓的最小外接矩形
rect = cv2.minAreaRect(contour)
#获取矩形四个顶点的坐标
box = cv2.boxPoints(rect)
#将矩形转换为水平的矩形
x_min = int(np.min(box[:,0]))
y_min = int(np.min(box[:,1]))
x_max = int(np.max(box[:,0]))
y_max = int(np.max(box[:,1]))
png_img = png_img[y_min:y_max,x_min:x_max,:]
cv2.imwrite("mask_images/mask.png",png_img)

给人脸添加口罩
import os,face_alignment
from PIL import Image
import numpy as npclass WearFaceMask(object):def __init__(self,face_path,mask_path,save_path,enlarge_ratio=0.9,use_gpu=True,show=False):self.face_path = face_pathself.mask_path = mask_pathself.save_path = save_pathself.enlarge_ratio = enlarge_ratioself.use_gpu = use_gpuself.show = showif use_gpu:self.fa=face_alignment.FaceAlignment(face_alignment.LandmarksType._2D, device='cuda')else:self.fa = face_alignment.FaceAlignment(face_alignment.LandmarksType._2D, device='cpu')def get_key_landmarks(self,face_landmarks):"""从68个关键点中获取4个关键点的位置用来定口罩佩戴的位置:param face_landmarks:人脸68个关键点:return:"""#获取下巴右边佩戴口罩的位置(关键点2)self.left_chin_point = face_landmarks[1]#获取鼻梁佩戴口罩的位置(关键点28)self.nose_point = face_landmarks[27]#获取下巴左边佩戴口罩的位置(关键点16)self.right_chin_point = face_landmarks[15]#获取下巴最下面佩戴口罩的位置(关键点9)self.bottom_chin_point = face_landmarks[8]@staticmethoddef cal_point_to_line_dist(point,line_point1,line_point2):"""计算点到直线的距离:param point: 点的坐标:param line_point1: 直线上第一点的坐标:param line_point2: 直线上另一点的坐标:return: 点到直线的距离"""#计算点和直线上点组成的向量vec1 = line_point1 - pointvec2 = line_point2 - pointdist = abs(np.cross(vec1,vec2)) / np.linalg.norm(line_point2 - line_point1)return distdef wear_face_mask(self):self._face_img = Image.open(self.face_path)self._mask_img = Image.open(self.mask_path)face_landmarks = self.fa.get_landmarks(np.asarray(self._face_img))[0].astype(np.int32)#获取需要的关键点信息self.get_key_landmarks(face_landmarks)#获取口罩的宽和高mask_width = self._mask_img.widthmask_height = self._mask_img.height#计算口罩适应人脸后和高度new_mask_height = int(np.linalg.norm(self.bottom_chin_point - self.nose_point))#将口罩分割为左右两部分用来适配人脸#左边口罩人脸mask_left_img = self._mask_img.crop((0,0,mask_width//2,mask_height))mask_left_width = self.cal_point_to_line_dist(self.left_chin_point,self.nose_point,self.bottom_chin_point)mask_left_width = int(mask_left_width * self.enlarge_ratio)mask_left_img = mask_left_img.resize((mask_left_width,new_mask_height))#右边口罩人脸mask_right_img = self._mask_img.crop((mask_width//2,0,mask_width,mask_height))mask_right_width = self.cal_point_to_line_dist(self.right_chin_point,self.nose_point,self.bottom_chin_point)mask_right_width = int(mask_right_width * self.enlarge_ratio)mask_right_img = mask_right_img.resize((mask_right_width,new_mask_height))#合并口罩size = (mask_left_width+mask_right_width,new_mask_height)mask_img = Image.new("RGBA",size)mask_img.paste(mask_left_img,(0,0),mask_left_img)mask_img.paste(mask_right_img,(mask_left_width,0),mask_right_img)#计算人脸的旋转角度angle = np.arctan2(self.bottom_chin_point[1]-self.nose_point[1],self.bottom_chin_point[0]-self.nose_point[0])#旋转口罩rotated_mask_img = mask_img.rotate(angle,expand=True)#计算mask的位置mask_center_x = (self.nose_point[0]+self.bottom_chin_point[0]) // 2mask_center_y = (self.nose_point[1]+self.bottom_chin_point[1]) // 2offset = mask_img.width // 2 - mask_left_width#将弧度转换为角度radian = angle * np.pi / 180#对口罩的位置进行微调box_x = mask_center_x + int(offset * np.cos(radian)) - rotated_mask_img.width // 2box_y = mask_center_y + int(offset * np.sin(radian)) - rotated_mask_img.height // 2self._face_img.paste(mask_img,(box_x,box_y),mask_img)self.save()def save(self):self._face_img.save(self.save_path)print(f'Save to {self.save_path}')face_path="imgs/test.jpg"
mask_path="mask_images/mask.png"
save_path="imgs/test_mask.jpg"
WearFaceMask(face_path,mask_path,save_path).wear_face_mask()

接下来我们试试给最不喜欢戴口罩的特没谱同志带上口罩,看看效果如何。感觉好像效果还是差了那么点,下篇文章介绍另一种方法来提升一下这个效果。

代码我已经上传到gitee:https://gitee.com/pragmaticAgile/wear_face_mask.git

python给人脸带上口罩(简单版)相关推荐

  1. python 提取最小外接矩形_python给人脸带上口罩(简单版)

    导读 因为目前公开的口罩人脸数据比较少,如果想训练一个口罩人脸识别模型,必须依赖大量的人脸数据.为了收集到更多的口罩人脸数据,我们只能利用已有的公开人脸数据上通过程序来模拟人脸带口罩.这篇文章向大家介 ...

  2. 用Python给你的女神带上口罩~

    前言 2019 年底开始蔓延的新型肺炎疫情牵动人心,作为个体,我们力所能及的就是尽量待在家中少出门. 看到一些朋友叫设计同学帮忙给自己的头像戴上口罩,作为技术人,心想一定还有更多人有这样的诉求,不如开 ...

  3. 给人脸戴上口罩,Python实战项目来了

    大家好,人生苦短,我用Python.今天给大家分享一个Python 实战案例:为人脸照片添加口罩,喜欢本文记得收藏.点赞.关注. 废话不多说,我们先展示最终的效果. [注]完整版代码.资料,技术沟通, ...

  4. 使用Python为人脸自动生成口罩

    来源:深度学习与计算机视觉 本文使用OpenCV dlib库生成口罩 口罩已经被证明是防止COVID-19传播的最好的防御措施之一,然而,这也导致了基于面部特征(包括鼻子.嘴和下巴线)的面部识别算法的 ...

  5. 这顶海贼王的帽子,我Python给你带上了 | 【人脸识别应用】

    微信公众号:AI算法与图像处理 关注可了解更多的资料及技巧.问题或建议,请公众号留言; 如果你觉得对你有帮助,欢迎分享和转发哈 本文主要参考: zhuanlan.zhihu.com/p/3229975 ...

  6. 图像修复神器!带上口罩都能还原!DDPM:用去噪扩散概率模型极限修复图像,效果太牛了!...

    点击下方卡片,关注"CVer"公众号 AI/CV重磅干货,第一时间送达 转载自:机器之心 | 编辑:杜伟.陈萍 无论掩码类型如何多变,苏黎世联邦理工学院计算机视觉实验室(CVL)的 ...

  7. 基于Python的人脸自动戴口罩系统

    目录 1.项目背景 2.页面设计 3.器官识别 4.退出系统 1.项目背景 2019年新型冠状病毒感染的肺炎疫情发生以来,牵动人心,举国哀痛,口罩.酒精.消毒液奇货可居.

  8. Python打造五线图谱(乐活五线谱)简单版

    效果图: 环境 python 3.7 scipy==1.1.0 plotly==4.7.1 cufflinks==0.17.3 计算代码 import pandas as pd import tali ...

  9. web人脸识别登陆系统简单版(springboot+mybatis)

    先获取人脸识别的sdk 进入官网下载:链接: 开发者中心 获取到APPID和SDK KEY window下的配置文件 人脸识别的jar包 人脸识别的demo 最后完成的效果图 完整的项目地址 gith ...

最新文章

  1. 利用Jenkins的Pipeline实现集群自动化部署SpringBoot项目
  2. JMeter学习(六)集合点
  3. 如何在Chrome调试器里检查嵌套Observable对象
  4. 鲶鱼效应:为什么要适当的贷款?
  5. [Python3]Python面向对象的程序设计
  6. 外籍主管眼中的阿里巴巴
  7. JAVA面试中问及HIBERNATE与 MYBATIS的对比,在这里做一下总结(转)
  8. Swift 面向协议编程 基础篇 (一) 介绍
  9. 强制 转换string 的一个简单方法(笔记)
  10. 美股第三次熔断!一觉醒来,苹果损失了1.5亿部iPhone 11 Pro
  11. Linear Algebra - Determinant(几何意义)
  12. 【Computer Organization笔记07】实验课:可编程逻辑器件介绍,硬件编程方法与原则,硬件编程流程
  13. Quidway S1700系列企业网交换机
  14. VS2017超有用秘钥(亲测)
  15. 华为语音网关iad208e(m)华为8口语音网关web界面
  16. 大白菜超级U盘启动盘制作工具极速装机版
  17. 【课程作业】学术英语写作:文献阅读报告2
  18. require的用法 php,PHP 关于require()文件包含的用法详解
  19. 微信公众号 - Java推送小程序订阅消息给用户
  20. USACO-Healthy Holsteins

热门文章

  1. 3DSlicer建立C++插件步骤
  2. COMP9315 week07课堂笔记
  3. catboost和xgboost_CatBoost:比XGBoost更优秀的GBDT算法
  4. linux yum 卸载apache2,CentOS卸载Apache方法
  5. java 数组和List排序方式汇总
  6. Java物业小程序源码物业管理系统源码
  7. 七牛云 X 英语流利说:教育 3.0 时代的智能突破
  8. CentOS7双网卡绑定bond
  9. 羽毛球双打处于进攻态势时应如何处理
  10. 用ggplot2绘制多维折线图