Python中如何使用OpenCV测量人与摄像头的距离?

null
Python中如何使用OpenCV测量人与摄像头的距离?

10 回复

如果摄像头的位置不是固定的,粗略测量的话你要先有标定物,然后知道标定物的具体尺寸,最后根据标定物在图片中的大小计算出距离


要测量人与摄像头的距离,需要先检测人脸,然后根据人脸在图像中的大小来估算距离。这里提供一个完整的解决方案:

import cv2
import numpy as np

class DistanceEstimator:
    def __init__(self, known_width=16.0, known_distance=50.0):
        """
        known_width: 已知距离下的人脸宽度(厘米)
        known_distance: 已知距离(厘米)
        focal_length: 焦距(像素)
        """
        self.known_width = known_width
        self.known_distance = known_distance
        self.focal_length = None
        
    def calculate_focal_length(self, measured_width):
        """计算焦距"""
        self.focal_length = (measured_width * self.known_distance) / self.known_width
        return self.focal_length
        
    def distance_to_camera(self, perceived_width):
        """根据检测到的人脸宽度计算距离"""
        if self.focal_length is None:
            raise ValueError("请先调用calculate_focal_length()计算焦距")
        return (self.known_width * self.focal_length) / perceived_width

def main():
    # 初始化
    face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
    cap = cv2.VideoCapture(0)
    
    # 第一步:校准 - 让人站在已知距离处
    print("请站在距离摄像头50厘米处,按空格键校准...")
    calibrating = True
    
    while calibrating:
        ret, frame = cap.read()
        if not ret:
            break
            
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        faces = face_cascade.detectMultiScale(gray, 1.1, 4)
        
        for (x, y, w, h) in faces:
            cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
            
        cv2.imshow('Calibration', frame)
        
        key = cv2.waitKey(1) & 0xFF
        if key == ord(' ') and len(faces) > 0:
            # 获取校准时的人脸宽度
            calibrate_width = faces[0][2]
            estimator = DistanceEstimator()
            estimator.calculate_focal_length(calibrate_width)
            print(f"校准完成!焦距: {estimator.focal_length:.2f}像素")
            calibrating = False
            cv2.destroyWindow('Calibration')
    
    # 第二步:实时测量距离
    print("开始实时距离测量...")
    
    while True:
        ret, frame = cap.read()
        if not ret:
            break
            
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        faces = face_cascade.detectMultiScale(gray, 1.1, 4)
        
        for (x, y, w, h) in faces:
            # 计算距离
            distance = estimator.distance_to_camera(w)
            
            # 绘制结果
            cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
            cv2.putText(frame, f"Distance: {distance:.1f}cm", 
                       (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 
                       0.7, (0, 255, 0), 2)
        
        cv2.imshow('Distance Measurement', frame)
        
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    
    cap.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

工作原理:

  1. 校准阶段:让人站在已知距离(如50厘米)处,测量此时人脸在图像中的像素宽度,计算出相机的焦距
  2. 测量阶段:检测实时视频中的人脸,根据人脸像素宽度和已知焦距,使用相似三角形原理计算实际距离

公式距离 = (已知人脸宽度 × 焦距) / 检测到的人脸像素宽度

使用步骤:

  1. 运行程序,按提示站在50厘米处按空格键校准
  2. 校准后即可实时看到距离测量结果
  3. 按’q’键退出

关键参数调整:

  • known_width:需要根据实际情况调整,亚洲成年人脸宽度约14-16厘米
  • face_cascade.detectMultiScale参数:可根据检测效果调整,1.1是缩放因子,4是最小邻居数

一句话总结:基于人脸检测和相似三角形原理,通过校准获得焦距后实时计算距离。

如果人站的位置不固定,你就需要一个深度摄像头,比如 kinect 上的那个,然后把人的位置所在的深度取出来就能知道距离了

双目视觉

摄像头的参数固定的话 可以假定人的比如头大小是基本固定的 然后去猜

realsense 了解下。

如果是摄像头的参数是固定的,理论上可以通过识别出来的人脸(或者整个身体)在画面中的位置和大小粗略判断与摄像头的距离。

OpenCV 可以通过图像分析计算出目标距离,但是这个不准,而且要求也多,如楼上几位所说。这个方案比较落后了。

双目可能方便点,可以我的双摄的手机无法同时打开 2 个摄像头,至少我写软件通过标准 API 调用不支持,设备告知只有一个后置摄像头。

摄像头集成深度感知信息能力就比较先进,在实际产品力也有用到(如微软的 Kinect,Google 的 Tango ),这种方式不需要软件参与计算(没有不必要的耗电),而且没有很麻烦的要求。只是目前精度也不高,估计以后好点。

只是简单的感知对面的距离没有计算,传感器直接会告知。

涉及到复杂的三维场景生成,机器视觉导航(像人眼一样看图像就知道哪里能走,哪里障碍)还是有很大量的计算,而且这个算法还不怎么成熟。

回到顶部