使用网络摄像头进行眼睛注视估计-600学习网

600学习网终身会员188,所有资源无秘无压缩-购买会员

让我们看看下面的情况。你坐在图书馆里。你刚刚看到最漂亮的女人坐在图书馆的另一边。哦,她发现你在盯着她。她估计你的眼睛在盯着她,你注意到你被她抓住了,因为她知道她的眼睛在指着你。

凝视:一个人眼睛的焦点

就像我们惊人的大脑毫不费力地完成了许多任务一样,这是一个很难”教”计算机的问题,因为我们需要执行几个困难的任务:

·人脸识别

·眼睛识别和瞳孔定位

·确定头部和眼睛的3D定位

商业视线跟踪器有各种形状和尺寸。从眼镜到屏幕的基本解决方案。然而,尽管这些产品非常准确,但它们使用专有的软件和硬件,而且非常昂贵。

让我们开始构建视线跟踪器

为了保持博客的长度合理,我们将构建一种基本的视线跟踪形式。有一些粗略的估计。我们不确定确切的固定点,而是确定固定的方向。

慕课、黑马、极客时间、小码哥、拉钩、尚硅谷、开课吧等千套课程打包VIP套餐,IT课程一网打尽

凝视是相对于相机的,我坐在相机下面

人脸识别和瞳孔定位

对于这项任务,我们将使用MediaPipe(https:/google.github.io/MediaPipe/solutions/face_mesh.html),这是google开发的一个惊人的深度学习框架。它将为我们实时提供468个2D人脸地标,同时使用很少的资源。

让我们看看一些代码:

将mediapipe导入为mp

导入cv2

导入凝视

mp_face_mesh=mp.solutions.face_mesh#初始化面网格模型

#摄像机流:

cap=cv2.VideoCapture(1)

带有mp_face_mesh.FaceMesh(

max_num_faces=1,#每帧中要跟踪的面数

refine_地标=True,#包括人脸网格模型中的虹膜地标

min_检测_置信度=0.5

min_跟踪_置信度=0.5)作为面_网格:

而cap.isOpened():

成功,image=cap.read()

如果不成功:#无帧输入

打印(“忽略空相机框。”)

持续

#为了提高性能,可以选择将图像标记为不可写入

#通过参考。

image.flags.writeable=假

image=cv2.cvtColor(image,cv2.COLOR_BGR2RGB)#人脸网格模型的帧到RGB

results=face_mesh.process(图像)

image=cv2.cvtColor(image,cv2.COLOR_RGB2BGR)

如果结果。多个_面_地标:

凝视.凝视(图像,结果.多人脸地标[0])

cv2.imshow(“输出窗口”,图像)

如果cv2.waitKey(2)和0xFF==27:

打破

盖释放装置()

这里没有什么特别的。在第27行中,我们将当前帧和从mediapipe框架获得的面部标志传递给我们的尺寸函数,这就是所有乐趣所在。

2D到3D?

眼动追踪是一个3D问题,但我们在标题中说,我们只使用了一个简单的网络摄像头,这怎么可能?

我们将使用一些魔法(线姓代数)来实现它。

首先,让我们了解我们的相机是如何”看到”世界的。

慕课、黑马、极客时间、小码哥、拉钩、尚硅谷、开课吧等千套课程打包VIP套餐,IT课程一网打尽

OpenCV文档中的图像

观看屏幕时,2D图像以蓝涩显示,3D世界以世界坐标系显示。他们之间有什么联系?我们如何从2D图像中绘制3D世界,或者至少得到一个粗略的估计?

让我们说清楚!

我们都一样

我们人类比我们想象的更相似。我们可以使用人脸的通用3D模型,这将是对大多数人的3D比例的良好估计。

让我们使用这样的模型来定义三维坐标系。我们将将鼻尖设置为坐标系的原点,并将相对于鼻尖再定义5个点,如下所示:

def凝视(帧,点):

'''

2D图像点。

relative获取归一化为〔-1,1〕的mediapipe点并返回图像点

at(x,y)格式

'''

图像_点=np.array(〔

相对(点地标[4],框架形状),#鼻尖

相对(点.地标[152],框架.形状),#Chin

relative(points.landmark〔263〕,frame.shape),#左眼左角

相对(点地标[33],框架形状),#右眼右角

相对(点地标[287],框架形状),#左嘴角

relative(points.landmark[57],frame.shape)#右嘴角

],dtype=”双”)

#3D模型点。

模型_点=np.array(〔

(0.0,0.0,0.0),#鼻尖

(0,-63.6,-12.5),#Chin

(-43.3,32.7,-26),#左眼左角

(43.3,32.7,-26),#右眼右角

(-28.9,-28.9.-24.1),#左嘴角

(28.9,-28.9,-24.1)#右嘴角

])

'''

3D模型眼点

眼球的中心

'''

眼睛_球_中心_右=np.阵列(〔-29.05〕,〔32.7〕,〔-39.5〕〕)

眼睛_球_中心_左=np.array(〔29.05〕,〔32.7〕,〔-39.5〕〕)

现在我们有6个从mediapipe获得的2D点和我们定义的世界坐标系中的相应3D点。我们的目标是了解这些点的3D位置的变化,并使用我们的2D图像来实现这一点。我们该怎么办?

针孔相机模型的救援

针孔相机模型是一种数学模型,它描述了3D世界中的点与它们在2D图像平面上的投影之间的关系。根据该模型,我们将得到以下方程:

慕课、黑马、极客时间、小码哥、拉钩、尚硅谷、开课吧等千套课程打包VIP套餐,IT课程一网打尽

利用该方程,我们可以获得将3D点投影到图像2D图像平面上的变换。但我们能解决这个问题吗?嗯,至少不是通过简单的代数工具,但你不必担心。这就是OpenCV使用solvePnP函数的地方。请查看链接以获得更深入的解释:

我们将获得6个图像点和相应的3D模型点,并将它们传递给solvepnp函数。作为回报,我们将得到一个旋转和平移向量,从而得到一个变换,这将帮助我们将一个点从3D世界点投影到2D平面。

慕课、黑马、极客时间、小码哥、拉钩、尚硅谷、开课吧等千套课程打包VIP套餐,IT课程一网打尽

'''

摄像机矩阵估计

'''

焦距=框架形状〔1〕

中心=(框架形状〔1〕/2,框架形状〔0〕/2)

摄像机_矩阵=np阵列(

〔焦距〕长度,0,中心〔0〕〕

[0,焦距,中心[1]]

〔0,0,1〕〕,dtype=”双”

)

dist_coeff=np.zeros((4,1))#假设没有镜头畸变

(成功,旋转_矢量,平移_矢量)=cv2.solvePnP(模型_点,图像_点,相机_矩阵,分布_系数,标志=cv2.cv2.solvePnP _迭代)

使用我们的新变换,我们可以从3D空间中获取一个点并将其投影到2D图像平面上。因此,我们将知道这个3D点在空间中的位置。这就是点(0.0150)的样子。

慕课、黑马、极客时间、小码哥、拉钩、尚硅谷、开课吧等千套课程打包VIP套餐,IT课程一网打尽

从3D到2D

现在我们将获取瞳孔2D图像坐标并将其投影到3D模型坐标。这与我们在头部姿势估计部分中所做的相反。

#将图像点投影到世界点

_,变换,_=cv2.estimateAffine3D(图像_点1,模型_点)#图像跳线到世界跳线变换

瞳孔世界帘线=变换@np.array(〔左〕瞳孔〔0〕,左瞳孔〔1〕,0,1〕〕)。T#变换*瞳孔图像点矢量

如代码片段所示,我们将使用OpenCV的估计Affline3D函数。此函数使用与我们讨论的针孔相机模型相同的原理。它获取两组3D点,并返回第一组和第二组之间的变换。但是等等,我们的图像点是二维的。这怎么可能?

我们将获得图像点(x,y),并将其作为(x,y0)传递,因此我们将得到图像坐标和模型坐标之间的转换。使用这种方法,我们可以从我们从mediapipe获得的2D图像点中获得瞳孔的3D模型点。

注:这不是一个非常准确的估计

慕课、黑马、极客时间、小码哥、拉钩、尚硅谷、开课吧等千套课程打包VIP套餐,IT课程一网打尽

我没有告诉你,但是如果你看上面的第二个代码片段,你可以看到我们有眼睛中心模型点(3D)。我们只是使用estimateAffline3D来获得瞳孔3D模型点。

现在要找到视线方向,我们需要解决线-平面相交问题,如上图所示。我们试图找到的点由S表示。让我们将这些点投影到2D平面上。

#将瞳孔图像点投影到世界点

瞳孔世界帘线=变换@np.array(〔左〕瞳孔〔0〕,左〔瞳孔〔1〕,0,1〕〕).T

#3D注视点(10是表示注视距离的任意值)

S=眼睛_球_中心_左+(瞳孔_世界_索-眼睛_球心_左)*10

#将3D凝视点投影到图像平面上。

(眼睛瞳孔2D,雅可比)=cv2.projectPoints((int(S[0]),int(S[1]),int[S[2]),旋转向量,平移向量,相机矩阵,距离系数)

#在屏幕上画视线

p1=(int(左_瞳孔[0]),int(左_瞳孔[1]))

p2=(int(眼睛_瞳孔2D[0][0][0]),int(眼睛_瞳孔2D[0][0][1]))

cv2.line(帧,p1,p2,(0,0,255),2)

注:在第5行中,我们使用了”魔法”数字10,因为我们不知道对象和相机之间的距离。因此,从瞳孔到相机的距离在图中用t表示是未知的

结束了吗?

还没有。现在我们需要考虑头部运动,这样我们的视线跟踪器才能适应头部运动。让我们从一开始就使用我们的头部姿势估计。

慕课、黑马、极客时间、小码哥、拉钩、尚硅谷、开课吧等千套课程打包VIP套餐,IT课程一网打尽

瞳孔的2D位置由点p表示,点g是凝视+头部旋转投影,点h是头部姿势投影。现在,为了获得清晰的视线信息,我们从向量A构造向量B。

#将3D视线方向投影到图像平面上。

(眼睛_瞳孔2D,_)=cv2.projectPoints((int(S[0]),int(S[1]),int(S[2])),旋转_矢量,平移_矢量,相机_矩阵,距离_系数)

#将3D头部姿势投影到图像平面中

(头部姿势,_)=cv2.projectPoints((int(瞳孔世界帘线[0]),int(瞳瞳世界帘线[1]),nt(40)),旋转矢量,平移矢量,相机矩阵,距离系数)

#正确注视头部旋转

凝视=左瞳孔+(眼瞳孔2D[0][0]-左瞳孔)-(头瞳孔姿势[0][0]-左瞳)

在第5行中,我们使用”神奇”数字40,原因与我们在上面的代码片段中使用10的原因相同。

终止

我们已经做到了,至少现在是这样。您可以在Github页面上看到完整的代码并在您的机器上运行它

但我们真的完蛋了吗?

我们可以更改某些内容以提高准确姓:

正确校准相机,不要使用估算值。

用两只眼睛计算两个位置之间的平均值。(我们只使用左眼)

我们正在使用estimateAffine3D方法将二维瞳孔位置投影到三维空间,但这不是一个准确的估计。我们可以使用眼睛结构和瞳孔在眼窝中的位置来推断瞳孔的三维位置。

我们完全忽略了对象和相机之间的距离。因此,我们只能得到一个注视方向,而不是注视点。这可能是最重要的部分,但也是最复杂的部分。

通过一些工作,您可以实现您的解决方案并将其应用于您的特定需求。

免责声明: 1、本站信息来自网络,版权争议与本站无关 2、本站所有主题由该帖子作者发表,该帖子作者与本站享有帖子相关版权 3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和本站的同意 4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责 5、用户所发布的一切软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。 6、您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。 7、请支持正版软件、得到更好的正版服务。 8、如有侵权请立即告知本站,本站将及时予与删除 9、本站所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章和视频仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。
600学习网 » 使用网络摄像头进行眼睛注视估计-600学习网