Python为人脸照片添加口罩实战
作者:.别拖至春天. 发布时间:2021-11-12 23:39:33
标签:Python,人脸,口罩
效果展示
数据集展示
数据集来源:使用了开源数据集FaceMask_CelebA
github地址:https://github.com/sevenHsu/FaceMask_CelebA.git
部分人脸数据集:
口罩样本数据集:
为人脸照片添加口罩代码
这部分有个库face_recognition需要安装,如果之前没有用过的小伙伴可能得费点功夫。
Face Recognition 库主要封装了dlib这一 C++ 图形库,通过 Python 语言将它封装为一个非常简单就可以实现人脸识别的 API 库,屏蔽了人脸识别的算法细节,大大降低了人脸识别功能的开发难度。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : 2014Vee
import os
import numpy as np
from PIL import Image, ImageFile
__version__ = '0.3.0'
IMAGE_DIR = os.path.dirname('E:/play/FaceMask_CelebA-master/facemask_image/')
WHITE_IMAGE_PATH = os.path.join(IMAGE_DIR, 'front_14.png')
BLUE_IMAGE_PATH = os.path.join(IMAGE_DIR, 'front_14.png')
SAVE_PATH = os.path.dirname('E:/play/FaceMask_CelebA-master/save/synthesis/')
SAVE_PATH2 = os.path.dirname('E:/play/FaceMask_CelebA-master/save/masks/')
class FaceMasker:
KEY_FACIAL_FEATURES = ('nose_bridge', 'chin')
def __init__(self, face_path, mask_path, white_mask_path, save_path, save_path2, model='hog'):
self.face_path = face_path
self.mask_path = mask_path
self.save_path = save_path
self.save_path2 = save_path2
self.white_mask_path = white_mask_path
self.model = model
self._face_img: ImageFile = None
self._black_face_img = None
self._mask_img: ImageFile = None
self._white_mask_img = None
def mask(self):
import face_recognition
face_image_np = face_recognition.load_image_file(self.face_path)
face_locations = face_recognition.face_locations(face_image_np, model=self.model)
face_landmarks = face_recognition.face_landmarks(face_image_np, face_locations)
self._face_img = Image.fromarray(face_image_np)
self._mask_img = Image.open(self.mask_path)
self._white_mask_img = Image.open(self.white_mask_path)
self._black_face_img = Image.new('RGB', self._face_img.size, 0)
found_face = False
for face_landmark in face_landmarks:
# check whether facial features meet requirement
skip = False
for facial_feature in self.KEY_FACIAL_FEATURES:
if facial_feature not in face_landmark:
skip = True
break
if skip:
continue
# mask face
found_face = True
self._mask_face(face_landmark)
if found_face:
# save
self._save()
else:
print('Found no face.')
def _mask_face(self, face_landmark: dict):
nose_bridge = face_landmark['nose_bridge']
nose_point = nose_bridge[len(nose_bridge) * 1 // 4]
nose_v = np.array(nose_point)
chin = face_landmark['chin']
chin_len = len(chin)
chin_bottom_point = chin[chin_len // 2]
chin_bottom_v = np.array(chin_bottom_point)
chin_left_point = chin[chin_len // 8]
chin_right_point = chin[chin_len * 7 // 8]
# split mask and resize
width = self._mask_img.width
height = self._mask_img.height
width_ratio = 1.2
new_height = int(np.linalg.norm(nose_v - chin_bottom_v))
# left
mask_left_img = self._mask_img.crop((0, 0, width // 2, height))
mask_left_width = self.get_distance_from_point_to_line(chin_left_point, nose_point, chin_bottom_point)
mask_left_width = int(mask_left_width * width_ratio)
mask_left_img = mask_left_img.resize((mask_left_width, new_height))
# right
mask_right_img = self._mask_img.crop((width // 2, 0, width, height))
mask_right_width = self.get_distance_from_point_to_line(chin_right_point, nose_point, chin_bottom_point)
mask_right_width = int(mask_right_width * width_ratio)
mask_right_img = mask_right_img.resize((mask_right_width, new_height))
# merge mask
size = (mask_left_img.width + mask_right_img.width, new_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_img.width, 0), mask_right_img)
# rotate mask
angle = np.arctan2(chin_bottom_point[1] - nose_point[1], chin_bottom_point[0] - nose_point[0])
rotated_mask_img = mask_img.rotate(angle, expand=True)
# calculate mask location
center_x = (nose_point[0] + chin_bottom_point[0]) // 2
center_y = (nose_point[1] + chin_bottom_point[1]) // 2
offset = mask_img.width // 2 - mask_left_img.width
radian = angle * np.pi / 180
box_x = center_x + int(offset * np.cos(radian)) - rotated_mask_img.width // 2
box_y = center_y + int(offset * np.sin(radian)) - rotated_mask_img.height // 2
# add mask
self._face_img.paste(mask_img, (box_x, box_y), mask_img)
# split mask and resize
width = self._white_mask_img.width
height = self._white_mask_img.height
width_ratio = 1.2
new_height = int(np.linalg.norm(nose_v - chin_bottom_v))
# left
mask_left_img = self._white_mask_img.crop((0, 0, width // 2, height))
mask_left_width = self.get_distance_from_point_to_line(chin_left_point, nose_point, chin_bottom_point)
mask_left_width = int(mask_left_width * width_ratio)
mask_left_img = mask_left_img.resize((mask_left_width, new_height))
# right
mask_right_img = self._white_mask_img.crop((width // 2, 0, width, height))
mask_right_width = self.get_distance_from_point_to_line(chin_right_point, nose_point, chin_bottom_point)
mask_right_width = int(mask_right_width * width_ratio)
mask_right_img = mask_right_img.resize((mask_right_width, new_height))
# merge mask
size = (mask_left_img.width + mask_right_img.width, new_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_img.width, 0), mask_right_img)
# rotate mask
angle = np.arctan2(chin_bottom_point[1] - nose_point[1], chin_bottom_point[0] - nose_point[0])
rotated_mask_img = mask_img.rotate(angle, expand=True)
# calculate mask location
center_x = (nose_point[0] + chin_bottom_point[0]) // 2
center_y = (nose_point[1] + chin_bottom_point[1]) // 2
offset = mask_img.width // 2 - mask_left_img.width
radian = angle * np.pi / 180
box_x = center_x + int(offset * np.cos(radian)) - rotated_mask_img.width // 2
box_y = center_y + int(offset * np.sin(radian)) - rotated_mask_img.height // 2
# add mask
self._black_face_img.paste(mask_img, (box_x, box_y), mask_img)
def _save(self):
path_splits = os.path.splitext(self.face_path)
# new_face_path = self.save_path + '/' + os.path.basename(self.face_path) + '-with-mask' + path_splits[1]
# new_face_path2 = self.save_path2 + '/' + os.path.basename(self.face_path) + '-binary' + path_splits[1]
new_face_path = self.save_path + '/' + os.path.basename(self.face_path) + '-with-mask' + path_splits[1]
new_face_path2 = self.save_path2 + '/' + os.path.basename(self.face_path) + '-binary' + path_splits[1]
self._face_img.save(new_face_path)
self._black_face_img.save(new_face_path2)
# print(f'Save to {new_face_path}')
@staticmethod
def get_distance_from_point_to_line(point, line_point1, line_point2):
distance = np.abs((line_point2[1] - line_point1[1]) * point[0] +
(line_point1[0] - line_point2[0]) * point[1] +
(line_point2[0] - line_point1[0]) * line_point1[1] +
(line_point1[1] - line_point2[1]) * line_point1[0]) / \
np.sqrt((line_point2[1] - line_point1[1]) * (line_point2[1] - line_point1[1]) +
(line_point1[0] - line_point2[0]) * (line_point1[0] - line_point2[0]))
return int(distance)
# FaceMasker("/home/aistudio/data/人脸.png", WHITE_IMAGE_PATH, True, 'hog').mask()
from pathlib import Path
images = Path("E:/play/FaceMask_CelebA-master/bbox_align_celeba").glob("*")
cnt = 0
for image in images:
if cnt < 1:
cnt += 1
continue
FaceMasker(image, BLUE_IMAGE_PATH, WHITE_IMAGE_PATH, SAVE_PATH, SAVE_PATH2, 'hog').mask()
cnt += 1
print(f"正在处理第{cnt}张图片,还有{99 - cnt}张图片")
掩膜生成代码
这部分其实就是对使用的口罩样本的二值化,因为后续要相关模型会用到
import os
from PIL import Image
# 源目录
# MyPath = 'E:/play/FaceMask_CelebA-master/facemask_image/'
MyPath = 'E:/play/FaceMask_CelebA-master/save/masks/'
# 输出目录
OutPath = 'E:/play/FaceMask_CelebA-master/save/Binarization/'
def processImage(filesoure, destsoure, name, imgtype):
'''
filesoure是存放待转换图片的目录
destsoure是存在输出转换后图片的目录
name是文件名
imgtype是文件类型
'''
imgtype = 'bmp' if imgtype == '.bmp' else 'png'
# 打开图片
im = Image.open(filesoure + name)
# =============================================================================
# #缩放比例
# rate =max(im.size[0]/640.0 if im.size[0] > 60 else 0, im.size[1]/1136.0 if im.size[1] > 1136 else 0)
# if rate:
# im.thumbnail((im.size[0]/rate, im.size[1]/rate))
# =============================================================================
img = im.convert("RGBA")
pixdata = img.load()
# 二值化
for y in range(img.size[1]):
for x in range(img.size[0]):
if pixdata[x, y][0] < 90:
pixdata[x, y] = (0, 0, 0, 255)
for y in range(img.size[1]):
for x in range(img.size[0]):
if pixdata[x, y][1] < 136:
pixdata[x, y] = (0, 0, 0, 255)
for y in range(img.size[1]):
for x in range(img.size[0]):
if pixdata[x, y][2] > 0:
pixdata[x, y] = (255, 255, 255, 255)
img.save(destsoure + name, imgtype)
def run():
# 切换到源目录,遍历源目录下所有图片
os.chdir(MyPath)
for i in os.listdir(os.getcwd()):
# 检查后缀
postfix = os.path.splitext(i)[1]
name = os.path.splitext(i)[0]
name2 = name.split('.')
if name2[1] == 'jpg-binary' or name2[1] == 'png-binary':
processImage(MyPath, OutPath, i, postfix)
if __name__ == '__main__':
run()
来源:https://blog.csdn.net/qq_52118067/article/details/124334872


猜你喜欢
- A.课程内容本节课主要学习函数的返回值returm,通过学习编写一个汇率转换器程序。B.知识点(1)定义函数(2)调用函数(3)返回值C.用
- 在python中json分别由列表和字典组成,本文主要介绍python中字典与json相互转换的方法。使用json.dumps可以把字典转成
- 本文实例为大家分享了python代码实现猜拳小游戏的具体代码,供大家参考,具体内容如下游戏实现具体功能原有的用户登录的信息均能保存在txt文
- 在Dreamweaver 4.0中,我们就已接触了模板与库的概念,知道它们是批量生成风格类似的网页的好工具。如今在Dreamweaver M
- 猜测下面这段程序的输出:class A(object): def __init__(self):
- 1. 更新日志1.1. v1.01.1.1. 破坏性变更gorm.Open返回类型为*gorm.DB而不是gorm.DB更新只会更新更改的字
- 学了这么长时间的Pygame,一直想写个游戏实战一下。看起来很简单的游戏,写其来怎么这么难。最初想写个俄罗斯方块,想了很长时间如何实现,想来
- 下面给大家介绍下pandas读取CSV文件时查看修改各列的数据类型格式,具体内容如下所述:我们在调bug的时候会经常查看、修改pandas列
- 如果不小心按到键盘上的Insert键的话,光标显示的就不是一条竖线,而是一个类似方块的阴影区域,比如插入一下insert键的介绍:它叫插入键
- 本文实例为大家分享了element跨分页操作选择的具体代码,供大家参考,具体内容如下业务需求:在批量导出或者批量删除的时候会涉及到跨分页导出
- 看了下网上有很多关于模拟登录淘宝,但是基本都是使用scrapy、pyppeteer、selenium等库来模拟登录,但是目前我们还没有讲到这
- OK,今天我们来学习一下 python 中的日志模块,日志模块也是我们日后的开发工作中使用率很高的模块之一,接下来们就看一看今天具体要学习日
- 最近python代码遇到了一个神奇的需求, 就是如果将python utc datetime转换为时间戳.百度找到都是使用time.mkti
- 这篇文章主要介绍了Python3的socket使用方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要
- 原理1.使用python中的mtplotlib库。2.立体爱心面公式点画法(实心)代码import matplotlib.pyplot as
- 开发Web应用时,你经常要加上搜索功能。甚至还不知能要搜什么,就在草图上画了一个放大镜。搜索是项非常重要的功能,所以像elasticsear
- try { int readByte = 0;  
- Python的创始人为荷兰人吉多·范罗苏姆 (Guido van Rossum)。 * 圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞
- 前言人生苦短,快学Python!日报,是大部分打工人绕不过的难题。对于管理者来说,日报是事前管理的最好抓手,可以了解团队的氛围和状态。可对于
- 下面就是解决方案: 1- From the command prompt, stop isqlplus: c:\>isqlplusct