大家好,今天带大家用 Python 一步到位实现3 个超酷视觉功能

  • 😊 表情识别(正常 / 微笑 / 大笑)
  • 😪 疲劳检测(闭眼报警)
  • 👨‍👩‍👧‍👦 年龄 + 性别检测

全程复制粘贴就能跑,零基础也能学会!


一、先搞清楚:我们要做什么?

打开电脑摄像头,实时画面里会自动显示:

  1. 你的表情(正常 / 微笑 / 大笑)
  2. 眼睛疲劳状态,长时间闭眼会报警
  3. 预测年龄和性别
  4. 全程中文显示,不闪退、不乱码

二、准备工作(超简单)

1. 安装 Python

直接去官网下载安装:https://www.python.org/安装时一定要勾选 Add Python to PATH

2. 安装需要的库

打开电脑的命令提示符(CMD),复制下面代码运行:

bash

运行

pip install opencv-python numpy pillow scikit-learn
pip install dlib==19.22.0.0

小白提示:如果安装慢,就加国内镜像:

bash

运行

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python numpy pillow scikit-learn dlib==19.22.0.0

3. 下载模型文件(必须下)

新建一个文件夹,比如叫 my_project,里面再建一个 model 文件夹。

把下面 6 个文件下载放进 model 里:

  1. opencv_face_detector.pbtxt
  2. opencv_face_detector_uint8.pb
  3. deploy_age.prototxt
  4. age_net.caffemodel
  5. deploy_gender.prototxt
  6. gender_net.caffemodel

再下载 1 个关键点模型:shape_predictor_68_face_landmarks.dat直接放在代码同一目录。


三、完整代码(直接复制,不改任何东西)

新建一个文本文档,把下面代码全部粘贴进去,保存为 .py 文件。

python

运行

import numpy as np
import dlib
import cv2
from sklearn.metrics.pairwise import euclidean_distances
from PIL import Image, ImageDraw, ImageFont

# ===================== 表情识别 =====================
def MAR(shape):
    A = euclidean_distances(shape[50].reshape(1, 2), shape[58].reshape(1, 2))
    B = euclidean_distances(shape[51].reshape(1, 2), shape[57].reshape(1, 2))
    C = euclidean_distances(shape[52].reshape(1, 2), shape[56].reshape(1, 2))
    D = euclidean_distances(shape[48].reshape(1, 2), shape[54].reshape(1, 2))
    return ((A + B + C) / 3) / D

def MJR(shape):
    M = euclidean_distances(shape[48].reshape(1, 2), shape[54].reshape(1, 2))
    J = euclidean_distances(shape[3].reshape(1, 2), shape[13].reshape(1, 2))
    return M / J

# ===================== 疲劳检测 =====================
def eye_aspect_ratio(eye):
    A = euclidean_distances(eye[1].reshape(1,2), eye[5].reshape(1,2))
    B = euclidean_distances(eye[2].reshape(1,2), eye[4].reshape(1,2))
    C = euclidean_distances(eye[0].reshape(1,2), eye[3].reshape(1,2))
    ear = ((A + B) / 2.0) / C
    return ear

def drawEye(eye):
    eyeHull = cv2.convexHull(eye)
    cv2.drawContours(frame, [eyeHull], -1, color=(0, 255, 0), thickness=1)

# ===================== 中文显示 =====================
def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30):
    img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(img_pil)
    try:
        font = ImageFont.truetype("simsun.ttc", textSize, encoding="utf-8")
    except:
        font = ImageFont.load_default()
    draw.text(position, text, font=font, fill=textColor)
    return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)

# ===================== 年龄性别检测 =====================
faceProto = "model/opencv_face_detector.pbtxt"
faceModel = "model/opencv_face_detector_uint8.pb"
ageProto = "model/deploy_age.prototxt"
ageModel = "model/age_net.caffemodel"
genderProto = "model/deploy_gender.prototxt"
genderModel = "gender_net.caffemodel"

ageNet = cv2.dnn.readNet(ageModel, ageProto)
genderNet = cv2.dnn.readNet(genderModel, genderProto)
faceNet = cv2.dnn.readNet(faceModel, faceProto)

ageList = ['[0-2岁]', '[4-6岁]', '[8-12岁]', '[15-20岁]', '[25-32岁]', '[38-43岁]', '[48-53岁]', '[60-100岁]']
genderList = ['男性', '女性']
mean = (78.4263377308, 87.7689143744, 114.895878788)

def getBoxes(net, frame):
    frameHeight, frameWidth = frame.shape[:2]
    blob = cv2.dnn.blobFromImage(frame, scalefactor=1.0, size=(300, 300),
                                 mean=(104, 117, 123), swapRB=True, crop=False)
    net.setInput(blob)
    detections = net.forward()
    faceBoxes = []
    for i in range(detections.shape[2]):
        confidence = detections[0, 0, i, 2]
        if confidence > 0.7:
            x1 = int(detections[0, 0, i, 3] * frameWidth)
            y1 = int(detections[0, 0, i, 4] * frameHeight)
            x2 = int(detections[0, 0, i, 5] * frameWidth)
            y2 = int(detections[0, 0, i, 6] * frameHeight)
            faceBoxes.append([x1, y1, x2, y2])
            cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
    return frame, faceBoxes

# ===================== 主程序 =====================
if __name__ == "__main__":
    detector = dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
    COUNTER = 0
    cap = cv2.VideoCapture(0)

    while True:
        ret, frame = cap.read()
        if not ret:
            break
        frame = cv2.flip(frame, 1)
        frame, faceBoxes = getBoxes(faceNet, frame)

        if not faceBoxes:
            cv2.imshow("Detection", frame)
            if cv2.waitKey(1) == 27:
                break
            continue

        faces = detector(frame, 0)
        for face in faces:
            shape = predictor(frame, face)
            shape = np.array([[p.x, p.y] for p in shape.parts()])

            # 表情
            mar = MAR(shape)
            mjr = MJR(shape)
            result = "正常"
            if mar > 0.5:
                result = "大笑"
            elif mjr > 0.45:
                result = "微笑"
            mouthHull = cv2.convexHull(shape[48:61])
            cv2.drawContours(frame, [mouthHull], -1, (0, 255, 0), 1)

            # 疲劳
            rightEye = shape[36:42]
            leftEye = shape[42:48]
            rightEAR = eye_aspect_ratio(rightEye)
            leftEAR = eye_aspect_ratio(leftEye)
            ear = (leftEAR + rightEAR) / 2.0

            if ear < 0.3:
                COUNTER += 1
                if COUNTER >= 50:
                    frame = cv2AddChineseText(frame, "!!!危险!!!", (250, 250), (0,0,255), 40)
            else:
                COUNTER = 0
                drawEye(rightEye)
                drawEye(leftEye)

            # 年龄性别
            x1, y1, x2, y2 = faceBoxes[0]
            faceImg = frame[y1:y2, x1:x2]
            blob = cv2.dnn.blobFromImage(faceImg, 1.0, (227, 227), mean, swapRB=False)
            genderNet.setInput(blob)
            gender = genderList[genderNet.forward()[0].argmax()]
            ageNet.setInput(blob)
            age = ageList[ageNet.forward()[0].argmax()]

            # 显示信息
            frame = cv2AddChineseText(frame, f"表情:{result}", (x1, y1-90), (0,255,0), 24)
            frame = cv2AddChineseText(frame, f"EAR:{ear[0][0]:.2f}", (x1, y1-60), (0,255,0), 24)
            frame = cv2AddChineseText(frame, f"性别:{gender}", (x1, y1-30), (0,255,0), 24)
            frame = cv2AddChineseText(frame, f"年龄:{age}", (x1, y1), (0,255,0), 24)

        cv2.imshow("Detection", frame)
        if cv2.waitKey(1) == 27:
            break

    cap.release()
    cv2.destroyAllWindows()

四、运行!一键启动

  1. 把代码、model 文件夹、.dat 模型放在一起
  2. 双击运行 .py 文件
  3. 摄像头自动打开,开始检测
  4. ESC 键退出程序

五、小白常见问题(必看)

1. 窗口标题乱码?

OpenCV 窗口不支持中文,代码里我已经改成英文,不会乱码

2. 报错找不到模型?

  • 检查有没有 model 文件夹
  • 检查模型名字和代码里一模一样
  • 模型必须放在代码同级目录

3. 摄像头打不开?

  • 检查摄像头权限
  • cv2.VideoCapture(1) 试试

4. 中文显示方框?

代码里已经做了兼容,Windows 正常显示,不行就换字体。


六、效果展示

  • 人脸自动框选
  • 表情实时判断
  • 眼睛闭合就计数,长时间闭眼报警
  • 性别、年龄自动预测
  • 所有文字中文清晰显示

七、总结

这一套代码整合了表情识别 + 疲劳检测 + 年龄性别检测,是非常经典的计算机视觉入门项目。不用懂复杂算法,复制粘贴就能跑,非常适合小白练手!

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐