还记得疫情之初,我们用Python给头像戴口罩的文章吗?
当时只是简单的调用了第三方模块将口罩图片替换入原图,内容非常简短。
今天,将为大家提供一个能够通过以下三种方式给头像戴上圣诞帽的Python教程:
1.实时打开摄像头读取头像图佩戴圣诞帽
2.从本地读取一幅头像图佩戴圣诞帽
3.从文件夹中批量读取头像图佩戴圣诞帽
1.准备
开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。
如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.
此外,推荐大家用VSCode编辑器,因为它可以在编辑器下方的终端运行命令安装依赖模块:Python 编程的最好搭档—VSCode 详细指南。
Windows环境下打开 Cmd (开始-运行-CMD),苹果系统环境下请打开 Terminal (command+空格输入Terminal),输入命令安装依赖:
pip install https://pypi.python.org/packages/da/06/bd3e241c4eb0a662914b3b4875fc52dd176a9db0d4a2c915ac2ad8800e9e/dlib-19.7.0-cp36-cp36m-win_amd64.whl#md5=b7330a5b2d46420343fbed5df69e6a3f
pip install opencv-python
有两个依赖,一个是 dlib模块,需要通过whl文件安装。一个是常用的opencv模块,直接pip安装即可。
文章源代码fork自:amusi/Merry_Christmas_Hat
本文全部源代码及图片可在此下载:
https://github.com/Ckend/Merry_Christmas_Hat
如果你访问不了Github,可在Python实用宝典公众号后台回复:圣诞帽 下载。
2.给头像戴上圣诞帽
为防大家没耐心看下去,我把佩戴圣诞帽的教程提前了。
下载源代码后,进入源代码的文件夹,一共有三种方式给你的头像佩戴圣诞帽。
1.打开摄像头读取头像图:
当摄像头打开后,会实时出现佩戴着圣诞帽的你。按q保存你最喜欢的图片即可,源代码如下:
def method_one(hat_img):
"""
方式1: 打开摄像头读取头像图
"""
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print('摄像头打开失败!')
else:
print('摄像头打开成功!')
print("请按下键盘上的'q',保存当前满意图像!")
while cap.isOpened():
_, img = cap.read()
cv2.imshow("img", img)
k = cv2.waitKey(33) & 0xFF
if(k == ord('q')):
cv2.imwrite("sefile.jpg", img)
face_flag, output = add_hat(img, hat_img)
if(-1 == face_flag):
break
cv2.imshow("output", output)
print("请按下键盘上的任意按键,退出当前程序!")
cv2.waitKey(0)
cv2.imwrite("output.jpg", output)
break
# 读取帽子图,第二个参数-1表示读取为rgba通道,否则为rgb通道
hat_img = cv2.imread("hat.png", -1)
# 选择你需要的方式
method_one(hat_img)
cv2.destroyAllWindows()
这样,通过运行Merry_Chirstmas_Hat.py文件就能打开摄像头并实时显示佩戴圣诞帽的你:
python Merry_Chirstmas_Hat.py
2.读取一个图像佩戴圣诞帽
这是最常见的使用场景,你只需要的源代码文件夹下,放置你所需要佩戴圣诞帽的图像,命名为test.jpg(或其他,只需要改函数调用里你的指定文件名称)。
放置完成后运行Merry_Chirstmas_Hat.py文件即可佩戴圣诞帽。
def method_two(hat_img, filename):
"""
方式2: 从本地读取一幅头像图
"""
img = cv2.imread(filename)
success, output = add_hat(img, hat_img)
if not success:
print("戴失败了!")
return
# 展示效果
cv2.imshow("output", output)
cv2.waitKey(0)
cv2.imwrite("output.jpg", output)
# 读取帽子图,第二个参数-1表示读取为rgba通道,否则为rgb通道
hat_img = cv2.imread("hat.png", -1)
# 选择你需要的方式
method_two(hat_img, "test.jpg")
cv2.destroyAllWindows()
3. 从文件夹中读取多张头像图(批量处理)
在源代码的文件夹下,创建一个名为images的文件夹,在里面放置所有以.jpg结尾的图像,运行Merry_Chirstmas_Hat.py文件后你能看到所有这些图像佩戴圣诞帽的效果。
def method_three(hat_img):
"""
方式3: 从文件夹中读取多张头像图(批量处理)
"""
import glob as gb
img_path = gb.glob("./images/*.jpg")
for path in img_path:
img = cv2.imread(path)
# 添加帽子
success, output = add_hat(img, hat_img)
if not success:
print("戴失败了!")
continue
# 展示效果
cv2.imshow("output", output)
cv2.waitKey(0)
# 读取帽子图,第二个参数-1表示读取为rgba通道,否则为rgb通道
hat_img = cv2.imread("hat.png", -1)
# 选择你需要的方式
method_three(hat_img)
cv2.destroyAllWindows()
我们的代码默认使用了第二种方式佩戴圣诞帽,你可以修改代码178行的method选择你所需要的方式。佩戴效果如下:
原图:
佩戴效果图:
3.原理分析
在上面的三种佩戴圣诞帽方法中,都调用了一个叫 add_hat 的函数。
顾名思义,这个函数里对原图像做了佩戴圣诞帽的逻辑,其步骤如下:
1. 正脸识别(才好佩戴帽子到头部)。
2. 遍历所有人脸,取5个关键点,并根据人脸大小调整帽子大小。
3. 利用alpha通道的图像提取放帽子的区域(提取空心区域)。
4. 将原帽子覆盖至第3步提取出来的空心区域上并放回原图。
下面分步骤阐述:
1.正脸识别
利用了dlib中已经训练好的人脸关键点检测模型对图像进行提取人脸的操作:
# dlib人脸关键点检测器(需要确保.py文件同级目录下有shape_predictor_5_face_landmarks.dat这个文件)
predictor_path = "shape_predictor_5_face_landmarks.dat"
predictor = dlib.shape_predictor(predictor_path)
# dlib正脸检测器
detector = dlib.get_frontal_face_detector()
# 正脸检测
dets = detector(img, 1)
检测到的人脸数据将会保存到dets变量中,因此dets的长度将大于0.
2.遍历人脸,取关键点并调整帽子大小
获取保存的人脸数据的各种参数,并根据这些参数对帽子进行比例转化:
# 如果检测到人脸
if len(dets) > 0:
# 遍历所有人脸
for d in dets:
x, y, w, h = d.left(), d.top(), d.right()-d.left(), d.bottom()-d.top()
# 关键点检测,5个关键点
shape = predictor(img, d)
# 选取左(0)右(2)眼眼角的点
point1 = shape.part(0)
point2 = shape.part(2)
# 求两点中心
eyes_center = ((point1.x+point2.x)//2, (point1.y+point2.y)//2)
# 根据人脸大小调整帽子大小
factor = 1.5 # 比例因子
resized_hat_h = int(
round(rgb_hat.shape[0]*w/rgb_hat.shape[1]*factor))
resized_hat_w = int(
round(rgb_hat.shape[1]*w/rgb_hat.shape[1]*factor))
# 避免帽子高度超出图像画面
if resized_hat_h > y:
resized_hat_h = y-1
# 根据人脸大小调整帽子大小
resized_hat = cv2.resize(rgb_hat, (resized_hat_w, resized_hat_h))
3. 利用alpha通道的图像提取放帽子的区域(提取空心区域)。
通过alpha通道生成的黑白图像作为mask,将其填充到原图中。生成了bg.jpg.
# 用alpha通道作为mask(bitwise_not)
mask = cv2.resize(a, (resized_hat_w, resized_hat_h))
mask_inv = cv2.bitwise_not(mask)
# 帽子相对与人脸框上线的偏移量
dh = 0
dw = 0
# 原图ROI
bg_roi = img[y+dh-resized_hat_h:y+dh,
(eyes_center[0]-resized_hat_w//3):(eyes_center[0]+resized_hat_w//3*2)]
# 原图ROI中提取放帽子的区域
bg_roi = bg_roi.astype(float)
mask_inv = cv2.merge((mask_inv, mask_inv, mask_inv))
alpha = mask_inv.astype(float)/255
# 相乘之前保证两者大小一致(可能会由于四舍五入原因不一致)
alpha = cv2.resize(alpha, (bg_roi.shape[1], bg_roi.shape[0]))
bg = cv2.multiply(alpha, bg_roi)
bg = bg.astype('uint8')
cv2.imwrite("bg.jpg", bg)
如果你打开bg.jpg,你就会发现这是一个佩带黑色模板的原图帽子区域:
4.将原帽子覆盖至第3步提取出来的空心区域上并放回原图。
接下来要做的,就是将帽子替换到第3部生成的空心区域上并放回原图:
# 提取帽子区域
hat = cv2.bitwise_and(resized_hat, resized_hat, mask=mask)
cv2.imwrite("hat.jpg", hat)
# 相加之前保证两者大小一致(可能会由于四舍五入原因不一致)
hat = cv2.resize(hat, (bg_roi.shape[1], bg_roi.shape[0]))
# 两个ROI区域相加
add_hat = cv2.add(bg, hat)
# 把添加好帽子的区域放回原图
img[y+dh-resized_hat_h:y+dh, (eyes_center[0]-resized_hat_w//3):(
eyes_center[0]+resized_hat_w//3*2)] = add_hat
return 1, img
这样,便完成了整个佩戴圣诞帽的流程。文章完整源代码可在Python实用宝典公众号后台回复:圣诞帽 下载。
我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。
有任何问题,可以在公众号后台回复:加群,回答相应红字验证信息,进入互助群询问。
原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!
点击下方阅读原文可获得更好的阅读体验
Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典