赞
踩
Python OpenCv 实现实时人脸识别及面部测距
准备
在进行人脸面部测距开发前,先在你的Python中分别安装4个库,分别为cvzone库,mediapipe库,tensorflow库,tensorflow-gpu库,其中安装cvzone库和mediapipe库都较快,直接使用下面语句即可快速安装好
pip install cvzone
pip install mediapipe
安装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
确保以上4个库都安装成功后就可以开始编写代码了。
原理
OpenCv实现人脸测距主要利用了相似三角形原理,见下图
参数说明:
(1)其中相机的焦距f是固定不变的;
(2)w为照相机成像后人眼的像素值距离,可以通过findFaceMesh( )将人脸网格识别后再测算成像人眼的像素距离w;
(3)W为现实中人左眼和右眼的距离,男人平均瞳距为64mm,女人的平均瞳距为62mm,本项目开发取中间值63mm;
(4)d为想要获得的实际人到相机的距离,通过相似三角形原理,变换公式后就可以计算出人到相机的距离公式:d=(f*W)/w
注:
不同的相机,焦距是不一样的,如果知道相机本身的参数是最好的,可以直接代入即可精准计算。如果不知道相机参数的条件下,就需要自己手动的多次校正确定焦距f。手动校正需要多测几数据,然后求均值,以确保焦距f的准确,从而提升测距精确度。手动校正时,先固定一个眼睛到相机的距离,比如50cm,用皮尺精确的测量,多测几次求出焦距f。具体测焦距f的代码见下:
import cv2 import cvzone from cvzone.FaceMeshModule import FaceMeshDetector #导入检测器 ## 下面是导入摄像头 cap = cv2.VideoCapture(0) detector = FaceMeshDetector(maxFaces = 1) #检测人脸,并只要一张人脸 ,最后的1表示最多只检测1张人脸 while True: success,img = cap.read() img,faces = detector.findFaceMesh(img,draw = False) #做检测器,查找面部网格,返回图像(img)和我们的面部(faces) ,draw = False有了这句话后就看不到点了 if faces: #如果有面部(faces)可用 ##通过以下语句找到左眼和右眼两个点 face = faces[0] #先进行第一阶段 pointLeft = face[145] #左边的值基本上是值145 pointRight = face[374] #右边的值基本上是值374 ###下面是找焦距的过程 ##找以像素为单位的距离 w,_ = detector.findDistance(pointLeft,pointRight) #将左眼点的位置到右眼点位置的距离赋值给w w后面的下划线是忽略其他的值 W = 6.3 #这是人眼的左眼与右眼之间的距离为63mm,取了中间值,男人的为64mm,女人的为62mm d = 50 #距离先假定是50cm f = (w * d) / W #将求焦距的公式代入 print(f) cv2.imshow("Iamge",img) cv2.waitKey(1)
通过上面代码多次测量焦距f求均值,本人使用的摄像头焦距为300,所以后面我的代码中f = 300,这里根据自己的实际焦距代入测量。下面将焦距f代入测量公式d = (f*W) / w,具体代码见下:
import cv2 import cvzone from cvzone.FaceMeshModule import FaceMeshDetector #导入检测器 ## 下面是导入摄像头 cap = cv2.VideoCapture(0) detector = FaceMeshDetector(maxFaces = 1) #检测人脸 while True: success,img = cap.read() img,faces = detector.findFaceMesh(img,draw = False) #做检测器,查找面部网格,返回图像(img)和我们的面部(faces) ,draw = False有了这句话后就看不到网格了 if faces: #如果有面部(faces)可用 ##通过以下语句找到左眼和右眼两个点 face = faces[0] #先进行第一阶段 pointLeft = face[145] #左边的值基本上是值145 pointRight = 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, _ = detector.findDistance(pointLeft, pointRight) # 将左眼点的位置到右眼点位置的距离赋值给w w后面的下划线是忽略其他的值 W = 6.3 # 这是人眼的左眼与右眼之间的距离为63mm,取了中间值,男人的为64mm,女人的为62mm ###查找距离 ##通过上面f = (w * d) / W公式,可以大致的测出,当人眼距离相机50cm时,相机的焦距为300左右 ##再将找到的焦距代入计算距离的公式,就可以算出距离 f = 300 d = (W * f) / w print(d) ##下面是将距离的文本字样跟随人脸移动输出在额头位置 cvzone.putTextRect(img,f'Depth:{int(d)}cm',(face[10][0]-95,face[10][1]-5),scale = 1.8) #将距离文本显示在图像上,以字符串形式显示,单位为cm,文本值显示的位置跟随人面部移动显示在额头上(额头上的id是10,也就是face[10],后面的face[10][0]表示第一个元素,face[10][1]表示第二个元素), ##上面scale = 2表示输出文本框在图片上的大小 ##face[10][0]改变的是左右,face[10][1]改变的是显示的高度 cv2.imshow("Iamge",img) cv2.waitKey(1)
最终的测试结果见下:
多人同时测距代码见下,本人还没有优化好,多人同时测距时会浮动不稳定。
import cv2 import cvzone from cvzone.FaceMeshModule import FaceMeshDetector #导入检测器 ## 下面是导入摄像头 cap = cv2.VideoCapture(0) detector = FaceMeshDetector(maxFaces=3) while True: sucess,img = cap.read() img,faces1 = detector.findFaceMesh(img) img,faces2 = detector.findFaceMesh(img) img,faces3 = detector.findFaceMesh(img) W = 6.3 # 这是人眼的左眼与右眼之间的距离为63mm,取了中间值,男人的为64mm,女人的为62mm if faces1: #如果检测到有面部可用 face1 = faces1[0] pointLeft1 = face1[145] #左眼的面部值为145 pointRight1 = 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, _ = detector.findDistance(pointLeft1, pointRight1) # 将第一张人脸左眼到右眼的位置距离赋值给w1 ,w1后面的下划线表示忽略其他的值 ###查找距离 ##通过上面f = (w * d) / W公式,可以大致的测出,当人眼距离相机50cm时,相机的焦距为300左右 ##再将找到的焦距代入计算距离的公式,就可以算出距离 f = 300 d1 = (W * f) / w1 cvzone.putTextRect(img, f'Depth:{int(d1)}cm', (face1[10][0] - 95, face1[10][1] - 5), scale = 1.8) if faces2: ##这里表示在测试到第一张人脸的时候,如果再出现第二张人脸则标记显示出来 face2 = faces2[0] pointLeft2 = face2[145] # 左眼的面部值为145 pointRight2 = 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,_ = detector.findDistance(pointLeft2,pointRight2) #将第一张人脸左眼到右眼的位置距离赋值给w1 ,w1后面的下划线表示忽略其他的值 ###查找距离 ##通过上面f = (w * d) / W公式,可以大致的测出,当人眼距离相机50cm时,相机的焦距为300左右 ##再将找到的焦距代入计算距离的公式,就可以算出距离 f = 300 d2 = (W * f) / w2 cvzone.putTextRect(img, f'Depth:{int(d2)}cm', (face2[10][0] - 95, face2[10][1] - 5), scale=1.8) if faces3: face3 = faces3[0] pointLeft3 = face3[145] # 左眼的面部值为145 pointRight3 = 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, _ = detector.findDistance(pointLeft3, pointRight3) # 将第一张人脸左眼到右眼的位置距离赋值给w1 ,w1后面的下划线表示忽略其他的值 ###查找距离 ##通过上面f = (w * d) / W公式,可以大致的测出,当人眼距离相机50cm时,相机的焦距为300左右 ##再将找到的焦距代入计算距离的公式,就可以算出距离 f = 300 d3 = (W * f) / w2 cvzone.putTextRect(img, f'Depth:{int(d3)}cm', (face3[10][0] - 95, face3[10][1] - 5), scale=1.8) cv2.imshow("img",img) cv2.waitKey(1)
以上就是通过Python OpenCv实现人脸识别及面部测距的过程,祝各位科研人多发文章,少掉头发!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。