目录
paddlehub的安装
我们先创建一个虚拟环境,名字随意,我这里起的名字为paddle,python指定版本为3.6,命令如下所示。
conda create -n paddle python=3.6
- 安装paddle之前需要先安装好cuda和cudnn了,如果大家没有安装,则需要先安装这两个加速器,然后再进入到我们的虚拟环境,开始安装paddle,paddle官网地址。
#进入虚拟环境
conda activate paddle
#根据操作系统,python版本以及cuda版本安装paddle。
python -m pip install paddlepaddle-gpu==1.8.4.post107 -i https://mirror.baidu.com/pypi/simple
- 检查paddle是否安装成功,再终端输入以下命令。
import paddle
paddle.fluid.install_check.run_check()
- 如果出现和下图一样的信息,则说明安装成功。
- 输入下面的命令即可安装paddlehub,paddlehub的官网链接为paddlehub官网链接
pip install paddlehub --upgrade -i https://pypi.tuna.tsinghua.edu.cn/simple
- 利用pip list或者pip show paddlehub,有paddlehub信息则说明安装成功,如下图所示。
利用paddlehub生成戴口罩的图片
- paddlehub检测出来的人脸关键点如下所所示,每个数字代表每一个脸部具体的位置。
- 具体图片的关键点的检测图如下所示。
- 下面的函数将口罩将要粘贴的四个关键点给返回出来。
import paddlehub as hub
def get_key_points(img):
# 加载人脸检测模型
face_landmark = hub.Module(name='face_landmark_localization')
# 利用人脸关键点检测模型开始检测人脸图片,并将图片加载到work目录下
result = face_landmark.keypoint_detection(images=[img], batch_size=1, use_gpu=False, output_dir='./work',
visualization=True)
# result[0]['data'][0]为所有检测到的关键点
location = result[0]['data'][0]
# 左眼睛靠下的位置就是2的位置
left = int(location[2][0])
# 右眼考下的位置也就是16的位置
right = int(location[16][0])
# 鼻梁的位置
top = int(location[29][1])
# 下巴的位置
bottom = int(location[9][1])
# 将所有的点以列表形式返回
return [left, bottom, right, top];
- 如下面的代码所示。
def wear_mask(mask_img, face_img):
'''给图像带上口罩'''
# 把原图像复制一份给face_img_copy,不然原图是带关键点图的图片
face_img_copy = face_img.copy();
face_points = get_key_points(face_img)
left = face_points[0];
bottom = face_points[1];
right = face_points[2];
top = face_points[3];
# 口罩的宽度
resize_width = right - left;
# 口罩的长度
resize_height = bottom - top;
# 调整口罩的大小
mask_img = cv2.resize(mask_img, (resize_width, resize_height))
# 分离通道
mask_channels = cv2.split(mask_img)
face_channels = cv2.split(face_img_copy)
b, g, r, a = cv2.split(mask_img)
# 遍历每个通道
for c in range(0, 3):
face_channels[c] = np.array(face_channels[c], dtype=np.uint8)
k = np.uint8((255.0 - a) / 255)
# 遍历原图像的每个通道让口罩区域变得透明
face_channels[c][top:top + resize_height, left:left + resize_width] = face_channels[c][top:top + resize_height,
left:left + resize_width] * k;
mask_channels[c] *= np.array(a / 255, dtype=np.uint8)
# # 因为口罩区域调整完毕之后可能有黑边,这里将像素值小于100的调整为255白色
mask_channels[c] = remove_black_side(mask_channels[c])
# 原图像的口罩区域逐通道加上口罩的通道像素值
face_channels[c][top:top + resize_height, left:left + resize_width] += np.array(mask_channels[c],
dtype=np.uint8)
# 通道合并为完整的图像
result_img = cv2.merge(face_channels)
return result_img;
- 口罩的图片
- 输入图像进行测试的代码
# 读入的测试图像
face_img = cv2.imread('./data/cool_boy.jpg')
# 口罩图像
mask_img = cv2.imread('./data/mask666.png', -1)
# 带上口罩的图像
result_img = wear_mask(mask_img, face_img)
# 显示图像
cv2.imshow("result.img", result_img)
cv2.waitKey(0)
这样出来之后口罩周围其实还是有黑边的,下面的函数可以将黑色的边缘像素点转换为白色。
def remove_black_side(mask_channels):
'''因为口罩区域调整完毕之后可能有黑边,这里将像素值小于100的调整为255白色'''
for i in range(mask_channels.shape[0]):
for j in range(mask_channels.shape[1]):
if mask_channels[i][j] < 100:
mask_channels[i][j] = 255;
return mask_channels;
- 最后的效果图如下所示
- 总体来说效果还不错,后面位置还需要再微调以下,以及还有一些小的黑像素点也需要去除。
- 完整代码如下所示
import cv2
import numpy as np
import paddlehub as hub
def get_key_points(img):
# 加载人脸检测模型
face_landmark = hub.Module(name='face_landmark_localization')
# 利用人脸关键点检测模型开始检测人脸图片,并将图片加载到work目录下
result = face_landmark.keypoint_detection(images=[img], batch_size=1, use_gpu=False, output_dir='./work',
visualization=True)
# result[0]['data'][0]为所有检测到的关键点
location = result[0]['data'][0]
# 左眼睛靠下的位置就是2的位置
left = int(location[2][0])
# 右眼考下的位置也就是16的位置
right = int(location[16][0])
# 鼻梁的位置
top = int(location[29][1])
# 下巴的位置
bottom = int(location[9][1])
# 将所有的点以列表形式返回
return [left, bottom, right, top];
def remove_black_side(mask_channels):
'''因为口罩区域调整完毕之后可能有黑边,这里将像素值小于100的调整为255白色'''
for i in range(mask_channels.shape[0]):
for j in range(mask_channels.shape[1]):
if mask_channels[i][j] < 100:
mask_channels[i][j] = 255;
return mask_channels;
def wear_mask(mask_img, face_img):
'''给图像带上口罩'''
# 把原图像复制一份给face_img_copy,不然原图是带关键点图的图片
face_img_copy = face_img.copy();
face_points = get_key_points(face_img)
left = face_points[0];
bottom = face_points[1];
right = face_points[2];
top = face_points[3];
# 口罩的宽度
resize_width = right - left;
# 口罩的长度
resize_height = bottom - top;
# 调整口罩的大小
mask_img = cv2.resize(mask_img, (resize_width, resize_height))
# 分离通道
mask_channels = cv2.split(mask_img)
face_channels = cv2.split(face_img_copy)
b, g, r, a = cv2.split(mask_img)
# 遍历每个通道
for c in range(0, 3):
face_channels[c] = np.array(face_channels[c], dtype=np.uint8)
k = np.uint8((255.0 - a) / 255)
# 遍历原图像的每个通道让口罩区域变得透明
face_channels[c][top:top + resize_height, left:left + resize_width] = face_channels[c][top:top + resize_height,
left:left + resize_width] * k;
mask_channels[c] *= np.array(a / 255, dtype=np.uint8)
# 因为口罩区域调整完毕之后可能有黑边,这里将像素值小于100的调整为255白色
mask_channels[c] = remove_black_side(mask_channels[c])
# 原图像的口罩区域逐通道加上口罩的通道像素值
face_channels[c][top:top + resize_height, left:left + resize_width] += np.array(mask_channels[c],
dtype=np.uint8)
# 通道合并为完整的图像
result_img = cv2.merge(face_channels)
return result_img;
# 读入的测试图像
face_img = cv2.imread('./data/baby.jpg')
# 口罩图像
mask_img = cv2.imread('./data/mask666.png', -1)
# 带上口罩的图像
result_img = wear_mask(mask_img, face_img)
# 显示图像
cv2.imshow("result.img", result_img)
cv2.waitKey(0)
demo总结
- 使用paddlehub框架可以很方便地实现人脸的关键点检测,并且精度也挺高。当然paddlehub框架不仅仅是人脸关键点检测,还有NLP以及其他领域的一些应用,更多的介绍大家可以去官网看看。
- 在得到关键点位置之后,我们可以根据这些关键点来做一些有意思的小demo。比如修改脸型,放大眼睛,等等…。
- 这次实现的过程中,其实还是有一些困难的,直接把口罩的图片贴在脸部的位置,这时候是一个矩形,口罩旁边的白色也会显示出来,效果非常不好。后来又搜了搜其他的实现方式,通过逐通道叠加的方式可以处理掉这个问题,但同时口罩的边缘也会有黑色。这时候再遍历这个口罩区域,把黑色像素值转换为白色,效果上会好一点。
- 总的来说,从这次实现中,自己也收获了很多。
联系我们,一起学Python吧
每周每日,分享Python实战代码,入门资料,进阶资料,基础语法,爬虫,数据分析,web网站,机器学习,深度学习等等。
微信群(关注「Python家庭」一起轻松学Python吧)
个人微信(备注来意,学习交流,合作,聊聊人生~)