京公网安备 11010802034615号
经营许可证编号:京B2-20210330
作者: 派森酱
来源:Python 技术
随着圣诞节的到来,节日气氛也越来越浓厚。大街上随处可见挂满饰品的圣诞树,好多小伙伴的头上也多了一顶红色牛角的圣诞帽。
往年在这个时候,好多 P图软件 会推出给头像加一顶圣诞帽的功能,甚至有一年大伙 @微信官方 就可以在自己的微信头像上加一顶圣诞帽。
作为一个学习 Python 的技术人,自己可以写程序实现这个功能,做成一个软件当然是一件很酷的事情了。
今天就给大家分享一下如何用 Python 制作一款自动给头像添加圣诞帽的软件。
如果不想看实现,可以直接跳到文末获取软件。
我们的 头像添加圣诞帽软件 制作的大致思路如下:
基于以上思路,我们制作这款软件的关键词有:
看了以上思路,相信大家脑海中已经对这个软件制作的过程有了一个大致的框架了。我们的实现主要分为:图像制作、GUI界面、打包三大块内容。
首先列举一下本次软件制作过程中需要用的的一些包模块:
pip install opencv-python
python 系统模块
pip install dlib
pip install pandas
pip install PySimpleGui
温馨提示:这其中安装 dlib 会遇到很多坑以及很多困难,一般需要一边安装一边上网搜索报错,从而找到解决办法。保证安装过一次之后不想尝试第二次。
我们需要准备一个圣诞帽的图片,格式最好为 png ,因为 png 图片我们可以直接用 Alpha通道 作为掩膜使用。如果是 jpg 图片,需要先转换成 png 格式图片。注意这里的转换不是只改个后缀名,那样是行不通的。
我们用到的圣诞帽如下图:
为了能够与 RGB 通道的头像图片进行运算,我们需要把圣诞帽图像分离成 RGB 通道图像和 alpha通道图像:
r,g,b,a = cv2.split(hat_img)
rgb_hat = cv2.merge((r,g,b))
cv2.imwrite("hat_alpha.jpg",a)
分离之后,得到的 alpha通道图像如下所示:
我从我的百宝箱中选择了一张傻萌傻萌的图片作为程序的测试图片。
大家注意,因为我们要做人脸识别,然后自动添加帽子,所以选择的图片一定要是真人的正面照片,不然识别不了人脸,也就不知道在哪添加圣诞帽。
下面我们用 dlib 的正脸检测器进行人脸检测,用 dlib 提供的模型提取人脸的五个关键点。代码如下:
# dlib人脸关键点检测器 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) # 如果检测到人脸 if len(dets)>0: for d in dets: x,y,w,h = d.left(),d.top(), d.right()-d.left(), d.bottom()-d.top() # x,y,w,h = faceRect cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2,8,0) # 关键点检测,5个关键点 shape = predictor(img, d) for point in shape.parts(): cv2.circle(img,(point.x,point.y),3,color=(0,255,0)) cv2.imshow("image",img) cv2.waitKey()
我们把图片打印出来的效果是这样的:
看到这个图片是不是有点熟悉,网上好多人脸识别的图片都是这样的。
我们选取两个眼角的点,求中心作为放置帽子的x方向的参考坐标,y 方向的坐标用人脸框上线的 y 坐标表示。
然后我们根据人脸检测得到的人脸的大小调整帽子的大小,使得帽子大小合适。
看到这里,你应该明白,我们头像的图片中人的脸越正面那么我们制作出来的效果越好。
# 选取左右眼眼角的点 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))
我们先将帽子的 alpha通道 作为 mask掩膜:
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, x+dw:x+dw+resized_hat_w] 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])) # print("alpha size: ",alpha.shape) # print("bg_roi size: ",bg_roi.shape) bg = cv2.multiply(alpha, bg_roi) bg = bg.astype('uint8')
提取后的效果图如下:
接下来,我们提取圣诞帽的区域:
hat = cv2.bitwise_and(resized_hat,resized_hat,mask = mask)
提取后的效果图如下:
图像处理的最后一步是盖帽了,就是把提取的圣诞帽区域和图片中提取的区域相加,然后再放到原图中去。这里需要注意的就是,相加之前resize一下保证两者大小一致
# 相加之前保证两者大小一致(可能会由于四舍五入原因不一致) hat = cv2.resize(hat,(bg_roi.shape[1],bg_roi.shape[0])) # 两个ROI区域相加 add_hat = cv2.add(bg,hat) # cv2.imshow("add_hat",add_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
最后,我们得到的效果图如下:
我们先来看效果图:
然后再来看这部分的实现代码:
import PySimpleGUI as sg import os.path import cv2
file_list_column = [
[sg.Submit('生成', key='Go', size=(15, 1)), sg.Cancel('退出', key='Cancel', size=(15, 1))],
[
sg.Text("图片位置(选择文件夹)"),
sg.In(size=(25, 1), enable_events=True, key="-FOLDER-"),
sg.FolderBrowse('浏览'),
],
[
sg.Listbox(
values=[], enable_events=True, size=(40, 20), key="-FILE LIST-" )
]
]
image_viewer_column = [
[sg.Text("从左边图片列表中选择一张图片:")],
[sg.Image(key="-IMAGE-")]
]
layout = [
[
sg.Column(file_list_column),
sg.VSeperator(),
sg.Column(image_viewer_column),
]
]
window = sg.Window("人像添加圣诞帽软件", layout)
filename = '' while True:
event, values = window.read() if event == "Cancel" or event == sg.WIN_CLOSED: break if event == "-FOLDER-":
folder = values["-FOLDER-"] try:
file_list = os.listdir(folder) except:
file_list = []
fnames = [
f for f in file_list if os.path.isfile(os.path.join(folder, f)) and f.lower().endswith((".jpg", ".png"))
]
window["-FILE LIST-"].update(fnames) elif event == "-FILE LIST-": try:
filename = os.path.join(values["-FOLDER-"], values["-FILE LIST-"][0]) if filename.endswith('.jpg'):
im = cv2.imread(filename)
cv2.imwrite(filename.replace('jpg', 'png'), im)
window["-IMAGE-"].update(filename=filename.replace('jpg', 'png')) except Exception as e:
print(e) elif event == "Go": try: # output = add_hat(filename) # 展示效果 # cv2.imshow("output",output) # cv2.waitKey(0) # cv2.imwrite("output.png",output) # print(output) window["-IMAGE-"].update(filename='output.png') except:
print('OMG!添加失败了!')
cv2.destroyAllWindows()
这里我选用的是 PySimpleGUI 框架来做的,比较简单。界面分为左右两部分,左边是两个按钮(确定和取消)加一个文件夹选择器,再加一个图片文件列表;右边是一个图片展示框。
左边选择文件夹后,会在下方列出文件夹里包含 .png 和 .jpg 的图片列表。点击图片列表中的图片,会在右边显示你所选择的图片。这个选中的图片也就是我们后面需要添加圣诞帽的图片。
这里需要注意的是,PySimpleGUI 的图片展示默认只支持 png 格式的,所以我在展示的时候做了判断,如果是 jpg 格式的图片,我就用 cv2 将其转换成 png 格式,然后再进行展示。
到这里,我们的关键步骤就完成了。接下来就是将我们两部分代码进行整合。其实也很简单,只需要在 GUI 界面上用户点击 “生成” 按钮时,后台接收到图片的路径,传递给我们的图片处理函数,在处理完后将图片保存在文件夹下,并更新 GUI 界面右边的展示的图片即可。
最终的运行效果:
打包软件我们还是用熟悉的 pyinstaller 模块,将代码打包成可执行的 exe 格式。
首先下载我们所需的模块包:
pip install pyinstaller
接着在命令行敲下打包命令:
pyinstaller christmashat.py
这个 christmashat.py 就是我们所写的程序了。
打包比较耗时,耐心等着就行。打包完成后,在我们代码的目录下会生成三个文件夹:
我们只需要关注 dist 就行。dist 文件夹下面是 christmashat 子文件夹,再进去就可以找到我们的 christmashat.exe 文件了。由于我们的程序运行有两个依赖文件,分别是我们的圣诞帽图片和我们的人脸识别训练集,所以我们需要将这两个文件放入这个 EXE 文件所在的文件夹下。
现在双击 christmashat.exe 文件就可以正常运行了。
本文从一个实际需求出发,向大家讲解了一个头像添加圣诞帽软件的诞生过程。相对于之前的一些小应用来说,涉及的知识点较多,可能还是有点复杂的。其中有一些知识点限于篇幅原因没有详细讲解,大家可以自己私下补充。
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
在用户运营与产品增长体系中,留存是衡量产品真实价值与用户粘性的核心标尺,也是决定用户生命周期价值、获客投产比的底层因素。 ...
2026-07-23 很多数据分析师精通Excel、SQL、Python等工具,但当被问到“面对一个具体的业务问题,该用什么分析方法”“描述性分析和诊断 ...
2026-07-23【核心关键词】埋点、产品、互联网、数据库、决策、数据分析、产品经理、商业模式、移动互联网、指标体系、运营模块、大数据平 ...
2026-07-22在高并发、大数据量的业务系统中,单表数据量达到千万级甚至亿级后,会出现查询性能骤降、索引维护成本飙升、存储扩容困难等问题 ...
2026-07-22 很多企业团队并非缺乏指标,而是陷入“指标失控”:仪表盘上堆满实时跳动的数据,却无法回答“当前瓶颈在哪、下一步该做什么 ...
2026-07-22在金融风控、企业运营、行业研究等数据分析场景中,大量数据以面板数据形态存在:例如多家分支机构连续多个季度的风险指标、多位 ...
2026-07-21 很多数据分析师每天都在计算指标、制作报表,但当被问到“什么叫指标数据元”“指标数据标准包含哪些核心维度”“指标数据质 ...
2026-07-21一、活动介绍 2026暑期CDA备考冲刺季,为想利用假期拿证的你量身打造。考点胶囊内容搭配多重硬核福利,让你在旅行、实习、居家 ...
2026-07-21金融行业的运营风险贯穿业务全流程,涵盖交易欺诈、操作违规、流程漏洞、合规偏差、客户信用异常等多元场景,是银行、保险、证券 ...
2026-07-17财产保险作为金融行业的核心板块,涵盖车险、家财险、责任险、企财险等多元品类,是个人与企业抵御财产风险、经营风险的重要保障 ...
2026-07-17 很多数据分析师能熟练写SQL、做透视表,但当被问到“数据是从哪里来的?经过哪些加工才进入数据仓库?ETL具体做了什么?”时 ...
2026-07-17【核心关键词】模块、餐饮、客户、门店、企业、订单、供应链、多样化、产品、生产计划、数据分析、生产管理、物料管理、业务分 ...
2026-07-16在数字化分析时代,原始数据本身不具备业务价值,只有通过科学的统计学方法加工、拆解、验证与解读,才能挖掘数据背后的规律、差 ...
2026-07-16 很多数据分析师能熟练地写SQL、做透视表、算描述性统计,但当被问到“如何预测用户流失概率”“如何归因销量下滑的关键因素 ...
2026-07-16在描述性统计分析、数据预处理、异常值排查与多组数据分布对比工作中,箱线图(Box Plot)是应用最广泛的可视化与统计工具之一。 ...
2026-07-15在企业数据存储、业务统计与数据分析工作中,绝大多数业务数据都带有时间维度属性,例如订单创建时间、用户注册时间、支付完成时 ...
2026-07-15 很多数据分析师拿到数据就开始清洗、建模,但当被问到“这批数据属于什么类型——结构化还是非结构化?分类变量还是数值变量 ...
2026-07-15【核心关键词】产品、经营、客户、调研、销售额、宏观、会计行业、客户满意度、发展趋势、经营状况、数据分析、竞争对手、数据 ...
2026-07-14问卷调查是市场调研、用户研究、社会调研与产品分析的核心数据采集方式。问卷数据大多以分类数据为主,例如用户性别、年龄分层、 ...
2026-07-14 很多数据分析师画过趋势图、做过业绩预测,但当被问到“这个月销售额增长20%,到底是长期趋势自然增长,还是促销活动的短期 ...
2026-07-14