单目测距实战:从相机标定到距离计算的完整指南
1. 项目概述从一张照片到真实距离“基于相机模型的单目测距——普通相机”这个标题听起来有点学术但它的核心目标非常直接只用一台普通的、没有深度传感器的摄像头比如你的手机摄像头通过一张照片估算出画面中某个物体离你到底有多远。这听起来像是科幻电影里的技术但实际上它背后的数学原理相机模型和工程实践OpenCV等工具已经相当成熟是计算机视觉领域一个经典且实用的课题。我最初接触这个需求是在一个机器人导航项目中。当时预算有限没法上昂贵的激光雷达或多目立体视觉系统但机器人又需要判断前方障碍物的距离来决定是否绕行。于是单目测距就成了一个极具性价比的解决方案。它不要求特殊的硬件仅凭一个普通的USB摄像头或手机摄像头就能工作核心在于对相机本身的精确“理解”和对场景的合理假设。简单来说这个过程可以拆解为三个关键步骤首先你得知道你的相机“看”世界的方式这通过“相机标定”来获取相机的内参其次你需要识别并定位图像中的目标物体最后结合已知的物体尺寸或场景几何约束利用透视投影原理反推出距离。整个流程的精度很大程度上取决于第一步——相机标定的准确性。这也是为什么相关热搜词里“相机标定”和“相机内参”会如此高频地出现。这篇文章我将以一个从业者的角度带你完整走一遍用普通相机实现单目测距的实战流程。我们会从最基础的相机模型讲起手把手完成相机标定然后探讨在实际场景中比如已知物体尺寸、或地面假设如何计算距离并分享我在调试过程中踩过的坑和积累的经验。无论你是做机器人、自动驾驶、AR应用还是单纯对技术好奇这篇内容都能给你提供一套可直接复现的代码和清晰的思路。2. 核心原理透视投影与相机模型拆解为什么一张2D的图片能反推出3D的距离这背后的基石是针孔相机模型和透视投影原理。理解了这个你才能明白后续所有操作的意义而不是机械地调用几个OpenCV函数。2.1 针孔相机模型世界如何被压扁在传感器上想象一下一个暗箱前端有一个小孔。外界的光线穿过这个小孔在暗箱后端的感光平面上形成一个倒立的像。这就是最简化的针孔相机模型。在这个模型里有几个关键点光心Optical Center可以近似理解为那个小孔的位置是所有光线汇聚的虚拟点。图像平面Image Plane就是感光元件CMOS/CCD所在的位置。焦距Focal Length光心到图像平面的垂直距离。一个现实世界中的点P(X, Y, Z)以相机光心为原点的坐标系下通过光心投影到图像平面上形成一个点p(u, v)。它们之间的关系就是透视投影的核心公式齐次坐标下s * [u, v, 1]^T K * [X, Y, Z]^T其中s是一个任意的尺度因子因为从3D到2D丢失了深度信息K就是我们要标定的相机内参矩阵。2.2 内参矩阵K相机的“身份证”内参矩阵K描述了相机自身的属性与它的摆放位置和朝向无关。一个常用的形式是K [ fx, 0, cx; 0, fy, cy; 0, 0, 1 ]fx, fy以像素为单位的焦距。fx f / dx,fy f / dy。其中f是物理焦距dx, dy是传感器每个像素的物理尺寸。由于制造工艺fx和fy可能略有不同。cx, cy主点坐标通常是图像的中心点width/2, height/2。它表示光轴与图像平面的交点。0这里假设图像坐标系的两个轴是严格垂直的对于大多数现代相机这个假设是合理的。如果存在严重的镜头畸变导致轴不垂直这里会有一个倾斜参数s但通常可以忽略。为什么内参如此重要因为它建立了图像像素坐标(u, v)与相机坐标系下方向射线之间的映射关系。知道了K给定一个图像点我们就能知道在相机前方有一条特定的空间射线对应着这个像素。测距问题就变成了如何在这条射线上确定一个具体的点即物体的真实位置。2.3 从2D回推3D为什么需要额外假设从公式s * p K * P可以看出我们想要求解P(X, Y, Z)但一个方程有X, Y, Z, s四个未知数而p(u, v)只提供了两个约束方程。这就是单目视觉固有的尺度不确定性你无法区分一个物体是小的但很近还是大的但很远。因此单目测距必须引入额外的先验信息或假设来固定这个尺度。最常见的有两种思路已知物体尺寸如果你知道目标物体在现实世界中的实际大小比如一个边长为15cm的立方体一个身高1.7米的人那么通过它在图像中占据的像素大小就可以根据相似三角形原理计算出距离。已知场景几何比如假设目标物体放置在一个水平地面上地面假设并且我们知道相机离地面的高度。那么物体接地点在图像中的位置就可以唯一确定其到相机的水平距离。注意镜头畸变径向畸变和切向畸变会破坏理想的针孔模型导致直线在图像中变弯。因此在利用内参进行几何计算前必须先对图像进行畸变校正将图像点校正到符合针孔模型的位置。OpenCV的标定过程会同时计算出畸变系数用于后续校正。3. 实战第一步高精度相机标定详解标定的目的是精确获取相机的内参矩阵K和畸变系数dist。OpenCV提供了非常完善的工具链但魔鬼藏在细节里。标定的精度直接决定了后续测距的可靠性。3.1 工具与材料准备相机任何普通的USB摄像头、网络摄像头、手机摄像头均可。建议使用焦距固定的镜头变焦镜头会增加复杂度。标定板推荐使用棋盘格。因为它角点检测稳定、精度高。打印一张棋盘格例如9x6个内角点每个方格边长建议在20-30mm并将其贴在一个非常平整的硬质表面如亚克力板、厚卡纸。平整度至关重要翘曲的纸会引入标定误差。OpenCV库确保安装了包含contrib模块的OpenCV用于更稳定的角点检测。可以通过pip install opencv-contrib-python安装。拍摄环境光线均匀避免反光和阴影覆盖角点。从不同角度、不同距离拍摄标定板覆盖整个图像区域。3.2 标定流程与代码实操标定的本质是求解一个最优化问题寻找一组内参和畸变系数使得根据这些参数将三维标定板角点投影到二维图像上时与实际检测到的图像角点之间的误差最小。以下是使用OpenCV进行标定的核心代码步骤和解释import cv2 import numpy as np import glob # 1. 定义棋盘格尺寸内角点数量非方格数 pattern_size (8, 5) # 例如棋盘格有9x6个方格则内角点为8x5 # 2. 准备物体点世界坐标系中的角点3D坐标Z0 objp np.zeros((pattern_size[0] * pattern_size[1], 3), np.float32) objp[:, :2] np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2) # 假设每个方格实际边长为25mm square_size 25.0 # 单位毫米 objp * square_size # 3. 用于存储所有图像的对象点和图像点 objpoints [] # 3d点 in real world space imgpoints [] # 2d点 in image plane. # 4. 读取所有标定图片 images glob.glob(./calibration_imgs/*.jpg) for fname in images: img cv2.imread(fname) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 查找棋盘格角点 ret, corners cv2.findChessboardCorners(gray, pattern_size, None) # 如果找到添加对象点和图像点细化后 if ret: objpoints.append(objp) # 亚像素级角点检测提升精度 criteria (cv2.TERM_CRITERIA_EPS cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) corners_refined cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria) imgpoints.append(corners_refined) # 可视化可选 cv2.drawChessboardCorners(img, pattern_size, corners_refined, ret) cv2.imshow(Corners Found, img) cv2.waitKey(500) cv2.destroyAllWindows() # 5. 相机标定 ret, mtx, dist, rvecs, tvecs cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) print(相机内参矩阵 K:\n, mtx) print(\n畸变系数 (k1, k2, p1, p2, k3):\n, dist.ravel()) # 6. 评估重投影误差衡量标定质量 mean_error 0 for i in range(len(objpoints)): imgpoints2, _ cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist) error cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2) mean_error error print(f\n平均重投影误差: {mean_error/len(objpoints):.6f} 像素)关键操作解析findChessboardCorners: 自动检测棋盘格角点的初始位置。cornerSubPix:这是提升精度的关键一步。初始角点坐标是整数像素级此函数通过迭代搜索将其优化到亚像素级别如0.1像素显著提高标定精度。calibrateCamera: 执行核心的标定优化计算。返回内参矩阵mtx、畸变系数dist、以及每张图片的旋转向量rvecs和平移向量tvecs。重投影误差这是标定质量的黄金指标。它计算的是用标定出的参数将3D点重新投影到2D图像与真实检测到的2D点之间的平均像素误差。一般来说误差小于0.5像素可以认为是优秀小于1像素可以接受。如果误差大于2像素就需要检查标定板平整度、图片数量和质量、角点检测是否正确。3.3 标定经验与避坑指南图片数量与质量至少需要10-15张不同位姿的清晰图片。太少会导致过拟合或解不稳定。确保标定板覆盖图像的各个角落尤其是边缘畸变更明显和不同深度。标定板平整度这是最容易被忽视的误差源。一张A4纸打印后很容易弯曲。务必贴在硬板上拍摄时也确保其平整。光照均匀避免局部高光或阴影这会导致角点检测失败或位置偏移。保存与使用参数标定一次后将mtx和dist保存为文件如np.save后续测距程序直接加载使用无需重复标定。畸变校正验证标定后用cv2.undistort()函数校正一张图片观察原本弯曲的直线如图像边缘的门框是否被拉直这是检验畸变系数是否有效的直观方法。4. 单目测距的两种核心实现方法拿到精确的内参和畸变系数后我们就可以进行测距了。下面介绍两种最常用、也最实用的方法。4.1 方法一基于已知物体尺寸的测距这是最直观的方法。前提是你知道目标物体的真实物理尺寸如宽度W或高度H。原理物体在图像中成像的像素宽度w_pixel物体的实际物理宽度W_real物体的距离Z沿光轴方向以及焦距f物理焦距但我们可以用像素焦距fx代替并假设物体正面平行于图像平面满足相似三角形关系W_real / Z w_pixel / fx。因此Z (W_real * fx) / w_pixel。实操步骤图像预处理与目标检测使用你的方法如YOLO、颜色分割、轮廓检测等定位目标物体并获取其像素级宽度或高度。例如用一个矩形框住物体框的宽度就是w_pixel。畸变校正将检测到的像素坐标或整个图像用cv2.undistort()进行校正确保使用的是无畸变的坐标进行计算。距离计算import cv2 import numpy as np # 加载之前标定的参数 mtx np.load(camera_mtx.npy) # 内参矩阵 dist np.load(camera_dist.npy) # 畸变系数 # 假设已知物体的真实宽度米 OBJECT_REAL_WIDTH 0.15 # 例如一个杯子的宽度是0.15米 # 读取图像并校正畸变 img cv2.imread(test_image.jpg) h, w img.shape[:2] newcameramtx, roi cv2.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h)) dst cv2.undistort(img, mtx, dist, None, newcameramtx) # 假设通过某种检测我们得到了物体边界框的像素坐标 (x_min, y_min, x_max, y_max) # 这里用模拟数据代替 bbox [320, 180, 480, 420] # [x1, y1, x2, y2] pixel_width bbox[2] - bbox[0] # 计算距离 (使用内参矩阵中的fx) fx mtx[0, 0] distance (OBJECT_REAL_WIDTH * fx) / pixel_width print(f检测到的像素宽度: {pixel_width}) print(f估算距离: {distance:.3f} 米)注意事项物体朝向公式Z (W_real * fx) / w_pixel成立的前提是物体正面完全平行于图像平面。如果物体有旋转其成像宽度会变窄导致距离估算偏大。对于非刚体或姿态变化的物体此方法误差较大。尺寸准确性OBJECT_REAL_WIDTH必须尽可能准确。对于同一类物体如易拉罐可以使用平均尺寸。检测框精度目标检测框的边界是否紧贴物体实际边缘直接影响pixel_width的准确性。4.2 方法二基于地面假设的测距单目逆透视变换这在机器人、自动驾驶中非常常见。前提是相机固定安装且其离地面的高度H已知目标物体与地面有接触点。原理我们建立两个坐标系图像坐标系(u, v)和真实世界的地面坐标系(X, Y)其中Y是相机前进方向X是横向方向地面为Z0平面。通过相机内参和外参主要是相机高度和俯仰角可以建立一个从图像像素到地面坐标的映射关系即逆透视变换IPM。推导与实现定义坐标系相机坐标系原点在光心Z轴沿光轴向前Y轴向下X轴向右。地面点P_g (X, 0, Z)在相机坐标系下这里Z是距离注意与地面坐标系区分。投影关系地面点投影到图像点p(u,v)满足s * [u, v, 1]^T K * [X, H, Z]^T。其中H是相机光心离地高度绝对值因为Y轴向下。求解距离我们可以消去尺度因子s得到两个方程。对于地面上的点Y H可以解出Z (H * fx) / (v - cy)这是一个简化公式假设相机没有俯仰角且主点准确。 更通用的需要先通过标定确定相机相对于地面的旋转矩阵R和平移向量tt[1]即高度H然后通过cv2.undistortPoints和cv2.solvePnP等函数进行坐标转换。简化版地面测距代码示例假设相机无俯仰光轴平行地面def estimate_distance_to_ground_point(img_point_v, camera_matrix, camera_height): 估算图像中一个地面接触点到相机的纵向距离。 :param img_point_v: 地面接触点在图像中的v坐标行坐标。 :param camera_matrix: 相机内参矩阵K。 :param camera_height: 相机光心离地面的高度单位米。 :return: 沿光轴方向的估计距离单位米。 fx camera_matrix[0, 0] cy camera_matrix[1, 2] # 注意这个公式是简化版假设主点在图像中心且无俯仰。 # 更精确的做法需要结合相机外参俯仰角。 distance (camera_height * fx) / (img_point_v - cy) return distance # 使用示例 camera_height 1.2 # 米相机离地高度 # 假设检测到前方一个物体的接地点在图像中的v坐标为400 v_coord 400 dist estimate_distance_to_ground_point(v_coord, mtx, camera_height) print(f物体接地点的估计距离: {dist:.3f} 米)注意事项相机外参标定简化公式误差大。实践中需要精确标定相机相对于地面的姿态俯仰角、滚转角。这可以通过在已知尺寸的地面上放置标定板用cv2.solvePnP求解。地面平坦假设必须假设物体所在区域地面是平坦的与相机标定时的地面是同一平面。接地点检测如何准确找到物体与地面的接触点如车轮底部、行人脚底是另一个挑战通常需要结合目标检测和地面分割。5. 工程实践构建一个完整的单目测距demo理论和方法都有了我们来串联一个完整的、可运行的示例。这个Demo将使用已知尺寸的物体比如一个A4纸进行测距。5.1 系统流程设计初始化加载预标定的相机内参和畸变系数。图像采集从摄像头或视频文件读取一帧图像。畸变校正对原始图像进行去畸变处理。目标检测与定位使用图像处理技术轮廓检测定位A4纸并获取其四个顶点的像素坐标。像素尺寸计算计算A4纸在图像中的像素宽度或高度。距离解算代入已知的A4纸真实尺寸0.21m x 0.297m利用相似三角形公式计算距离。可视化输出在图像上绘制检测框和计算出的距离。5.2 完整代码实现import cv2 import numpy as np class MonocularDistanceEstimator: def __init__(self, camera_matrix, dist_coeffs, object_real_width0.21, object_real_height0.297): 初始化单目测距器。 :param camera_matrix: 相机内参矩阵 :param dist_coeffs: 畸变系数 :param object_real_width: 已知物体的真实宽度米例如A4纸短边 :param object_real_height: 已知物体的真实高度米例如A4纸长边 self.mtx camera_matrix self.dist dist_coeffs self.obj_width object_real_width self.obj_height object_real_height self.fx camera_matrix[0, 0] self.fy camera_matrix[1, 1] def _undistort_frame(self, frame): 校正图像畸变 h, w frame.shape[:2] newcameramtx, roi cv2.getOptimalNewCameraMatrix(self.mtx, self.dist, (w,h), 1, (w,h)) undistorted cv2.undistort(frame, self.mtx, self.dist, None, newcameramtx) return undistorted def _find_a4_paper(self, image): 使用轮廓检测寻找图像中类似A4纸的矩形 gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred cv2.GaussianBlur(gray, (5,5), 0) edged cv2.Canny(blurred, 50, 150) contours, _ cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) contours sorted(contours, keycv2.contourArea, reverseTrue)[:5] # 取面积最大的5个轮廓 for contour in contours: peri cv2.arcLength(contour, True) approx cv2.approxPolyDP(contour, 0.02 * peri, True) # 寻找有四个顶点的轮廓 if len(approx) 4: # 计算轮廓的宽高比A4纸比例约为1:1.414 (sqrt(2)) x, y, w, h cv2.boundingRect(approx) aspect_ratio w / float(h) if 0.6 aspect_ratio 0.8 or 1.2 aspect_ratio 1.5: # 宽松的比例范围 # 对顶点进行排序左上右上右下左下 rect self._order_points(approx.reshape(4, 2)) return rect, (x, y, w, h) return None, None def _order_points(self, pts): 对矩形四个顶点进行排序左上右上右下左下 rect np.zeros((4, 2), dtypefloat32) s pts.sum(axis1) rect[0] pts[np.argmin(s)] # 左上角xy最小 rect[2] pts[np.argmax(s)] # 右下角xy最大 diff np.diff(pts, axis1) rect[1] pts[np.argmin(diff)] # 右上角y-x最小 rect[3] pts[np.argmax(diff)] # 左下角y-x最大 return rect def _calculate_distance(self, pixel_width, pixel_height): 根据像素尺寸计算距离使用宽度和高度取平均或根据姿态选择 # 简单平均更复杂的做法可以判断物体姿态选择更可靠的维度 distance_via_width (self.obj_width * self.fx) / pixel_width distance_via_height (self.obj_height * self.fy) / pixel_height # 返回平均值也可以根据宽高比判断哪个更可靠 return (distance_via_width distance_via_height) / 2.0 def process_frame(self, frame): 处理一帧图像返回带标注的图像和距离 undistorted_frame self._undistort_frame(frame) paper_contour, bbox self._find_a4_paper(undistorted_frame) distance None output_frame undistorted_frame.copy() if paper_contour is not None: # 绘制轮廓和边框 cv2.drawContours(output_frame, [paper_contour.astype(int)], -1, (0, 255, 0), 2) x, y, w, h bbox cv2.rectangle(output_frame, (x, y), (xw, yh), (255, 0, 0), 2) # 计算像素尺寸使用轮廓顶点计算更准确 (tl, tr, br, bl) paper_contour pixel_width np.linalg.norm(tr - tl) # 上边宽度 pixel_height np.linalg.norm(br - tr) # 右边高度 # 计算距离 distance self._calculate_distance(pixel_width, pixel_height) # 在图像上显示距离 cv2.putText(output_frame, fDist: {distance:.2f}m, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) return output_frame, distance # 主程序 if __name__ __main__: # 加载标定参数假设已保存为npy文件 try: mtx np.load(camera_mtx.npy) dist np.load(camera_dist.npy) except FileNotFoundError: print(未找到标定文件请先运行相机标定程序。) exit() # 初始化测距器目标设为A4纸宽0.21m高0.297m estimator MonocularDistanceEstimator(mtx, dist, object_real_width0.21, object_real_height0.297) # 打开摄像头 cap cv2.VideoCapture(0) if not cap.isOpened(): print(无法打开摄像头) exit() print(按 q 键退出程序。) while True: ret, frame cap.read() if not ret: break processed_frame, dist estimator.process_frame(frame) cv2.imshow(Monocular Distance Estimation, processed_frame) if dist: print(f当前估算距离: {dist:.3f}米, end\r) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()5.3 代码要点与调试技巧轮廓检测的鲁棒性示例中使用Canny边缘检测和轮廓近似来寻找矩形。在实际环境中光照变化、背景杂乱会影响检测。可以尝试使用自适应阈值代替固定阈值的Canny。在检测前先进行颜色过滤如果目标颜色已知。使用更稳定的角点检测方法如Shi-Tomasi来定位纸张的四个角。距离计算的稳定性单帧计算可能受噪声影响。可以加入简单的滤波如移动平均滤波来平滑距离输出避免数值跳动。# 简单的移动平均滤波 class MovingAverageFilter: def __init__(self, window_size5): self.window [] self.size window_size def update(self, value): if value is None: return None self.window.append(value) if len(self.window) self.size: self.window.pop(0) return sum(self.window) / len(self.window)多维度融合示例中同时使用了宽度和高度来计算距离并取平均。更好的策略是判断物体的姿态。如果物体宽度方向更正对相机则用宽度计算更准反之用高度。可以通过计算轮廓的宽高比和最小外接矩形的角度来粗略判断。6. 误差分析与性能优化实战单目测距的误差来源是多方面的理解并尽可能减少这些误差是提升系统实用性的关键。6.1 主要误差来源剖析误差类别具体原因影响程度缓解措施标定误差标定板不平、图片数量不足、角点检测不准高确保标定板平整采集15-20张高质量图片使用亚像素优化。内参漂移相机对焦/变焦后内参变化中-高固定焦距拍摄若使用变焦镜头需重新标定或建立查找表。物体尺寸误差先验尺寸不准确如人的身高估算高使用更精确的平均值或在线估计如基于统计模型。检测定位误差目标检测框不紧、角点定位偏差中优化检测算法使用亚像素级边缘/角点定位。姿态假设误差物体不平行于图像平面方法一高改用基于接地点的方法或引入姿态估计。地面假设误差地面不平、相机俯仰角标定不准方法二高定期标定外参或结合IMU数据动态估计姿态。镜头畸变残余标定未完全校正尤其是边缘中使用更高阶的畸变模型如k3, k4, k5确保标定覆盖全图。6.2 提升测距精度的实用技巧融合多尺度信息不要只依赖一个尺寸。如果物体有多个已知尺寸的特征如车牌的长和宽、人脸的瞳距和鼻尖到下巴的距离可以同时利用它们进行计算并通过RANSAC等算法剔除 outliers得到更鲁棒的距离估计。利用消失点约束在结构化场景如道路、室内走廊中平行线的消失点可以提供强大的几何约束。结合消失点和已知的物体尺寸或相机高度可以更稳定地计算距离对物体姿态的依赖性更低。引入滤波与跟踪对于视频流不要孤立地处理每一帧。使用卡尔曼滤波Kalman Filter或粒子滤波Particle Filter对目标的位置和距离进行跟踪。这可以平滑噪声并在目标短暂丢失时进行预测大大提升体验的连贯性和稳定性。在线标定与自适应对于固定场景的应用可以在场景中放置一个或多个已知尺寸的参考物。系统运行时自动检测这些参考物用它们来动态微调距离计算的尺度因子补偿内参漂移或安装误差。深度学习辅助传统的几何方法依赖于精确的特征提取和假设。可以结合深度学习使用更鲁棒的目标检测和实例分割网络如YOLOv8, Mask R-CNN来获取精确的像素级掩码比矩形框更准。直接训练一个网络进行单目深度估计如MiDaS虽然它是相对深度但如果在固定场景下用少量真实距离数据进行微调可以得到不错的绝对距离估计作为几何方法的补充或验证。6.3 常见问题排查清单当你发现测距结果不准时可以按以下清单逐一排查标定是否可靠检查重投影误差是否 1像素。用cv2.undistort看校正后的图像直线是否笔直。目标检测是否准确可视化检测框看是否紧密贴合物体边缘。尝试手动标注一个框用这个框计算距离是否准确如果准确问题在检测算法。已知尺寸是否正确用尺子实际测量一下目标物体确认输入的程序的数据无误。考虑物体的平均尺寸是否有代表性比如“成年人”的身高用1.7米可能偏差较大。物体姿态是否满足假设对于“已知尺寸”法物体是否正对相机如果倾斜计算的距离会偏大。可以尝试从不同角度拍摄同一距离的物体观察距离读数变化。对于“地面假设”法物体是否确实接触地面相机高度和俯仰角参数是否准确光照与环境影响强光、反光、阴影是否影响了目标特征的提取如轮廓、角点尝试在不同光照条件下测试观察结果稳定性。单目测距是一个平衡成本、复杂度和精度的技术方案。它无法达到双目或深度相机的精度但在许多对精度要求不极端、成本控制严格的场景下通过精细的标定、合理的假设和巧妙的算法设计完全可以达到实用水平。理解其原理的每一个环节并系统地分析误差来源是将其成功应用于实际项目的关键。