头像添加圣诞帽python(如何用python做一个圣诞树图案)

作者: 派森酱

作者:帕森斯酱

来源:Python技术

随着圣诞节的到来,节日的气氛越来越浓。街上随处可见挂满装饰物的圣诞树,很多朋友头上还戴着一顶红色牛角的圣诞帽。

往年这个时候很多P图软件都会推出给头像加圣诞帽的功能。甚至有一年,每个人@微信官方都可以在自己的微信头像上加一顶圣诞帽。

作为一个研究Python的技术人员,写一个程序来实现这个功能,做一个软件是很酷的。

今天就和大家分享一下如何用Python做一个自动给头像添加圣诞帽的软件。

如果不想看实现,可以直接跳到文末获取软件。

思路

给我们的头像添加圣诞帽软件的大致思路如下:

要实现一个软件,我们需要制作一个GUI界面供用户操作。要实现在头像上戴圣诞帽的功能,需要用户上传头像,还需要准备一张圣诞帽的图片。要将圣诞帽戴在头像上,我们需要识别头像中的人脸和头部特征,然后将帽子戴在头顶合成一张图片。基于以上想法,制作本软件的关键词是:

GUI界面圣诞帽图片头像图片人脸识别包装软件

实现

已经看过了上面的思路,相信大家对于制作这个软件的过程在脑海中都有一个大概的框架。我们的实现主要分为三个部分:图像制作、图形用户界面和包装。

00-1010首先,列出一些需要在这个软件生产过程中使用的包模块:

Cv2osdlibnumpyPySimpleGUI提示:安装dlib有很多漏洞和困难。一般需要在安装的时候上网搜索错误,这样才能找到解决办法。请确保安装一次后不想重试。

准备工作

图像制作

我们需要准备一张圣诞帽的图片,最好是png格式的,因为我们可以直接使用Alpha通道作为png图片的蒙版。如果是jpg图片,需要先转换成png图片。请注意,这里的转换不仅仅是更改后缀名称,这是行不通的。

我们使用的圣诞帽如下:

不用P图!用Python给头像加圣诞帽并制作成可执行软件

为了操作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通道图像如下所示:

不用P图!用Python给头像加圣诞帽并制作成可执行软件

人脸识别

我从我的百宝箱中选择了一张傻萌傻萌的图片作为程序的测试图片。

不用P图!用Python给头像加圣诞帽并制作成可执行软件

大家注意,因为我们要做人脸识别,然后自动添加帽子,所以选择的图片一定要是真人的正面照片,不然识别不了人脸,也就不知道在哪添加圣诞帽。

下面我们用 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()  

我们把图片打印出来的效果是这样的:

不用P图!用Python给头像加圣诞帽并制作成可执行软件

看到这个图片是不是有点熟悉,网上好多人脸识别的图片都是这样的。

调整帽子大小

我们选取两个眼角的点,求中心作为放置帽子的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')

提取后的效果图如下:

不用P图!用Python给头像加圣诞帽并制作成可执行软件

接下来,我们提取圣诞帽的区域:

hat = cv2.bitwise_and(resized_hat,resized_hat,mask = mask)

提取后的效果图如下:

不用P图!用Python给头像加圣诞帽并制作成可执行软件

盖帽

图像处理的最后一步是盖帽了,就是把提取的圣诞帽区域和图片中提取的区域相加,然后再放到原图中去。这里需要注意的就是,相加之前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

最后,我们得到的效果图如下:

不用P图!用Python给头像加圣诞帽并制作成可执行软件

GUI界面

我们先来看效果图:

不用P图!用Python给头像加圣诞帽并制作成可执行软件

然后再来看这部分的实现代码:

import PySimpleGUI as sgimport os.pathimport cv2file_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 界面右边的展示的图片即可。

最终的运行效果:

不用P图!用Python给头像加圣诞帽并制作成可执行软件

打包软件

打包软件我们还是用熟悉的 pyinstaller 模块,将代码打包成可执行的 exe 格式。

首先下载我们所需的模块包:

接着在命令行敲下打包命令:

这个 christmashat.py 就是我们所写的程序了。

打包比较耗时,耐心等着就行。打包完成后,在我们代码的目录下会生成三个文件夹:

  • __pycache__
  • build
  • dist

我们只需要关注 dist 就行。dist 文件夹下面是 christmashat 子文件夹,再进去就可以找到我们的 christmashat.exe 文件了。由于我们的程序运行有两个依赖文件,分别是我们的圣诞帽图片和我们的人脸识别训练集,所以我们需要将这两个文件放入这个 EXE 文件所在的文件夹下。

现在双击 christmashat.exe 文件就可以正常运行了。

总结

本文从一个实际需求出发,向大家讲解了一个头像添加圣诞帽软件的诞生过程。相对于之前的一些小应用来说,涉及的知识点较多,可能还是有点复杂的。其中有一些知识点限于篇幅原因没有详细讲解,大家可以自己私下补充。

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/158189.html

(0)

相关推荐