Python给你的头像加上圣诞帽


Posted in Python onJanuary 04, 2018

引言

随着圣诞的到来,大家纷纷@官方微信给自己的头像加上一顶圣诞帽。当然这种事情用很多P图软件都可以做到。但是作为一个学习图像处理的技术人,还是觉得我们有必要写一个程序来做这件事情。而且这完全可以作为一个练手的小项目,工作量不大,而且很有意思。

用到的工具

OpenCV(毕竟我们主要的内容就是OpenCV…)

dlib(前一篇文章刚说过,dlib的人脸检测比OpenCV更好用,而且dlib有OpenCV没有的关键点检测。)

用到的语言为Python。但是完全可以改成C++版本,时间有限,就不写了。有兴趣的小伙伴可以拿来练手。

流程一、素材准备

首先我们需要准备一个圣诞帽的素材,格式最好为PNG,因为PNG的话我们可以直接用Alpha通道作为掩膜使用。我们用到的圣诞帽如下图:

Python给你的头像加上圣诞帽

我们通过通道分离可以得到圣诞帽图像的alpha通道。代码如下:

r,g,b,a = cv2.split(hat_img) 
rgb_hat = cv2.merge((r,g,b))

cv2.imwrite("hat_alpha.jpg",a)

为了能够与rgb通道的头像图片进行运算,我们把rgb三通道合成一张rgb的彩色帽子图。Alpha通道的图像如下图所示。

Python给你的头像加上圣诞帽

二、人脸检测与人脸关键点检测

我们用下面这张图作为我们的测试图片。

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()

这部分效果如下图:

Python给你的头像加上圣诞帽

三、调整帽子大小

我们选取两个眼角的点,求中心作为放置帽子的x方向的参考坐标,y方向的坐标用人脸框上线的y坐标表示。然后我们根据人脸检测得到的人脸的大小调整帽子的大小,使得帽子大小合适。

# 选取左右眼眼角的点
 point1 = shape.part(0)
 point2 = shape.part(2)

 # 求两点中心
 eyes_center = ((point1.x+point2.x)//2,(point1.y+point2.y)//2)

 # cv2.circle(img,eyes_center,3,color=(0,255,0)) 
 # cv2.imshow("image",img)
 # cv2.waitKey()

 # 根据人脸大小调整帽子大小
 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一个用于把帽子图中的帽子区域取出来,一个用于把人物图中需要填帽子的区域空出来。后面你将会看到。         

# 用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')

这是的背景区域(bg)如下图所示。可以看到,刚好是需要填充帽子的区域缺失了。

Python给你的头像加上圣诞帽

然后我们提取帽子区域。

# 提取帽子区域
hat = cv2.bitwise_and(resized_hat,resized_hat,mask = mask)

提取得到的帽子区域如下图。帽子区域正好与上一个背景区域互补。

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

最后我们得到的效果图如下所示。

Python给你的头像加上圣诞帽

下载:完整代码。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python脚本实现自动发带图的微博
Apr 27 Python
Python实现购物车功能的方法分析
Nov 10 Python
Python cookbook(数据结构与算法)实现优先级队列的方法示例
Feb 18 Python
如何用python整理附件
May 13 Python
python 字典修改键(key)的几种方法
Aug 10 Python
详解在Python中以绝对路径或者相对路径导入文件的方法
Aug 30 Python
python默认参数调用方法解析
Feb 09 Python
python3用PyPDF2解析pdf文件,用正则匹配数据方式
May 12 Python
Pandas读取csv时如何设置列名
Jun 02 Python
详解Python 最短匹配模式
Jul 29 Python
python -v 报错问题的解决方法
Sep 15 Python
属性与 @property 方法让你的python更高效
Sep 21 Python
Python编程实现线性回归和批量梯度下降法代码实例
Jan 04 #Python
Python语言描述随机梯度下降法
Jan 04 #Python
微信小程序跳一跳游戏 python脚本跳一跳刷高分技巧
Jan 04 #Python
python使用xpath中遇到:到底是什么?
Jan 04 #Python
python使用itchat库实现微信机器人(好友聊天、群聊天)
Jan 04 #Python
python实现微信跳一跳辅助工具步骤详解
Jan 04 #Python
Python中实现最小二乘法思路及实现代码
Jan 04 #Python
You might like
php目录管理函数小结
2008/09/10 PHP
PHP魔术引号所带来的安全问题分析
2014/07/15 PHP
php中curl使用指南
2015/02/05 PHP
PHP代码实现爬虫记录――超管用
2015/07/31 PHP
php实现通过soap调用.Net的WebService asmx文件
2017/02/27 PHP
window.parent调用父框架时 ie跟火狐不兼容问题
2009/07/30 Javascript
javascript之AJAX框架使用说明
2010/04/24 Javascript
Js event事件在IE、FF兼容性问题
2011/01/01 Javascript
myEvent.js javascript跨浏览器事件框架
2011/10/24 Javascript
js如何取消事件冒泡
2013/09/23 Javascript
javascript结合canvas实现图片旋转效果
2015/05/03 Javascript
javascript实现日期按月份加减
2015/05/15 Javascript
jquery插件uploadify实现带进度条的文件批量上传
2015/12/13 Javascript
jQuery实现底部浮动窗口效果
2016/09/07 Javascript
从零学习node.js之express入门(六)
2017/02/25 Javascript
javascript  删除select中的所有option的实例
2017/09/17 Javascript
微信小程序http连接访问解决方案的示例
2018/11/05 Javascript
JS实现的点击按钮图片上下滚动效果示例
2019/01/28 Javascript
vue cli安装使用less的教程详解
2019/07/12 Javascript
jquery实现垂直手风琴菜单
2020/03/04 jQuery
Python使用email模块对邮件进行编码和解码的实例教程
2016/07/01 Python
python最长回文串算法
2018/06/04 Python
使用Python爬虫爬取小红书完完整整的全过程
2021/01/19 Python
联想台湾官网:Lenovo TW
2018/05/09 全球购物
介绍一下linux文件系统分配策略
2013/02/25 面试题
小区门卫值班制度
2014/01/24 职场文书
30年同学聚会感言
2014/01/30 职场文书
安全生产月活动总结
2014/05/04 职场文书
运动会方队口号
2014/06/07 职场文书
2014年民主评议党员个人总结
2014/09/24 职场文书
2016猴年春节慰问信
2015/11/30 职场文书
2019广播稿怎么写
2019/04/17 职场文书
解决Golang中goroutine执行速度的问题
2021/05/02 Golang
logback如何自定义日志存储
2021/08/30 Java/Android
CentOS MySql8 远程连接实战
2022/04/19 MySQL
Spring Cloud OpenFeign模版化客户端
2022/06/25 Java/Android