Python中如何使用OpenCV测量人与摄像头的距离?
null
Python中如何使用OpenCV测量人与摄像头的距离?
如果摄像头的位置不是固定的,粗略测量的话你要先有标定物,然后知道标定物的具体尺寸,最后根据标定物在图片中的大小计算出距离
要测量人与摄像头的距离,需要先检测人脸,然后根据人脸在图像中的大小来估算距离。这里提供一个完整的解决方案:
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()
工作原理:
- 校准阶段:让人站在已知距离(如50厘米)处,测量此时人脸在图像中的像素宽度,计算出相机的焦距
- 测量阶段:检测实时视频中的人脸,根据人脸像素宽度和已知焦距,使用相似三角形原理计算实际距离
公式:距离 = (已知人脸宽度 × 焦距) / 检测到的人脸像素宽度
使用步骤:
- 运行程序,按提示站在50厘米处按空格键校准
- 校准后即可实时看到距离测量结果
- 按’q’键退出
关键参数调整:
known_width:需要根据实际情况调整,亚洲成年人脸宽度约14-16厘米face_cascade.detectMultiScale参数:可根据检测效果调整,1.1是缩放因子,4是最小邻居数
一句话总结:基于人脸检测和相似三角形原理,通过校准获得焦距后实时计算距离。
如果人站的位置不固定,你就需要一个深度摄像头,比如 kinect 上的那个,然后把人的位置所在的深度取出来就能知道距离了
双目视觉
摄像头的参数固定的话 可以假定人的比如头大小是基本固定的 然后去猜
realsense 了解下。
如果是摄像头的参数是固定的,理论上可以通过识别出来的人脸(或者整个身体)在画面中的位置和大小粗略判断与摄像头的距离。
OpenCV 可以通过图像分析计算出目标距离,但是这个不准,而且要求也多,如楼上几位所说。这个方案比较落后了。
双目可能方便点,可以我的双摄的手机无法同时打开 2 个摄像头,至少我写软件通过标准 API 调用不支持,设备告知只有一个后置摄像头。
摄像头集成深度感知信息能力就比较先进,在实际产品力也有用到(如微软的 Kinect,Google 的 Tango ),这种方式不需要软件参与计算(没有不必要的耗电),而且没有很麻烦的要求。只是目前精度也不高,估计以后好点。
只是简单的感知对面的距离没有计算,传感器直接会告知。
涉及到复杂的三维场景生成,机器视觉导航(像人眼一样看图像就知道哪里能走,哪里障碍)还是有很大量的计算,而且这个算法还不怎么成熟。

