You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Python的鱼眼摄像头人脸识别应用开发问题求助

适配鱼眼摄像头的人脸识别解决方案:从关键点检测失败到正常运行

Hey Logesh, 我看了你遇到的鱼眼摄像头适配问题——普通webcam下人脸识别正常,但切换到鱼眼镜头后连人脸关键点都检测不出来,这确实是鱼眼镜头的畸变特性导致的典型问题。咱们一步步拆解解决:

问题根源分析

鱼眼镜头会产生桶形畸变,画面边缘的人脸会被严重拉伸变形,而face_recognition和dlib的人脸检测模型是基于正常平面图像训练的,自然无法识别畸变后的人脸形态。另外我注意到你的代码里还有两个独立的摄像头循环,这会导致硬件资源冲突,也是关键点检测失败的潜在原因。


解决方案步骤

1. 先矫正鱼眼图像的畸变

首先需要通过OpenCV的鱼眼畸变矫正功能,把扭曲的画面还原成正常平面图像。你需要先获取摄像头的内参(K)和畸变系数(D),如果没有专业标定数据,可以先用近似参数,之后再用棋盘格标定优化。

畸变矫正函数与示例参数

import numpy as np
import cv2

def undistort_fisheye(frame, K, D):
    # 初始化畸变矫正映射表
    h, w = frame.shape[:2]
    map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, D, np.eye(3), K, (w, h), cv2.CV_16SC2)
    # 应用矫正
    undistorted_frame = cv2.remap(frame, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
    return undistorted_frame

# 示例参数(根据你的摄像头调整,建议用棋盘格标定获取准确值)
K = np.array([[600, 0, 320], [0, 600, 240], [0, 0, 1]], dtype=np.float32)
D = np.array([[0.1, 0.05, 0.01, 0.005, 0.0]], dtype=np.float32)

2. 修复代码中的两个关键错误

  • 颜色格式转换错误:原代码中rgb_small_frame = small_frame[:, :, ::1]是错的,OpenCV读取的是BGR格式,face_recognition需要RGB,应该改成::-1。
  • 双摄像头循环冲突:原代码同时启动了两个摄像头捕获循环,会导致硬件资源抢占,必须合并成一个循环。

3. 优化人脸检测灵敏度

即使矫正了畸变,鱼眼镜头下的人脸可能还是有轻微变形,可以调高dlib检测器的upsample参数,提升对变形/小尺寸人脸的检测率:

# 原代码的detector调用改成:
faces = detector(gray, 2)  # 第二个参数为upsample次数,默认0,设为2会更敏感

修正后的完整代码

import face_recognition
import cv2
import numpy as np
import dlib

# 鱼眼畸变矫正参数(根据你的摄像头调整,建议用棋盘格标定获取准确值)
K = np.array([[600, 0, 320], [0, 600, 240], [0, 0, 1]], dtype=np.float32)
D = np.array([[0.1, 0.05, 0.01, 0.005, 0.0]], dtype=np.float32)

def undistort_fisheye(frame, K, D):
    h, w = frame.shape[:2]
    map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, D, np.eye(3), K, (w, h), cv2.CV_16SC2)
    undistorted_frame = cv2.remap(frame, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
    return undistorted_frame

# 获取默认摄像头引用
video_capture = cv2.VideoCapture(0)
# 设置摄像头分辨率(可选,根据你的鱼眼摄像头调整)
video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

# 加载样本图片并生成编码
obama_image = face_recognition.load_image_file("obama.jpg")
obama_face_encoding = face_recognition.face_encodings(obama_image)[0]

biden_image = face_recognition.load_image_file("biden.jpg")
biden_face_encoding = face_recognition.face_encodings(biden_image)[0]

Logesh_image = face_recognition.load_image_file("Upside Logesh.jpg")
Logesh_face_encoding = face_recognition.face_encodings(Logesh_image)[0]

known_face_encodings = [
    obama_face_encoding,
    biden_face_encoding,
    Logesh_face_encoding
]
known_face_names = [
    "Barack Obama",
    "Joe Biden",
    "Logesh"
]

# 初始化变量
face_locations = []
face_encodings = []
face_names = []
process_this_frame = True

# 初始化dlib的检测器和关键点预测器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

while True:
    ret, frame = video_capture.read()
    if not ret:
        break

    # 第一步:矫正鱼眼畸变
    undistorted_frame = undistort_fisheye(frame, K, D)

    # 缩小帧以加快处理速度
    small_frame = cv2.resize(undistorted_frame, (0, 0), fx=0.25, fy=0.25)
    # 正确转换为RGB格式
    rgb_small_frame = small_frame[:, :, ::-1]

    # 每隔一帧处理一次以节省资源
    if process_this_frame:
        face_locations = face_recognition.face_locations(rgb_small_frame)
        face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)

        face_names = []
        for face_encoding in face_encodings:
            matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
            name = "Unknown"

            # 选择最匹配的人脸
            face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
            best_match_index = np.argmin(face_distances)
            if matches[best_match_index]:
                name = known_face_names[best_match_index]

            face_names.append(name)

    process_this_frame = not process_this_frame

    # 绘制人脸识别结果
    display_frame = undistorted_frame.copy()
    frame_center = display_frame.shape[1] // 2
    for (top, right, bottom, left), name in zip(face_locations, face_names):
        # 缩放回原尺寸
        top *= 4
        right *= 4
        bottom *= 4
        left *= 4

        # 绘制人脸框和名称
        cv2.rectangle(display_frame, (left, top), (right, bottom), (0, 0, 255), 2)
        cv2.rectangle(display_frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
        font = cv2.FONT_HERSHEY_DUPLEX
        cv2.putText(display_frame, name, (left + 10, bottom - 6), font, 1.0, (255, 255, 255), 1)

        # 位置提示
        if right < frame_center - 100:
            cv2.putText(display_frame, "You are in the right side", (left - 100, bottom - 300), font, 0.8, (255, 255, 255), 1)
        elif left > frame_center + 100:
            cv2.putText(display_frame, "You are in the left side", (left - 100, bottom - 300), font, 0.8, (255, 255, 255), 1)

    # 检测并绘制人脸关键点
    gray = cv2.cvtColor(display_frame, cv2.COLOR_BGR2GRAY)
    faces = detector(gray, 2)  # 提升检测灵敏度
    for face in faces:
        landmarks = predictor(gray, face)
        for n in range(0, 68):
            x = landmarks.part(n).x
            y = landmarks.part(n).y
            cv2.circle(display_frame, (x, y), 3, (255, 0, 0), -1)

    # 显示结果
    cv2.imshow('Fisheye Face Recognition', display_frame)

    # 按q退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 释放资源
video_capture.release()
cv2.destroyAllWindows()

额外优化建议

如果近似畸变参数效果不好,建议用棋盘格标定法获取准确的K和D参数:打印一张棋盘格,用鱼眼摄像头从不同角度、距离拍摄20-30张图片,然后用OpenCV的cv2.fisheye.calibrate工具计算出专属的畸变参数,这样矫正效果会更精准。

内容的提问来源于stack exchange,提问作者Logesh M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 22:12:42