赠书 | Python人脸五官姿态检测
作者 | 李秋键
出品 | AI科技大本营
近几个月来由于疫情的影响使得网络授课得到了快速的发展,人工智能作为最有潜力的发展行业,同样可以应用于网络授课的监督。比如通过检测人脸姿态,眼睛是否张开,鼻子嘴巴等特征,来达到监测专注度等情绪特征。故本文主要是基于Github项目搭建pytorch项目实现人脸姿态监测。
此源码地址:
https://github.com/WIKI2020/FacePose_pytorch
*文末有赠书福利
并且该算法已应用于以下两种产品:儿童在线教育,用于识别儿童是否认真听讲;现场会议或学校教室,以判断演讲质量。
人脸检测是指从复杂的背景当中提取我们感兴趣的人脸图像。脸部毛发、化妆品、光照、噪声、人脸倾斜和大小变化及各种遮挡等因素都会有导致人脸检测问题变得更为复杂。人脸识别技术主要目的在于输入的整幅图像上寻找特定人脸区域,从而为后续的人脸识别做准备。其中三大关键技术:基于特征的人脸检测技术;基于模板匹配人脸检测技术;基于统计的人脸检测技术
一般常用的算法特点如下:
1、Dlib:面部关键点识别不准确,旋转或滚动面部时误差很大。
2、虚拟3D模型:将关键点的识别与“2D到3D虚拟修复模型”进行比较非常不准确,因为每个人的面孔都不一样。
3、3DDFA:效果很差,我不知道为什么有那么多“github星星”。
4、通过卷积网络统计出关键点位图,角度也很不准确。
实验前的准备
首先我们使用的python版本是3.6.5所用到的模块如下:
opencv是将用来进行图像处理和生成。
numpy模块用来处理矩阵数据的运算。
pytorch模块是常用的用来搭建模型和训练的深度学习框架。
math是python中用来存储一些常见的数学函数库。
网络模型的定义和训练
(1)脸部特征提取:使用Retinaface提取面部框架,然后使用PFLD识别面部关键点。最后,关键点被跟踪以估计面部姿势。
def calculate_pitch_yaw_roll(landmarks_2D, cam_w=256, cam_h=256,radians=False):""" Return thethe pitch yaw and roll angles associatedwith the input image.@param radians When True itreturns the angle in radians, otherwise in degrees."""assert landmarks_2D is not None,'landmarks_2D is None'# Estimated camera matrixvalues.c_x = cam_w / 2c_y = cam_h / 2f_x = c_x / np.tan(60 / 2 *np.pi / 180)f_y = f_xcamera_matrix =np.float32([[f_x, 0.0, c_x], [0.0, f_y, c_y],[0.0, 0.0, 1.0]])camera_distortion =np.float32([0.0, 0.0, 0.0, 0.0, 0.0])# dlib (68 landmark) trachedpoints# TRACKED_POINTS = [17, 21, 22,26, 36, 39, 42, 45, 31, 35, 48, 54, 57, 8]# wflw(98 landmark) trachedpoints# TRACKED_POINTS = [33, 38, 50,46, 60, 64, 68, 72, 55, 59, 76, 82, 85, 16]# X-Y-Z with X pointing forwardand Y on the left and Z up.# The X-Y-Z coordinates used arelike the standard coordinates of ROS (robotic operative system)# OpenCV uses the referenceusually used in computer vision:# X points to the right, Y down,Z to the frontlandmarks_3D = np.float32([[6.825897, 6.760612,4.402142], # LEFT_EYEBROW_LEFT,[1.330353, 7.122144,6.903745], # LEFT_EYEBROW_RIGHT,[-1.330353, 7.122144,6.903745], # RIGHT_EYEBROW_LEFT,[-6.825897, 6.760612,4.402142], # RIGHT_EYEBROW_RIGHT,[5.311432, 5.485328,3.987654], # LEFT_EYE_LEFT,[1.789930, 5.393625,4.413414], # LEFT_EYE_RIGHT,[-1.789930, 5.393625,4.413414], # RIGHT_EYE_LEFT,[-5.311432, 5.485328,3.987654], # RIGHT_EYE_RIGHT,[-2.005628, 1.409845,6.165652], # NOSE_LEFT,[-2.005628, 1.409845,6.165652], # NOSE_RIGHT,[2.774015, -2.080775,5.048531], # MOUTH_LEFT,[-2.774015, -2.080775,5.048531], # MOUTH_RIGHT,[0.000000, -3.116408, 6.097667], # LOWER_LIP,[0.000000, -7.415691,4.070434], # CHIN])landmarks_2D =np.asarray(landmarks_2D, dtype=np.float32).reshape(-1, 2)# Applying the PnP solver tofind the 3D pose of the head from the 2D position of the landmarks.# retval - bool# rvec - Output rotation vectorthat, together with tvec, brings points from the world coordinate system to thecamera coordinate system.# tvec - Output translationvector. It is the position of the world origin (SELLION) in camera co-ords_, rvec, tvec =cv2.solvePnP(landmarks_3D, landmarks_2D,camera_matrix, camera_distortion)#Get as input the rotationalvector, Return a rotational matrix# const double PI = 3.141592653;# double thetaz = atan2(r21,r11) / PI * 180;# double thetay = atan2(-1 *r31, sqrt(r32*r32 + r33*r33)) / PI * 180;# double thetax = atan2(r32,r33) / PI * 180;rmat, _ = cv2.Rodrigues(rvec)pose_mat = cv2.hconcat((rmat,tvec))_, _, _, _, _, _, euler_angles =cv2.decomposeProjectionMatrix(pose_mat)return map(lambda k: k[0], euler_angles) # euler_angles contain (pitch,yaw, roll)
(2)计算和绘制特征图形函数的定义:收集面部角度转换数据,并通过数百人的面部的旋转关键点拟合了一个简单的线性模型。实验表明,简单的数学线性点模型更加有效和准确。
class AverageMeter(object):"""Computes and stores the average and current value"""def __init__(self):self.reset()def reset(self):self.val = 0self.avg = 0self.sum = 0self.count = 0def update(self, val, n=1):self.val = valself.sum += val * nself.count += nself.avg = self.sum / self.count
def vis_landmark(img_path, annotation, norm, point_num):"""line format: [img_name bbox_x1 bbox_y1 bbox_x2 bbox_y2 landmark_x1 landmark y1 ...]"""# check point lenassert len(line) == 1+4+point_num*2 # img_path + bbox + point_num*2img = cv2.imread(img_path)h, w = img.shape[:2]img_name = annotation[0]bbox_x1, bbox_y1, bbox_x2, bbox_y2 = annotation[1:5]landmark = annotation[5:]landmark_x = line[1+4::2]landmark_y = line[1+4+1::2] if norm:for i in range(len(landmark_x)):landmark_x[i] = landmark_x[i] * wlandmark_y[i] = landmark_y[i] * h# draw bbox and face landmarkcv2.rectangle(img, (int(bbox_x1), int(bbox_y1)), (int(bbox_x2), int(bbox_y2)), (0, 0, 255), 2)for i in range(len(landmark_x)):cv2.circle(img, (int(landmark_x[i]), int(landmark_y[i])), 2, (255, 0, 0), -1)cv2.imshow("image", img)cv2.waitKey(0)
(3)网络层的定义:
import torch
import torch.nn as nn
import math
def conv_bn(inp, oup, kernel, stride, padding=1):return nn.Sequential(nn.Conv2d(inp, oup, kernel, stride, padding, bias=False),nn.BatchNorm2d(oup),nn.ReLU(inplace=True))
def conv_1x1_bn(inp, oup):return nn.Sequential(nn.Conv2d(inp, oup, 1, 1, 0, bias=False),nn.BatchNorm2d(oup),nn.ReLU(inplace=True))
class PFLDInference(nn.Module):def __init__(self):super(PFLDInference, self).__init__()self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1, bias=False)self.bn1 = nn.BatchNorm2d(64)self.relu = nn.ReLU(inplace=True)self.conv2 = nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1, bias=False)self.bn2 = nn.BatchNorm2d(64)self.relu = nn.ReLU(inplace=True)self.conv3_1 = InvertedResidual(64, 64, 2, False, 2)self.block3_2 = InvertedResidual(64, 64, 1, True, 2)self.block3_3 = InvertedResidual(64, 64, 1, True, 2)self.block3_4 = InvertedResidual(64, 64, 1, True, 2)self.block3_5 = InvertedResidual(64, 64, 1, True, 2)self.conv4_1 = InvertedResidual(64, 128, 2, False, 2)self.conv5_1 = InvertedResidual(128, 128, 1, False, 4)self.block5_2 = InvertedResidual(128, 128, 1, True, 4)self.block5_3 = InvertedResidual(128, 128, 1, True, 4)self.block5_4 = InvertedResidual(128, 128, 1, True, 4)self.block5_5 = InvertedResidual(128, 128, 1, True, 4)self.block5_6 = InvertedResidual(128, 128, 1, True, 4)self.conv6_1 = InvertedResidual(128, 16, 1, False, 2) # [16, 14, 14]self.conv7 = conv_bn(16, 32, 3, 2) # [32, 7, 7]self.conv8 = nn.Conv2d(32, 128, 7, 1, 0) # [128, 1, 1]self.bn8 = nn.BatchNorm2d(128)self.avg_pool1 = nn.AvgPool2d(14)self.avg_pool2 = nn.AvgPool2d(7)self.fc = nn.Linear(176, 196)
模型的调用和显示
(1)根据点坐标绘制标注图形:
def point_line(point,line):x1 = line[0] y1 = line[1]x2 = line[2]y2 = line[3]x3 = point[0]y3 = point[1]k1 = (y2 - y1)*1.0 /(x2 -x1)b1 = y1 *1.0 - x1 *k1 *1.0k2 = -1.0/k1b2 = y3 *1.0 -x3 * k2 *1.0x = (b2 - b1) * 1.0 /(k1 - k2)y = k1 * x *1.0 +b1 *1.0return [x,y]def point_point(point_1,point_2):x1 = point_1[0]y1 = point_1[1]x2 = point_2[0]y2 = point_2[1]distance = ((x1-x2)**2+(y1-y2)**2)**0.5return distancedef point_line(point,line):x1 = line[0] y1 = line[1]x2 = line[2]y2 = line[3]x3 = point[0]y3 = point[1]k1 = (y2 - y1)*1.0 /(x2 -x1)b1 = y1 *1.0 - x1 *k1 *1.0k2 = -1.0/k1b2 = y3 *1.0 -x3 * k2 *1.0x = (b2 - b1) * 1.0 /(k1 - k2)y = k1 * x *1.0 +b1 *1.0return [x,y]
(2)主函数定义:通过加载训练好的模型和定义好的特征参数,通过摄像头获取的视频流或是读取本地视频和图片进行输出姿态特点:
def main(args):checkpoint = torch.load(args.model_path, map_location=device)plfd_backbone = PFLDInference().to(device)plfd_backbone.load_state_dict(checkpoint['plfd_backbone'])plfd_backbone.eval()plfd_backbone = plfd_backbone.to(device)transform = transforms.Compose([transforms.ToTensor()])videoCapture = cv2.VideoCapture(args.image_name)fps = videoCapture.get(cv2.CAP_PROP_FPS)size = (int(videoCapture.get(cv2.CAP_PROP_FRAME_WIDTH)),int(videoCapture.get(cv2.CAP_PROP_FRAME_HEIGHT)))print("fps:",fps,"size:",size)videoWriter = cv2.VideoWriter("./video/result.avi",cv2.VideoWriter_fourcc('X','V','I','D'),fps,size)success,img = videoCapture.read()cv2.imwrite("1.jpg",img)while success:height, width = img.shape[:2]model_test = AntiSpoofPredict(args.device_id)image_bbox = model_test.get_bbox(img)x1 = image_bbox[0]y1 = image_bbox[1]x2 = image_bbox[0] + image_bbox[2]y2 = image_bbox[1] + image_bbox[3]w = x2 - x1h = y2 - y1size = int(max([w, h]))cx = x1 + w/2cy = y1 + h/2x1 = cx - size/2x2 = x1 + sizey1 = cy - size/2y2 = y1 + sizedx = max(0, -x1)dy = max(0, -y1)x1 = max(0, x1)y1 = max(0, y1)edx = max(0, x2 - width)edy = max(0, y2 - height)x2 = min(width, x2)y2 = min(height, y2)cropped = img[int(y1):int(y2), int(x1):int(x2)]if (dx > 0 or dy > 0 or edx > 0 or edy > 0):cropped = cv2.copyMakeBorder(cropped, dy, edy, dx, edx, cv2.BORDER_CONSTANT, 0)cropped = cv2.resize(cropped, (112, 112))input = cv2.resize(cropped, (112, 112))input = cv2.cvtColor(input, cv2.COLOR_BGR2RGB)input = transform(input).unsqueeze(0).to(device)_, landmarks = plfd_backbone(input)pre_landmark = landmarks[0]pre_landmark = pre_landmark.cpu().detach().numpy().reshape(-1, 2) * [112, 112]point_dict = {}i = 0for (x,y) in pre_landmark.astype(np.float32):point_dict[f'{i}'] = [x,y]i += 1
效果如下图所示:
源码地址:
https://github.com/WIKI2020/FacePose_pytorch
#欢迎留言在评论区和我们讨论#
看完本文,对于python实现人脸检测你有什么想说的?
欢迎在评论区留言
我们将在 10 月 22 日精选出 3 条优质留言
赠送价值148元的《python机器学习一本通》纸质书籍一本哦!
更多精彩推荐
四款5G版iPhone 12齐发,苹果股价却应声而跌
听说你的模型训练耗时太长?来昇腾开发者沙龙找解决方案
图神经网络快速爆发,最新进展都在这里了
官宣!1024 程序员节日程发布,第一代程序员求伯君将出席大会
如何应对云原生之旅中的安全挑战?
相关文章:

明白了这十个故事,你也就参悟了人生
1、断箭 不相信自己的意志,永远也做不成将军。 春秋战国时代,一位父亲和他的儿子出征打仗。父亲已做了将军,儿子还只是马前卒。又一阵号角吹响,战鼓雷鸣了,父亲庄严地托起一个箭囊,其中插着一只箭。…

java中的几种对象(PO,VO,DAO,BO,POJO)
一、PO :(persistant object ),持久对象 可以看成是与数据库中的表相映射的java对象。使用Hibernate来生成PO是不错的选择。二、VO :(value object) ,值对象通常用于业务层之间的数据传递,和PO一样也是仅仅包含数据而已。但应是抽象出的业务对…

jquery文件上传控件 Uploadify
基于jquery的文件上传控件,支持ajax无刷新上传,多个文件同时上传,上传进行进度显示,删除已上传文件。 要求使用jquery1.4或以上版本,flash player 9.0.24以上。 有两个版本,一个用flash,一个是html5。html5…
AI 还原康乾盛世三代皇帝的样貌,简直太太太好玩了!
作者 | Jack Cui出品 | AI科技大本营一位 B 站 up 主「Jack Cui」使用 AI 技术,还原了康熙、雍正、乾隆的历史样貌。看看富态的雍正!!算法实现人工智能技术,可以实现很多有趣而又有意义的事情。 利用 StyleGAN 算法,可…

男人一生中要做的事
作者:未知 请作者速与本人联系揽住母亲的肩头: 每个人都是最棒的,父体的千万个细胞中最强壮的一个才能跑到最前面与来自母体的细胞结合。这时,有二分之一的机会会诞生一个男人。儿子,无疑是父亲所有理想的最好载体&am…

【BZOJ2157】旅游
2157: 旅游 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 1460 Solved: 656[Submit][Status][Discuss]Description Ray 乐忠于旅游,这次他来到了T 城。T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接。为了方便游客到…

PHP面向对象精要
1 使用extends实现继承以及重载、魔术方法的含义 class B extends A 声明的时候B里可以没有A里的方法 调用的时候$bnew B(); $b->A里的方法(); $b->A里的属性1; $b->B里的方法(); $b->B里的方法(); 如果$anew A(); 可以 $a->A里的方法(); $a->A里…
码农新机会!2019-2020行业调查报告出炉,这个领域程序员缺口很大!
近日,CSDN发布了《2019-2020中国开发者调查报告》,本报告从2004年开始针对一年一度的CSDN开发者大调查数据分析结果形成,是迄今为止覆盖国内各类开发者人群数量最多、辐射地域、行业分布最广的调查活动。笔者从本次调查中,挑选出一…

线性代数与矩阵论 定理 1.5.6 拉格朗日插值公式
给定域$\mathbf{F}$中$n1$个不同的数$\alpha_1,\alpha_2,\cdots,\alpha_{n1}$,以及域$\mathbf{F}$中另外$n1$个数$\beta_1,\beta_2,\cdots,\beta_{n1}$,则唯一存在域$\mathbf{F}$中一个次数不超过$n$的多项式$f(x)$,使得$f(\alpha_j)\beta_j,1\leq j\leq n1$,其中 \begin{equat…

Android的ToolBar
ToolBar比ActionBar更加可控,自由。因此,Google 逐渐使用ToolBar来代替ActionBar。 使用ToolBar 1.要引入appCompat_v7支持 2.主题设置为NoActionBar 在style.xml文件中 <style name"MyAppTheme" parent"Theme.AppCompat.Light.NoActi…

利用.NET的XML序列化解决系统配置问题
作者:未知 请作者速与本人联系 出自: http://blog.csdn.net/ycl111/在Web系统开发中,我们经常需要读取和设置一些系统配置项,常见的例如数据库连接字符串、上传路径等等。在最初的ASP系统中,比较常用的方法是将值保存…
告别CNN?一张图等于16x16个字,计算机视觉也用上Transformer了
编译 | 凯隐出品 | AI科技大本营(ID:rgznai100)Transformer是由谷歌于2017年提出的具有里程碑意义的模型,同时也是语言AI革命的关键技术。在此之前的SOTA模型都是以循环神经网络为基础(RNN, LSTM等)。从本质上来讲&…

mysql left join,right join,inner join用法分析
2019独角兽企业重金招聘Python工程师标准>>> 下面是例子分析 表A记录如下: aID aNum 1 a20050111 2 a20050112 3 a20050113 4 a20050114 5 a20050115 表B记录如下: bID bName 1 2006032401 2 2006032402 3 2006032403 4 200603240…

如果BarTender出现卸载不干净的问题如何处理
自从BarTender 2016出了之后,好多小伙伴都想试试新功能咋样,这就意味着首先要卸载电脑上旧版BarTender。然而就是这个操作,难倒了好一批人,他们表示BarTender卸载卸不干净,不仅旧版的用不起来了,新版BarTen…

iometer硬盘测试工具附教程
教程地址http://servers.pconline.com.cn/skills/0711/1145597.html转载于:https://blog.51cto.com/cywin7/1081456
Python炫技操作:模块重载的五种方法
作者 | 写代码的明哥来源 | Python编程时光环境准备新建一个 foo 文件夹,其下包含一个 bar.py 文件$ tree foofoo└── bar.py 0 directories, 1 filebar.py 的内容非常简单,只写了个 print 语句print("successful to be imported")只要 bar.…

使用Powershell管理Linux 下的 SQL Server
使用Powershell管理Linux 下的 SQL Server我们上一篇文章介绍了在Centos 7.3下安装及配置 SQL Server,今天我们主要介绍的是如何在Windows下使用Powershell来管理Linux下的SQL Server,其实说到Powershell大家都已经很熟悉了,Powershell不止是…
这么多年,终于有人讲清楚Transformer了
作者 | Jay Alammar译者 | 香槟超新星,责编 | 夕颜来源 | CSDN(ID:CSDNnews)注意力机制是一种在现代深度学习模型中无处不在的方法,它有助于提高神经机器翻译应用程序性能的概念。在本文中,我们将介绍Transformer这种模…

提高IIS网站服务器的效率的八种方法 (转载)
作者:未知 请作者速与本人联系以下是提高IIS 5.0网站服务器的执行效率的八种方法: 1. 启用HTTP的持续作用可以改善15~20%的执行效率。 2. 不启用记录可以改善5~8%的执行效率。 3. 使用 [独立] 的处理程序会损失20%的执行效率。 4. 增加快取记忆体的保存…

搭建Docker私有仓库--自签名方式
为了能集中管理我们创建好的镜像,方便部署服务,我们会创建私有的Docker仓库。通读了一遍官方文档,Docker为了确保安全使用TLS,需要CA认证,认证时间长的要钱啊,免费过期时间太短,还是用自签名比较简单。 准备…

Visual C# .NET 2003 语言的改变
Visual C# .NET 2003 语言的改变 Prashant Sridharan Microsoft Corporation 2002年12月30日 适用于: Microsoft Visual Studio C# 2003 摘要:为了与欧洲计算机制造商协会 (ECMA) 的 C# 规范完全兼容,Microsoft Corporation 对 C# 编译器的…

.net内存管理与指针
本人前段时间准备做个TIN三角网的程序,思想是是分割合并法,分割的同时建立平衡二叉树,然后子树建三角网并相互合并,再向上加入父亲的点集。由于我对.net语言熟点,就准备用c#语言实现。但是不知从那听过当建立的类型只想…
强化学习是针对优化数据的监督学习?
作者 | Ben Eysenbach、Aviral Kumar、Abhishek Gupta 编译 | 凯隐出品 | AI科技大本营(ID:rgznai100)强化学习(RL)可以从两个不同的视角来看待:优化和动态规划。其中,诸如REINFORCE等通过计算不可微目标期…

solrcloud Read and Write Side Fault Tolerance
2019独角兽企业重金招聘Python工程师标准>>> SolrCloud supports elasticity, high availability, and fault tolerance in reads and writes. What this means, basically, is that when you have a large cluster, you can always make requests to the cluster: …

XML的二十个热点问题
http://www.netqu.com 中华技术网会员 Wuxuehui 发布翻译:Chen Zhihong 编辑:孙一中这些日子,几乎每个人都在谈论XML (Extensible Markup Language),但是很少有人真正理解其含义。XML的推崇者认为它能够解决所有HTML不能解决的问题࿰…
5G+云网融合,移动云带领开发者释放边缘计算的力量
在5G浪潮的驱动下,智能设备、自动驾驶、VR/AR等对于实时性、本地性有着较强需求的场景日益丰富,边缘计算应运而生,有效提升了用户体验。众所周知,边缘计算技术的突破,意味着许多控制将通过本地设备实现而无需交由云端&…

Linux下模拟RAID5实现磁盘损坏,数据自动切换到备份磁盘上
另一个博客地址:www.rsyslog.org Linux社区 RAID5磁盘配额, 1块磁盘,分5个分区模拟5块磁盘,其中4个做成RAID5分区,剩余一个作为冗余磁盘,挂载到/data1目录,模拟其中一块磁盘损坏,冗…

jsp9大内置对象
转载于:https://www.cnblogs.com/xtdxs/p/6523059.html

RHCSA 解析-01
这是RHCSA题目开始正式做题前的准备部分。 后面会陆续连载部分类似的题型极其解法。 考试时间:RHCSA 2.5小时 总分300分,210分pass考试环境:考试为上机考试,在一台真实机系统中,已经预安装好虚拟机,要求所…

关于Visual C#装箱与拆箱的研究
关于Visual C#装箱与拆箱的研究2004-09-15 作者: 出处: CSDN在对这个问题展开讨论之前,我们不妨先来问这么几个问题,以系统的了解我们今天要探究的主题。观者也许曾无数次的使用过诸如System.Console类或.NET类库中那些品种繁多的…