Python OpenCv实现实时人脸识别和人脸测距

准备

在开发面部测距之前,首先在你的 Python 中安装四个库,分别是 cvzone 库、mediapipe 库、tensorflow 库和 tensorflow GPU 库。安装 cvzone 库和 mediapipe 库更快。直接使用下面的语句就可以快速安装

点安装 cvzone

点安装媒体管道

在安装tensorflow库和tensorflow GPU库时,由于库文件较大,常规的安装方法经常会下载到一半失败。这里推荐使用以下命令。我自己测试过,可以快速安装。

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple tensorflow

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple tensorflow-gpu

确保以上四个库都安装成功后,就可以开始写代码了。

原则

OpenCv主要利用相似三角形原理实现人脸测距,如下图

参数说明:

(1)相机的焦距f是固定的;

(2) W是相机成像后人眼的像素距离。通过findFaceMesh()识别人脸网格后可以测量人眼的像素距离w;

(3) W是现实中左眼和右眼之间的距离。男性的平均瞳距为 64 毫米,女性为 62 毫米。本项目开发取中间值63mm;

(4) d 是您想要获取的从实际人到相机的距离。通过相似三角形原理,将公式变换后可以计算出人到相机的距离公式:du003d(f*W)/w

笔记:

不同的相机有不同的焦距。如果您知道相机本身的参数是最好的,您可以直接替换它们进行精确计算。如果不知道相机参数,需要多次手动校正确定焦距f。手动校正需要多测量几个数据,然后计算平均值以保证焦距f的准确性,从而提高测距精度。手动校正,先固定眼睛到相机的距离,比如50cm,用卷尺准确测量,多测几次,找到焦距F。测量焦距f的具体代码如下图:

导入 cv2

导入 cvzone

from cvzone.FaceMeshModule import FaceMeshDetector #导入检测器

##这里是导入相机

上限 u003d cv2.VideoCapture(0)

detector u003d FaceMeshDetector(maxFaces u003d 1) #检测人脸,只检测一张人脸。最后1表示最多只能检测到一张人脸

当真:

成功,img u003d cap.read()

img,faces u003ddetector.findFaceMesh(img,draw u003d False) #找到人脸后,返回人脸u003dfalse

if faces: #如果面孔可用

##通过下面的语句找到左眼和右眼的两个点

face u003d faces[0] #第一阶段

pointLeft u003d face[145] #左边的值基本是145

pointRight u003d face[374] #右边的值基本都是374

###以下是寻找焦距的过程

##以像素为单位查找距离

w,_ u003ddetector.findDistance(pointLeft,pointRight) #将左眼点位置到右眼点位置的距离赋值给w,w后面的下划线忽略其他值

W u003d 6.3 #这是人眼左右眼的距离,即63mm。取中间值,男性为64mm,女性为62mm

d u003d 50 #距离假设为50cm

f u003d (w * d) / W #将焦距公式代入

打印(女)

cv2.imshow("图像",img)

cv2.waitKey(1)

通过上面的代码多次测量焦距f,求平均值。我使用的相机焦距是300,所以后面我的代码中f u003d 300。在这里,根据我的实际焦距代替测量。接下来将焦距f代入测量公式d u003d (f*W) / w,具体代码如下图:

导入 cv2

导入 cvzone

from cvzone.FaceMeshModule import FaceMeshDetector #导入检测器

##这里是导入相机

上限 u003d cv2.VideoCapture(0)

detector u003d FaceMeshDetector(maxFaces u003d 1) #人脸检测

当真:

成功,img u003d cap.read()

img,faces u003ddetector.findFaceMesh(img,draw u003d False) #做一个检测器,找到人脸网格,返回图片(img)和我们的人脸。画u003d假。有了这句话,我们就看不到网格了

if faces: #如果面孔可用

##通过下面的语句找到左眼和右眼的两个点

face u003d faces[0] #第一阶段

pointLeft u003d face[145] #左边的值基本是145

pointRight u003d face[374] #右边的值基本都是374

##这里是眼睛两点之间的距离

cv2.line(img, pointLeft, pointRight, (0, 200, 0), 3) # 在眼睛的两点之间画一条线。起点是pointLeft,终点是pointRight。线条颜色为绿色,线条宽度为3

cv2.circle(img,pointLeft,5,(255,0,255),cv2.FILLED) #在img图像上画一个圆。中心点为pointLeft,半径为5,颜色为紫色。最终运行结果可以在成像仪左眼标记紫点

cv2.circle(img,pointRight,5,(255,0,255),cv2.FILLED) #在img图像上画一个圆。中心点为pointRighe,半径为5,颜色为紫色。最终运行结果可以在成像仪右眼标出紫点

w, _ u003ddetector.findDistance(pointLeft, pointRight) # 赋值左眼点位置到右眼点位置到w的距离,w后面的下划线忽略其他值

W u003d 6.3 #这是人眼左右眼的距离,即63mm。取中间值,男性为64mm,女性为62mm

###查找距离

##根据上式f u003d (w * d) / W,可以粗略测出,人眼距离相机50cm时,相机焦距约为300

##然后将找到的焦距代入距离计算公式,即可计算出距离

f u003d 300

d u003d (W * f) / w

打印(d)

##下面是距离的文字,跟随着人脸,在额头位置输出

cvzone.putTextRect(img,f'深度:{int(d)}cm',(面[10][0]-95,面[10][1]-5), scale u003d 1.8) #距离文字以字符串的形式显示在图像上,单位为cm。文字值的位置随着人脸的移动显示在额头上(额头上的id为10,即人脸[10],下面的人脸[10][0]表示第一个元素,face[10][1] 表示第二个元素),

上面的##scale u003d 2表示图片上输出文本框的大小

##face[10][0]左右改变,face[10][1]改变显示高度

cv2.imshow("图像",img)

cv2.waitKey(1)

最终测试结果如下:

多人同时测距见以下代码。我还没有优化它。多人同时测距时,会浮动,不稳定。

导入 cv2

导入 cvzone

from cvzone.FaceMeshModule import FaceMeshDetector #导入检测器

##这里是导入相机

上限 u003d cv2.VideoCapture(0)

检测器 u003d FaceMeshDetector(maxFacesu003d3)

当真:

成功,img u003d cap.read()

img,faces1 u003d 检测器.findFaceMesh(img)

img,faces2 u003d 检测器.findFaceMesh(img)

img,faces3 u003d 检测器.findFaceMesh(img)

W u003d 6.3 #这是人眼左右眼的距离,即63mm。取中间值,男性为64mm,女性为62mm

if faces1: #如果检测到人脸

面1 u003d 面1[0]

pointLeft1 u003d face1[145] #左眼的人脸值为145

pointRight1 u003d face1[374] #右眼的人脸值为374

##这里是两只眼睛的距离

cv2.line(img,pointLeft1,pointRight1,(0,200,0),3) #眼睛里

cv2.circle(img,pointLeft1,5,(255,0,255),cv2.FILLED) #在img图像上画一个圆,圆心为pointLeft,半径为5,颜色为紫色

#cv2.circle(img,pointRight1,5,(255,0,255),cv2.FILLED) #在img图像上画一个圆,中心点为pointRight,半径为5,颜色为紫色

w1, _ u003ddetector.findDistance(pointLeft1, pointRight1) # 将第一张脸的左眼到右眼的位置距离赋值给w1。 w1 后面的下划线表示忽略其他值

###查找距离

##根据上式f u003d (w * d) / W,可以粗略测出,人眼距离相机50cm时,相机焦距约为300

##然后将找到的焦距代入距离计算公式,即可计算出距离

f u003d 300

d1 u003d (W * f) / w1

cvzone.putTextRect(img, f'Depth:{int(d1)}cm', (face1[10][0] - 95, face1[10][1] - 5),比例 u003d 1.8)

if faces2: ##这表示当第一个面被测试时,如果第二个面再次出现,就会显示标记

面2 u003d 面2[0]

pointLeft2 u003d face2[145] # 左眼的人脸值为145

pointRight2 u003d face2[374] # 右眼的人脸值为374

#cv2.line(img, pointLeft2, pointRight2, (0, 200, 0), 3) # 眼睛里

cv2.circle(img, pointLeft2, 5, (255, 0, 255), cv2.FILLED) # 在img图像上画一个圆,中心点为pointLeft,半径为5,颜色为紫色

cv2.circle(img, pointRight2, 5, (255, 0, 255), cv2.FILLED) # 在img图像上画一个圆,中心点为pointRight,半径为5,颜色为紫色

w2,_ u003ddetector.findDistance(pointLeft2,pointRight2) #将第一张脸的左眼到右眼的位置距离赋值给w1。 w1 后面的下划线表示忽略其他值

###查找距离

##根据上式f u003d (w * d) / W,可以粗略测出,人眼距离相机50cm时,相机焦距约为300

##然后将找到的焦距代入距离计算公式,即可计算出距离

f u003d 300

d2 u003d (W * f) / w2

cvzone.putTextRect(img, f'Depth:{int(d2)}cm', (face2[10][0] - 95, face2[10][1] - 5),规模u003d1.8)

如果面临3:

面3 u003d 面3[0]

pointLeft3 u003d face3[145] #左眼的人脸值为145

pointRight3 u003d face3[374] # 右眼的人脸值为374

cv2.line(img, pointLeft3, pointRight3, (0, 200, 0), 3) # 眼睛里

cv2.circle(img, pointLeft3, 5, (255, 0, 255), cv2.FILLED) # 在img图像上画一个圆,中心点为pointLeft,半径为5,颜色为紫色

cv2.circle(img, pointRight3, 5, (255, 0, 255), cv2.FILLED) # 在img图像上画一个圆,中心点为pointRight,半径为5,颜色为紫色

w3, _ u003ddetector.findDistance(pointLeft3, pointRight3) # 将第一张脸的左眼到右眼的位置距离赋值给w1。 w1 后面的下划线表示忽略其他值

###查找距离

##根据上式f u003d (w * d) / W,可以粗略测出,人眼距离相机50cm时,相机焦距约为300

##然后将找到的焦距代入距离计算公式,即可计算出距离

f u003d 300

d3 u003d (W * f) / w2

cvzone.putTextRect(img, f'Depth:{int(d3)}cm', (face3[10][0] - 95, face3[10][1] - 5),规模u003d1.8)

cv2.imshow("img",img)

cv2.waitKey(1)

以上就是通过Python OpenCv实现人脸识别和人脸测距的过程。祝所有研究人员文章多,脱发少!

Logo

Python社区为您提供最前沿的新闻资讯和知识内容

更多推荐