ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

单目测距实战:从相机标定到距离计算的完整实现

单目测距实战:从相机标定到距离计算的完整实现 1. 项目缘起从“看得见”到“量得出”最近在整理一些视觉相关的项目资料翻到了一个挺有意思的早期实验——单目测距。说它简单是因为它的核心逻辑确实不复杂不需要昂贵的双目摄像头也不需要复杂的激光雷达仅仅依靠一个普通的摄像头就能估算出画面中某个物体离我们有多远。这听起来有点像魔法但背后的原理其实是我们每天都在用的“经验”和“几何”。比如你看到远处一个人很小就知道他离得远看到近处一个杯子很大就知道它离得近。单目测距就是尝试用数学和程序来量化这种“经验”。这个实验的价值在于它为我们打开了一扇低成本感知世界深度的大门。无论是机器人避障、辅助驾驶中的前车距离预警还是AR应用中虚拟物体的放置甚至是无人机在室内环境下的悬停都可能用到类似的思路。当然它也有其局限性比如对已知物体尺寸的依赖、对相机标定的严格要求等这些我们后面都会详细拆解。但无论如何作为一个入门计算机视觉深度感知的实践项目它非常合适。今天我就把这个实验的完整过程、核心原理、踩过的坑以及一些优化思路系统地梳理一遍希望能给想动手尝试的朋友一个清晰的参考。2. 核心原理拆解透视与比例的数学游戏单目测距之所以可行核心依赖于一个经典的几何模型针孔相机模型和相似三角形原理。我们不需要被这些名词吓到其实理解起来非常直观。想象一下你面前有一个固定高度的物体比如一个标准的330毫升可乐罐高度大约是12.3厘米。你用手机摄像头对准它在照片里这个可乐罐会呈现为一个有高度的像素区域。关键点来了当可乐罐离你越远它在图像传感器CMOS/CCD上成像的高度就越小离你越近成像高度就越大。这个关系是严格成反比的。我们可以用一张简化的侧视图来理解这个过程。假设相机光心可以粗略理解为镜头中心是一个点O成像平面传感器在它后面距离为f的地方这个f就是相机的焦距以像素为单位时我们常称之为fx或fy是相机内参的一部分。可乐罐的实际高度为H其底部和顶部发出的光线穿过光心O在成像平面上分别形成了像点。这两个像点之间的像素距离就是我们能在图片中测量出的物体像素高度h。此时根据相似三角形我们可以列出比例关系H / D h / f。其中D就是我们要求的物体到相机的距离。稍微变换一下就得到了单目测距最基础的公式D (H * f) / h这个公式就是整个实验的基石。它告诉我们只要我们知道物体的真实物理尺寸H、相机的焦距f像素单位并在图像中精准地测量出该物体的像素高度h就能计算出距离D。这里有几个关键概念需要明确真实物理尺寸H这是必须已知的先验知识。测距的目标物体其尺寸高度或宽度必须是已知且固定的。比如我们选择可乐罐就是因为它的高度是标准化的。如果换成一个未知尺寸的盒子这个公式就失效了。这是单目测距最大的限制之一。焦距f像素单位这不是镜头上的物理焦距如50mm而是通过相机标定得到的内参矩阵中的fx和fy。它代表了在x和y方向上每单位物理长度如毫米对应多少个像素。标定的目的之一就是精确获取这个值。如果直接用物理焦距和传感器像元尺寸去换算误差会很大因为制造和组装总有偏差。像素高度h这需要在图像中通过图像处理技术如轮廓检测、目标检测精确提取。测量的准确性直接决定了最终距离估算的精度。所以整个实验的流程链条就清晰了相机标定获取内参含f→ 在图像中检测并测量目标物体得到h→ 结合已知物体真实尺寸H → 代入公式计算距离D。3. 环境搭建与工具选型为什么是PythonOpenCV工欲善其事必先利其器。对于这个实验工具链的选择直接关系到上手难度和实验效率。我选择的是Python OpenCV的组合这是目前计算机视觉入门和实践最主流、最友好的方案。3.1 为什么选择PythonPython的语法简洁拥有极其丰富的科学计算和数据处理库如NumPy, SciPy非常适合做算法原型验证和快速实验。我们不需要花费大量时间在内存管理、指针操作上可以更专注于算法逻辑本身。社区庞大遇到任何问题几乎都能找到相关的代码片段或讨论。3.2 为什么选择OpenCVOpenCVOpen Source Computer Vision Library是一个跨平台的计算机视觉库它为我们封装了成百上千个经典的图像处理和计算机视觉算法。对于我们这个实验我们需要用到的几乎所有功能OpenCV都提供了成熟、高效的实现相机标定cv2.calibrateCamera等函数。图像读取与显示cv2.imread,cv2.imshow,cv2.VideoCapture。颜色空间转换与阈值分割cv2.cvtColor,cv2.inRange。轮廓查找与筛选cv2.findContours,cv2.contourArea。形态学操作cv2.erode,cv2.dilate用于去噪。绘制与标注cv2.rectangle,cv2.putText用于可视化结果。用C也可以但配置环境更复杂调试周期更长。对于快速验证想法的实验阶段PythonOpenCV是效率最高的选择。3.3 环境搭建详细步骤与避坑指南这里以Windows系统为例介绍最稳妥的安装方式。很多人喜欢用pip install opencv-python这确实简单但对于需要用到contrib模块虽然本实验不一定需要或追求稳定性的情况我推荐使用Anaconda环境。步骤1安装Anaconda去Anaconda官网下载并安装对应你系统版本的Anaconda。它自带了Python、pip以及很多科学计算库能避免很多依赖冲突。步骤2创建并激活虚拟环境打开Anaconda Prompt或系统终端如果你配置了conda路径执行以下命令创建一个名为mono_depth的独立环境Python版本建议3.8或3.9兼容性最好conda create -n mono_depth python3.8 conda activate mono_depth使用虚拟环境是个好习惯它能将项目依赖与系统全局Python隔离避免版本冲突把系统环境搞乱。步骤3安装OpenCV在激活的mono_depth环境中使用pip安装OpenCVpip install opencv-python如果你后续可能需要用到SIFT、SURF等专利算法在opencv-contrib-python中或者想用更全的功能可以安装pip install opencv-contrib-python但请注意opencv-contrib-python和opencv-python不能同时安装二者选一即可。对于我们这个基础测距实验opencv-python足够了。步骤4验证安装安装完成后启动Python解释器或创建一个test.py文件输入以下代码import cv2 print(cv2.__version__)如果能成功打印出版本号如4.8.0并且不报错说明安装成功。注意一个常见的巨坑——“ModuleNotFoundError: No module named ‘cv2’”。这个问题99%的原因是你的Python解释器路径不对。你可能在A环境下安装了OpenCV但在VSCode或PyCharm中运行时却使用了系统默认的Python解释器或另一个环境下的解释器。务必在IDE中检查并切换到你创建并安装了OpenCV的那个虚拟环境mono_depth。4. 第一步相机标定——让相机“认识自己”这是整个实验中最关键、也最容易出错的一步。标定的目的是获取我们之前公式里提到的相机内参矩阵Intrinsic Matrix和畸变系数Distortion Coefficients。内参矩阵包含了焦距f以像素为单位和主点坐标cx, cy等信息畸变系数则用于校正镜头产生的图像扭曲桶形畸变、枕形畸变。为什么必须标定因为手机或USB摄像头都不是理想的针孔模型镜头有畸变传感器像元也不是完美的正方形。不经过标定我们测量出的像素坐标h和实际物理位置的对应关系是不准确的用这个h去算距离结果自然偏差很大。4.1 标定板的选择与制作标定需要用一个已知精确几何图案的物体。最常用的是棋盘格标定板。OpenCV内置了针对棋盘格的标定函数。你需要准备一张棋盘格图片并把它打印出来贴在一个平整的硬板如亚克力板上。关键点方格数量通常选择内部角点intersection points数量比如9x6意思是每行10个方格有9个内部角点每列7个方格有6个内部角点。OpenCV检测的是内部角点所以行列数要减一。方格尺寸必须精确测量每个方格的实际物理边长比如25.0 mm。这个值将作为世界坐标系的尺度必须准确。用游标卡尺测量多个方格取平均。4.2 数据采集多角度拍摄标定板你需要用待标定的相机从不同角度、不同距离、不同方位拍摄至少15-20张标定板的照片。照片要满足标定板要尽量充满画面不同区域四个角、中心。标定板要有明显的倾斜、旋转不要总是正对着。确保标定板平整成像清晰光线均匀避免反光和阴影。 将这批照片保存在一个专门的文件夹里。4.3 标定代码实现与解读下面是一个完整的相机标定脚本。我会逐段解释其作用。import cv2 import numpy as np import glob # 1. 定义标定板参数 CHECKERBOARD (6, 9) # 内部角点数量 (rows, columns) 对应9x6的棋盘格 square_size 25.0 # 每个方格的实际物理尺寸单位毫米 # 2. 为世界坐标系中的角点准备坐标 # 例如(0,0,0), (25,0,0), (50,0,0) ... (200,150,0) objp np.zeros((CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32) objp[:, :2] np.mgrid[0:CHECKERBOARD[1], 0:CHECKERBOARD[0]].T.reshape(-1, 2) objp * square_size # 将像素坐标乘以物理尺寸得到真实世界坐标毫米 # 3. 用于存储所有图像的世界坐标点和图像坐标点 objpoints [] # 3d points in real world space imgpoints [] # 2d points in image plane. # 4. 读取所有标定图片 images glob.glob(./calibration_images/*.jpg) # 修改为你的图片路径 for fname in images: img cv2.imread(fname) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 5. 查找棋盘格角点 ret, corners cv2.findChessboardCorners(gray, CHECKERBOARD, None) # 6. 如果找到添加对象点和图像点 if ret True: objpoints.append(objp) # 提高角点检测精度 corners2 cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria(cv2.TERM_CRITERIA_EPS cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)) imgpoints.append(corners2) # 可选在图像上绘制并显示角点 img cv2.drawChessboardCorners(img, CHECKERBOARD, corners2, ret) cv2.imshow(Found Corners, img) cv2.waitKey(500) # 显示500毫秒 cv2.destroyAllWindows() # 7. 进行相机标定 if len(objpoints) 0: ret, mtx, dist, rvecs, tvecs cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) print(相机内参矩阵 (mtx):) print(mtx) print(\n畸变系数 (dist):) print(dist) # 计算重投影误差评估标定质量 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)}) # 误差通常应小于0.5像素越小越好 # 8. 保存标定结果供后续使用 np.savez(camera_calibration.npz, mtxmtx, distdist) print(标定参数已保存到 camera_calibration.npz) else: print(未在图片中找到足够的棋盘格角点请检查图片和CHECKERBOARD参数。)代码关键点解析objp定义了世界坐标系下棋盘格每个角点的3D坐标。我们假设棋盘格在Z0的平面上所以Z坐标全是0。X和Y坐标根据方格数量和尺寸生成。findChessboardCornersOpenCV的核心函数用于在灰度图中自动查找棋盘格角点的初始像素位置。cornerSubPix亚像素级角点优化。初始的角点位置是整数像素这个函数能将其优化到亚像素精度显著提高标定精度。calibrateCamera执行标定的核心函数。输入是所有图像对应的3D世界点(objpoints)和2D图像点(imgpoints)以及图像尺寸。它通过最小化重投影误差求解出最优的相机内参mtx、畸变系数dist以及每张图片的旋转向量rvecs和平移向量tvecs。内参矩阵mtx是一个3x3的矩阵形式通常为[[fx, 0, cx], [0, fy, cy], [0, 0, 1]]。其中fx,fy就是我们公式里需要的焦距像素单位cx,cy是图像的主点坐标通常接近图像中心。重投影误差是评价标定好坏的核心指标。它计算的是用标定得到的参数将3D点重新投影回2D图像得到的投影点与之前检测到的角点之间的平均像素距离。这个值越小越好一般要小于0.5像素。如果误差很大比如大于2说明标定数据质量差或检测有问题需要重新采集图片。实操心得标定质量是测距精度的生命线。我最初实验时用A4纸打印棋盘格没有贴平导致标定板在照片中有轻微弯曲重投影误差达到了1.2像素测距结果在2米处就有近20厘米的波动。后来改用硬质亚克力板贴平并且精心拍摄了20多张各个角度的清晰照片误差降到了0.3像素以下测距稳定性立刻大幅提升。另外光照也很重要避免局部过亮或过暗导致角点检测失败。5. 第二步目标检测与像素尺寸测量拿到标定参数后下一步就是在实时视频流或图片中找到我们要测距的目标物体并精确测量它在图像中的像素高度或宽度。我们以那个经典的330毫升可乐罐为例假设其真实高度H 123mm。5.1 图像预处理从BGR到二值化摄像头读取的图像通常是BGR格式。我们的可乐罐是红色的所以一个自然的想法是利用颜色来分割。但直接使用RGB/HSV空间并设定一个固定的红色范围对环境光非常敏感。更好的做法是转换到HSV色彩空间HSVHue, Saturation, Value比BGR对光照变化稍微鲁棒一些色相H通道基本定义了颜色。定义颜色阈值范围通过实验确定可乐罐红色区域对应的H、S、V范围。这个范围可能需要根据你的环境光进行调整。应用阈值得到掩膜使用cv2.inRange函数将图像中在阈值范围内的像素设为白色255之外的设为黑色0得到一个二值化的掩膜图像。import cv2 import numpy as np # 加载之前保存的标定参数 calibration_data np.load(camera_calibration.npz) mtx calibration_data[mtx] dist calibration_data[dist] # 已知物体真实高度 (毫米) KNOWN_HEIGHT 123.0 # 可乐罐高度 # 初始化摄像头 cap cv2.VideoCapture(0) # 0代表默认摄像头 # 定义红色在HSV空间的范围 (需要根据实际物体颜色调整) # 红色在HSV色环上位于0°和180°附近所以需要两个范围 lower_red1 np.array([0, 70, 50]) upper_red1 np.array([10, 255, 255]) lower_red2 np.array([170, 70, 50]) upper_red2 np.array([180, 255, 255]) while True: ret, frame cap.read() if not ret: break # 1. 畸变校正 (使用标定得到的参数) h, w frame.shape[:2] newcameramtx, roi cv2.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h)) undistorted_frame cv2.undistort(frame, mtx, dist, None, newcameramtx) # 2. 转换到HSV空间 hsv_frame cv2.cvtColor(undistorted_frame, cv2.COLOR_BGR2HSV) # 3. 根据红色阈值创建掩膜 mask1 cv2.inRange(hsv_frame, lower_red1, upper_red1) mask2 cv2.inRange(hsv_frame, lower_red2, upper_red2) mask cv2.bitwise_or(mask1, mask2) # 4. 形态学操作去除小噪声点填充空洞 kernel np.ones((5,5), np.uint8) mask cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) # 开运算先腐蚀再膨胀去小白点 mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 闭运算先膨胀再腐蚀填小黑洞 cv2.imshow(Mask, mask) # 显示处理后的掩膜方便调试5.2 轮廓查找与筛选得到干净的掩膜后我们就可以用cv2.findContours来查找白色区域的轮廓了。但图像中可能有很多红色物体我们需要从中筛选出最可能是可乐罐的那个轮廓。# 5. 查找轮廓 contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 初始化距离变量 distance 0 if len(contours) 0: # 6. 筛选轮廓按面积排序取最大的假设可乐罐是画面中最大的红色物体 contours sorted(contours, keycv2.contourArea, reverseTrue) largest_contour contours[0] # 可选进一步筛选比如通过轮廓的宽高比可乐罐是细长的 x, y, w_pixel, h_pixel cv2.boundingRect(largest_contour) aspect_ratio float(w_pixel) / h_pixel if h_pixel ! 0 else 0 # 可乐罐的宽高比通常小于1 (比如~0.6)可以设置一个范围如 0.4 aspect_ratio 0.8 if 0.4 aspect_ratio 0.8 and cv2.contourArea(largest_contour) 500: # 面积阈值过滤噪声 # 7. 绘制边界框 cv2.rectangle(undistorted_frame, (x, y), (xw_pixel, yh_pixel), (0, 255, 0), 2) # 计算像素高度 (就是我们需要的 h) # 注意boundingRect得到的是矩形框其高度可能略大于物体实际高度但对于直立物体这是一个很好的近似。 pixel_height h_pixel # 8. 单目测距计算 # 公式: D (H * f) / h # 从内参矩阵 mtx 中获取焦距 f (这里用fy因为高度对应y方向) fy mtx[1, 1] if pixel_height 0: distance_cm (KNOWN_HEIGHT * fy) / pixel_height / 10.0 # 转换为厘米 distance distance_cm # 在图像上显示距离 cv2.putText(undistorted_frame, fDistance: {distance:.1f} cm, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)5.3 距离计算与显示代码中已经实现了核心的距离计算。这里有几个细节需要注意使用哪个焦距内参矩阵mtx中的fx和fy可能略有不同这是因为像素不是完美的正方形。我们测量的是物体的像素高度h_pixel它对应图像坐标系的y轴方向因此理论上应该使用fy。如果测量的是像素宽度则应使用fx。在大多数情况下如果相机传感器是规整的fx和fy非常接近用哪个影响不大。单位换算公式D (H * f) / h计算出的D其单位与H一致。我们的H是123.0毫米f是像素单位h也是像素单位所以D的结果单位是毫米。代码中除以10是为了转换成厘米显示。边界框的近似我们用cv2.boundingRect得到的是物体轮廓的最小外接正矩形。对于像可乐罐这样基本是竖直圆柱体的物体这个矩形的高度h_pixel可以很好地近似物体的像素高度。但如果物体有倾斜或不是规则形状这个近似误差会变大。更精确的做法是找到轮廓的最小外接旋转矩形cv2.minAreaRect然后计算其高度但这对于直立物体提升有限且计算稍复杂。最后显示结果并清理资源# 显示最终结果 cv2.imshow(Monocular Distance Estimation, undistorted_frame) # 按q退出 if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()6. 误差来源分析与优化策略实验跑起来后你可能会发现测得的距离有波动或者在特定距离上偏差较大。这是完全正常的。单目测距的精度受多种因素影响理解这些误差来源是提升系统鲁棒性的关键。6.1 主要误差来源相机标定误差这是系统性误差的最大来源。重投影误差的大小直接反映了标定的精度。标定板不平、方格尺寸测量不准、拍摄图片数量不足或角度单一、角点检测不准确都会导致内参矩阵特别是焦距f不准确。目标检测与像素测量误差颜色分割不精确光照变化、物体反光、背景干扰会导致掩膜不完整或有噪声影响轮廓提取。边界框拟合误差boundingRect得到的是轴对齐矩形如果物体有倾斜其高度会大于实际高度导致距离估算偏近。像素高度测量在图像中一个像素的边缘并不总是清晰的尤其是低分辨率图像这会给高度测量带来±1像素的误差。这个误差在物体距离较远成像高度h很小时会被放大。例如h10像素时±1像素的误差就是10%对距离计算影响巨大。先验知识误差我们假设可乐罐的高度是精确的123.0mm。但实际中罐子可能因品牌、容量略有差异或者我们测量时存在误差。这个H值的误差会直接线性地传递到距离D上。假设模型误差我们的公式基于严格的相似三角形和针孔模型。现实中我们进行了畸变校正但校正并非完美。此外我们假设物体底部接触地面或支撑面且与相机光轴垂直这个假设在实际复杂场景中往往不成立。6.2 针对性优化策略针对以上误差我们可以从多个层面进行优化策略一提升标定精度高质量标定板使用高精度打印、表面平整、无反光的标定板。充足且多样的数据拍摄20-30张以上图片覆盖画面各个区域和不同倾斜角度。精确的方格尺寸使用高精度游标卡尺多次测量取平均。验证标定结果除了看重投影误差还可以用标定好的相机去拍摄一个已知尺寸的物体用另一把尺子用同样的测距程序测试看在不同距离上的误差曲线反向验证标定参数。策略二改进目标检测动态阈值或机器学习对于颜色分割可以尝试在程序开始时让用户框选目标物体自动计算其HSV范围实现自适应阈值。更高级的做法是使用目标检测模型如YOLO、SSD来定位物体这能极大提升在复杂背景下的鲁棒性但会引入模型复杂度。轮廓精炼使用cv2.minAreaRect()获取旋转矩形对于非直立的物体能更准确地反映其实际朝向和尺寸。同时可以对轮廓进行多边形近似(cv2.approxPolyDP)平滑轮廓减少噪声影响。多帧平滑对于视频流可以对连续多帧检测到的像素高度或计算出的距离进行移动平均或卡尔曼滤波能有效抑制单帧噪声带来的跳动。策略三系统级修正地面假设与俯仰角如果相机不是水平放置或者物体不在一个已知高度的平面上公式需要修正。如果知道相机相对于地面的俯仰角可以通过几何关系进行补偿。更通用的方法是使用多特征点如同时知道物体的高度和宽度或者知道物体上两个特征点的距离建立方程组来求解这可以放松对物体姿态的假设。非线性优化将单目测距看作一个优化问题。如果我们能从多个帧、多个不同距离观测同一个物体或者观测同一个场景中多个已知尺寸的物体我们可以构建一个优化函数同时优化相机内参微调、物体距离甚至姿态这属于SLAM同步定位与地图构建或SfM运动恢复结构的范畴远超本实验范围但指出了更精确的方向。实操心得不要追求绝对精度关注相对趋势和稳定性。在低成本单目方案中想达到厘米级甚至毫米级的绝对精度是非常困难的。这个实验更重要的价值是理解原理并实现一个在特定条件下如固定光照、固定物体、相机静止能稳定输出、趋势正确的测距系统。例如让可乐罐从远到近移动程序输出的距离值应该单调递减且变化平滑这就算成功了。在实际应用中可以针对特定场景如室内机器人、固定工位的检测进行大量的数据采集和参数标定从而在有限的工作范围内达到可用的精度。7. 从实验到应用思路拓展与局限性完成了基础的单目测距实验我们可以思考它的应用场景和如何将其变得更实用。7.1 可能的简单应用场景桌面机械臂抓取在固定的工作台上相机俯瞰桌面。已知待抓取物体如螺丝、药瓶的尺寸通过单目测距可以估算物体相对于机械臂基座或末端执行器的粗略位置辅助进行粗略定位再结合视觉伺服进行精确定位。简易车辆倒车距离提示在车尾安装一个朝后的摄像头已知车牌或保险杠上某个特征的高度可以实时估算车尾与后方障碍物的距离实现一个低成本的距离告警系统。当然这需要极高的稳定性和可靠性验证不能直接用于安全控制。互动展示与AR在博物馆或展厅摄像头识别特定的展品已知尺寸可以估算观众与展品的距离从而触发不同距离下的互动内容如近距离显示细节远距离显示简介。7.2 系统的核心局限性我们必须清醒认识到这种方法的局限性避免将其误用于不合适的场景依赖先验尺寸必须已知物体的实际尺寸。这极大地限制了其通用性。对于未知物体此方法无效。对姿态敏感公式D (H * f) / h成立的前提是物体的高度方向与成像平面平行。如果物体倾斜我们在图像中测得的像素高度h会小于其正对时的投影高度从而导致计算出的距离D远大于实际距离。这是该方法最大的理论误差来源之一。精度随距离增加而急剧下降由公式可知距离D与像素高度h成反比。当物体很远时h很小可能只有几个像素此时h的测量误差哪怕只有1个像素会导致距离估算产生巨大百分比误差。因此该方法通常只适用于较近的距离范围例如几米内。受环境干扰大基于颜色或简单特征的检测方法在光照变化、背景复杂、遮挡、反光等情况下极易失效。7.3 进阶方向如果你对这个方向感兴趣可以沿着以下路径深入学习深度学习目标检测用YOLO、Faster R-CNN等模型替代颜色分割可以稳定检测出特定类别的物体如“可乐罐”、“人”、“汽车”。但模型通常不直接给出物理尺寸你仍然需要知道该类物体的平均尺寸或通过其他方式获取尺寸。基于深度学习的单目深度估计这是当前的研究热点。通过训练一个神经网络直接从单张RGB图像预测每个像素的深度图即距离。这种方法不依赖于已知物体尺寸但需要大量的、带有真实深度标签的数据进行训练且泛化能力取决于训练数据。多视图几何与SLAM使用单个移动的相机通过分析连续帧之间的特征点匹配可以同时恢复出相机的运动轨迹和场景的3D结构稀疏点云。这属于“运动恢复结构”Structure from Motion, SfM或视觉SLAM的范畴是更强大但也更复杂的深度感知手段。这个简单的单目测距实验就像一把钥匙为你打开了计算机视觉中三维感知这扇大门。它用最直观的方式展示了如何将二维图像信息与几何先验结合反推三维世界。虽然简单但其蕴含的针孔模型、相机标定、图像处理等思想是通往更高级视觉算法不可或缺的基石。希望你在动手实现的过程中不仅能得到一串距离数字更能体会到背后那一套严谨的数学与工程逻辑。
返回列表