Python OpenCv 实现实时人脸识别及面部距离测量

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实现人脸测距主要利用了相似三角形原理,见下图
Python OpenCv 实现实时人脸识别及面部距离测量_第1张图片
参数说明:
(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)

最终的测试结果见下:
Python OpenCv 实现实时人脸识别及面部距离测量_第2张图片
多人同时测距代码见下,本人还没有优化好,多人同时测距时会浮动不稳定。

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

你可能感兴趣的:(Python,OpenCv,python,opencv,tensorflow)