如何使用OpenCV的ArUco框架计算相机到ArUco标记的距离
基于OpenCV ArUco框架的相机到标记距离测算方案
核心实现逻辑
整个测算的底层是小孔成像的相似三角形原理,分两种实现路径:
- 高精度方案(推荐):依赖预先标定的相机内参(内参矩阵、畸变系数),结合识别到的标记角点坐标,直接解算标记相对于相机的三维位姿,平移向量的Z轴分量就是相机光心到标记平面的直线距离,误差通常可以控制在1%以内。
- 简易方案(无标定场景用):不需要相机标定,提前通过已知距离的标记测算出等效焦距,后续通过成像的像素边长反向推算距离,精度受标定场景影响较大,误差一般在5%以上。
注意:所有测算的前提是你提前知道所用ArUco标记的实际物理边长,比如打印的标记边长为5cm,就需要把这个值作为固定参数传入算法。
具体操作步骤(高精度方案,OpenCV 4.x版本)
- 步骤1:准备前置参数
- 完成单目相机标定,得到内参矩阵
camera_matrix、畸变系数dist_coeffs,这两个参数可以消除镜头畸变带来的成像形变,是精度的核心保障 - 测量你使用的ArUco标记的实际物理边长,记为
marker_length,单位建议统一用米,后续输出的距离单位也会是米
- 完成单目相机标定,得到内参矩阵
- 步骤2:初始化ArUco检测器
对应代码示例:
如果你用的是OpenCV 4.6及更早版本,把检测器初始化部分替换为旧版接口即可:import cv2 import numpy as np # 替换为你实际使用的ArUco字典,示例为6x6规格、共250个标记的字典 aruco_dict = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_6X6_250) detect_params = cv2.aruco.DetectorParameters() aruco_detector = cv2.aruco.ArucoDetector(aruco_dict, detect_params)aruco_dict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250) detect_params = cv2.aruco.DetectorParameters_create() - 步骤3:检测图像中的ArUco标记
可以对单张图像或者视频流逐帧做检测:# 单张图像检测示例,视频流场景替换为从摄像头取帧即可 frame = cv2.imread("aruco_test.jpg") # 检测输出:标记角点坐标、标记ID、未识别成功的候选区域 corners, ids, rejected = aruco_detector.detectMarkers(frame) - 步骤4:解算位姿提取距离
检测到有效标记后,调用位姿解算接口直接得到距离:if ids is not None: # 解算每个标记的旋转向量、平移向量 rvecs, tvecs, _ = cv2.aruco.estimatePoseSingleMarkers( corners, marker_length, camera_matrix, dist_coeffs ) # 遍历所有识别到的标记输出距离 for idx in range(len(ids)): # 平移向量的第三个分量就是相机到标记的直线距离 distance = tvecs[idx][0][2] print(f"标记ID {ids[idx][0]} 距离相机:{distance:.2f}m") - 步骤5:精度优化(可选)
- 对检测到的角点做亚像素优化,进一步提升角点坐标精度,降低距离误差
- 连续检测多帧取距离平均值,消除单帧识别的波动误差
- 尽量保证标记平面和相机成像平面平行,标记和相机夹角超过30°时,测算误差会明显升高
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

