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实现人脸识别及面部测距的过程,祝各位科研人多发文章,少掉头发!