立体匹配的问题及基本解决思路与流程

参考

一文详解三维重建中的立体匹配

1.立体匹配的困难之处

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.基本解决思路

2.1 图像预处理 Preprocess

如果是因为两幅图像的亮度、噪声不一致,一般会先对图像做预处理,使得两幅图像的整体质量区域一致。

经典方法有:

  1. 对图像做滤波操作去除图像中的噪声,比如高斯拉普拉斯滤波和双边滤波等
  2. 对图像亮度做归一化操作,比如减去领域的均值
  3. 对图像做特征变换,提取图像中不变的特征供后续处理,如Census变换

2.2 代价计算 Cost Computation

若计算同名点匹配代价时采用的是单个像素点的绝对值的差异,很容易受到噪声的干扰。

规避方法有二:

  1. 换用更鲁棒的单像素的代价函数
  2. 采用邻域支持窗来计算整体代价

下面细说。

1.换用更鲁棒的单像素的代价函数

如像素差异绝对值 Absolute Differences,平方差 Squared Differences,截断绝对差 Truncated Absolute Differences (TAD),

2.采用邻域支持窗来计算整体代价

仅仅考虑单个像素,还是很难得到好的结果。

更好的方式是通过计算所关注的像素点的邻域的整体情况,来提升信噪比,减少噪声的影响。我们把这个邻域范围称为“支持窗(Support Window)”,通过支持窗内所有像素来计算一个匹配代价值。

这种策略就是把单个像素的计算转换为一个支持窗内的整体计算了。

如:像素绝对差值和 Sum of Absolute differences (SAD),像素差值平方和Sum of Squared differences (SSD),截断绝对差值和 Sum of truncated absolute differences (STAD)。

除了这些简单的代价函数,还有更多方法,比如利用两个图像的互相关信息的,利用图像梯度域信息的,或是利用一些非参数方法的,等等。

总之,我们可以为R中的每个像素点和选定的T中的像素点计算一个代价,并且这个代价还具有很高的区分度。

是在一个范围[dmin, dmax]中搜索匹配点,因此对任何一个R中的像素点,可以算出dmax - dmin + 1种代价值。如果图像的宽高分别为W和H,那么我们总共会得到W x H x (dmax - dmin + 1)种代价值。所有这些代价值可以存储到一个立方体中,这就是所谓的代价立方体。

在这里插入图片描述

2.3 代价聚合(Cost Aggregation)和视差优化(Disparity Optimization)

通过支持窗计算代价已经对图像的噪声、光照不一致等等提升了一定的鲁棒性,但依然有很多问题遗留下来。

比起最基础的方案,视差图似乎平滑了很多,没有了大片的噪声。但是很多局部是错误的。

固定支持窗,英文是Fixed Window,简称FW。上述结果不够理想,是因为FW策略违背了一些基础假设。

  1. FW假设支持窗是正对相机的平面,支持窗内的所有点的视差是一致的,这显然和实际情况不一样。
  2. 支持窗忽略了窗口内深度不连续,甚至有突变的情况,而强行把窗口内的视差值加权平均到一起。这就会导致产生的视差图内出现大量的物体边缘错误。
  3. 当场景中有大面积的重复纹理、无纹理的部分时,小尺寸的支持窗无法解决同名点计算错误的问题,这种情况下可能出现很多候选像素点的代价值都一样,难以区分的情况。

尽管固定支持窗有这样那样的缺点,但它理解和实现都很容易,且非常便于并行化,在现代处理器上也比较容易做到实时运行,非常容易采用FPGA这样的硬件进行实现,性价比很足!所以很多传统算法的代价计算这一步都是采用固定大小支持窗来完成的。而要继续提升最终算法的效果,还得靠后续的步骤。

主要有两大类思路,也就是局部聚合思路,和全局优化思路。

2.3.1. 代价聚合(Cost Aggregation)

局部聚合思路通过对代价立方体中同一视差的代价进行某种程度的聚合,来减少或消除错误代价的影响,这一步就是所谓的代价聚合(Cost Aggregation)。

同一个视差的窗口我们会扩大并将代价立方体中相应的代价聚合在一起。

一般来说是通过调整支持窗的位置、形状、窗内各像素的权重等等来完成聚合的。

2.3.2 视差优化(Disparity Optimization)

全局优化思路,则是希望寻找到每个像素的最优视差结果,使得全局的、整体的匹配代价最小,这一步被称为视差优化(Disparity Optimization)。

这个过程就变成了一个最优化某个能量函数的过程,该函数通常写成如下的形式:
在这里插入图片描述
等号右边第1项是数据项,用于约束全局代价最小化。

但是代价立方体中通常含有噪声和错误,直接最小化求得的结果也会有很多问题,所以还需要第2项平滑项。这一项一般用于给出某些额外的约束条件,比如通常假设整个图像的视差是平滑变化的。这样视差的大变化只会在场景内视差边缘处产生,一般也和图像内物体边缘高度相关。

如:图割法、置信度传播法、动态规划法等

2.4 视差后处理(Disparity Refinement)

前面介绍的步骤最终将输出一张视差图,然而正如你已经看到的,即便是在上面那些受约束的场景,得到的视差图依然不是完美的,还是有很多错误。

因此,还需要一个后处理的步骤,来消除其中的错误,得到更准确的视差图。

在这里插入图片描述
需要解决的问题有:

  1. 亚像素插值:我们上面计算的视差值都是离散的整数值,但实际场景物体存在连续变化的视差,我们希望得到以浮点数表示的更精细的视差值。一般来说,会采用某种二次的抛物线插值法,得到连续的视差值,计算量也比较低,结果也不错。
  2. 噪声和错误消除:有时候会简单采用图像滤波的技术来处理视差图,也能得到不错的结果。从简单的中值滤波,到复杂的双边滤波都有人尝试。另外一个重要的技巧是双向匹配,这种方法分别以双目图像中左图和右图作为参考图像R计算两个视差图(缺点:增加了计算量)。然后它认为一对匹配点的视差值是互反的,也就是说一对正确匹配点的视差值会非常接近。如果不满足这个条件那么对应的视差值应该就是错误的。

3. 如何确定视差范围

在这里插入图片描述
在这里插入图片描述

<think>嗯,用户的问题是关于在PCL库中实现立体匹配算法的示例代码。用户明确提到了参考站内引用中的PCL相关内容,说明用户对点云处理和立体匹配的结合感兴趣。从用户的问题来看,ta应该是有一定开发经验的用户,可能在尝试实现三维重建或立体视觉相关的项目。用户提到“解决方案或教程”,说明ta更关注实用性的代码实现而非理论细节。回顾引用内容,引用[2]和[4]特别重要:-引用[2]提到PCL提供立体匹配工具包,可利用SGM进行3D重建-引用[4]详细说明了PCL的配准算法,包括ICP等用户没有明确说明应用场景,但提到“立体匹配算法示例代码”,推测可能用于三维重建、机器人导航或自动驾驶领域。ta的核心需求是找到可以直接运行的PCL立体匹配代码,最好包含预处理和后处理流程。PCL中虽然不直接提供SGM实现,但相关模块需要结合使用。用户可能需要:1基础立体匹配生成视差图2视差图转点云3点云处理/配准考虑到用户要求“示例代码”,应该提供完整的代码框架,特别是容易被忽略的点云转换部分。同时需要提醒依赖关系和版本问题,因为OpenCV和PCL的接口变化可能影响兼容性。用户可能会遇到的难点包括:-参数调整困难(特别是SGM的P1/P2参数)-点云生成时的坐标转换-内存优化问题这些都需要在代码注释中特别标注。值得注意用户引用中提到了OpenCV和C++实现,所以补充说明PCL+OpenCV协同工作的方式会很有帮助。最后再提供性能优化建议,帮助用户应对实际应用中的效率问题。</think> 好的,基于您的要求查找在PCL库中实现**立体匹配算法**的解决方案或示例代码,以及对相关流程的介绍如下: 📌 **核心要点:** 1. **PCL的主要角色:** PCL (**P**oint **C**loud **L**ibrary)本身的核心是**处理点云数据**(离散的三维点集合)。它不专注于原始图像处理或基础的稠密视差图计算(即直接从左右图像生成视差的像素级匹配过程)。 2. **集成SGM:** PCL提供的功能更多是利用立体匹配(如SGM)*生成的视差图*来**计算点云(3D重建)**,或者对已经存在的点云进行后续处理(如滤波、配准、表面重建等)。 3. **视差图来源:** 生成视差图本身,通常需要依赖**其他库**(最常见的是OpenCV)来实现基础的立体匹配算法(包括SGM)。PCL在**`pcl::stereo`模块**中提供了一些立体视觉相关的工具和接口,但其视差图生成功能相对基础和有限,且并非PCL的核心优势或主要应用方向。 4. **典型流程(结合OpenCV & PCL):** 在PCL生态中进行立体视觉处理和3D重建的流程通常是: * **步骤1: 立体图像获取**(左图、右图) * **步骤2: 预处理**(校正、去噪等,常用OpenCV) * **步骤3: 立体匹配 & 视差计算**(核心步骤:常用**OpenCV**中的`cv::StereoSGBM`(Semi-Global Block Matching)类或其`cv::StereoSGM`(通常需要较新OpenCV版本))⭐️ * **步骤4: 视差图转点云**(将视差图转换为点云,这一步PCL可以直接完成) * **步骤5: 点云后处理3D重建**(滤波、配准、表面重建,这是**PCL的核心功能**⭐️) --- 🔧 **PCL相关模块示例(重点关注点云生成后处理):** 虽然核心匹配在OpenCV,但PCL提供了连接两者的桥梁: 1. **`pcl::io::PointCloudImageExtractorFromLabelField` (或类似) + `pcl::PointCloud`:** 这个思路是利用 **`pcl::stereo::DisparityMapConverter`** 结合视差图数据来生成点云。视差图数据本身(`DisparityImage`)需要用其他方式获得(如OpenCV计算)。 ```cpp #include <pcl/point_cloud.h> #include <pcl/point_types.h> #include <pcl/io/pcd_io.h> #include <pcl/stereo/disparity_map_converter.h> #include <opencv2/opencv.hpp> // 用于获取视差图 (disparity_map) #include <opencv2/core/eigen.hpp> // 用于OpenCV Mat到Eigen转换 (如果需要) // ... 假设已使用OpenCV计算得到视差图 cv::Mat disparity_map (数据类型通常为 CV_16S 或 CV_32F) // ... 已获取相机内参(焦距fx, fy, 主点cx, cy)和基线距离baseline // 1. 创建一个空的点云对象(彩色点云) pcl::PointCloud<pcl::PointXYZRGB>::Ptr point_cloud_ptr(new pcl::PointCloud<pcl::PointXYZRGB>()); // 2. 配置视差图转换器 pcl::DisparityMapConverter<pcl::PointXYZRGB> dmap_conv; dmap_conv.setBaseline(baseline); // 基线长度 (单位焦距一致,通常米) dmap_conv.setFocalLength(fx); // 通常设定为fx (假设fy=fx或正方形像素) dmap_conv.setImageCenterX(cx); dmap_conv.setImageCenterY(cy); dmap_conv.setDisparityThresholdMin(min_disparity); // 可选:最小有效视差 dmap_conv.setDisparityThresholdMax(max_disparity); // 可选:最大有效视差 dmap_conv.setMedianFilterSize(median_kernel_size); // 可选:中值滤波大小 (过滤噪声) // 3. 获取左图颜色信息 (用于给点云赋色,如果是彩色图) cv::Mat left_image_bgr; // 你的左图(用于颜色) // 将OpenCV的BGR左图转换为RGB格式 (因为PCL通常使用RGB) cv::Mat left_image_rgb; cv::cvtColor(left_image_bgr, left_image_rgb, cv::COLOR_BGR2RGB); dmap_conv.setImage(left_image_rgb); // 提供左图给转换器赋色 // 4. 设置视差图数据 (核心!) // 将OpenCV视差图数据放入pcl::DisparityImage结构中 pcl::DisparityImage disparity_image; disparity_image.width = disparity_map.cols; disparity_image.height = disparity_map.rows; disparity_image.resize(disparity_image.width * disparity_image.height); // 将视差值填充到 disparity_image 的 data 中 // 注意数据类型转换:OpenCV的视差值通常有缩放(例如16倍放大以存储整数)和偏移(减去min_disparity) // 假设disparity_map是CV_16S类型,包含放大16倍后的真实视差值(除以16.0得到真实视差) // 并且视差值已经是正值(实际值 = (disp + minDisp) / factor) const float scale_factor = 16.0f; // 对应StereoSGBM::DISP_SCALE默认值 const int min_disp = ...; // 你SGM/SGBM算法设置的最小视差 for (int y = 0; y < disparity_map.rows; ++y) { for (int x = 0; x < disparity_map.cols; ++x) { int idx = y * disparity_map.cols + x; // 获取OpenCV存储的视差值 short disp_val = disparity_map.at<short>(y, x); // 转换为实际视差值 (具体转换取决于你的算法设置) // 常见转换:真实视差 = (disp_val / scale_factor) + min_disp float real_disp = static_cast<float>(disp_val) / scale_factor; // + min_disp? 需确认算法配置 // 填充到PCL数据结构 disparity_image.data[idx] = real_disp; } } // 设置转换器的视差图 (这是核心数据源) dmap_conv.setDisparityMap(disparity_image); // 5. 执行转换:将视差图转换为点云 dmap_conv.convert(*point_cloud_ptr); // 6. (可选)点云后处理 - PCL核心功能 // - 滤波器(例如:统计异常值去除 `pcl::StatisticalOutlierRemoval`) // - 体素网格降采样 (`pcl::VoxelGrid`) // - 配准 (如果需要多个视角融合,使用 `pcl::IterativeClosestPoint`) // - 表面重建 (例如:泊松重建 `pcl::Poisson`) // 7. 保存点云 pcl::io::savePCDFileBinary("output_pointcloud.pcd", *point_cloud_ptr); ``` 2. **`pcl::StereoMatching` 类(较基础):** PCL确实在`pcl::stereo`命名空间下提供了`StereoMatching`基类及其子类(如`pcl::AdaptiveCostSOStereoMatching`)。但这些实现往往: * 功能较基础,性能和精度可能不如主流的OpenCV实现。 * 缺乏文档和活跃维护。 * 主要作为研究或特定场景的参考实现。 **不推荐**作为生产环境的首选立体匹配算法库。OpenCV的`StereoSGBM`或`StereoSGM`是更成熟的选择。 --- 📝 **总结建议解决方案:** 1. **核心匹配用OpenCV:** 将 **OpenCV** 作为**立体匹配算法(尤其是SGM)** 的实现库。使用 `cv::StereoSGBM`(较通用)或 `cv::StereoSGM`(需OpenCV 4.5.1+)计算高质量的视差图。 2. **点云生成处理用PCL:** 利用 **PCL** 的 **`pcl::DisparityMapConverter`** 类(或者手动编写坐标转换代码)将OpenCV计算得到的**视差图转换为点云**。然后利用PCL强大的**点云处理库**(滤波、配准、表面重建)进行后续3D重建和分析工作。 3. **示例流程代码:** 上面提供的C++代码示例展示了如何结合OpenCV(获取视差图)和PCL(转换点云并进行初步后处理)工作的基本框架。你需要填充OpenCV计算视差图的部分以及相机标定参数部分。 💡 **学习资源:** * **OpenCV 立体匹配文档:** * [cv::StereoSGBM Class Reference](https://docs.opencv.org/master/d2/d85/classcv_1_1StereoSGBM.html) * [cv::stereo::StereoBinarySGM Class Reference](https://docs.opencv.org/master/d9/d44/classcv_1_1stereo_1_1StereoBinarySGM.html) (通常比StereoSGBM更快) * **PCL 点云生成处理文档:** * [pcl::DisparityMapConverter Class Template Reference](https://pointclouds.org/documentation/classpcl_1_1_disparity_map_converter.html) * [pcl::PointCloud Class Template Reference](https://pointclouds.org/documentation/classpcl_1_1_point_cloud.html) * [Point Cloud Library Tutorials](https://pcl.readthedocs.io/projects/tutorials/en/master/) * **实际项目参考:** 可以查看一些整合了OpenCV (SGM) + PCL (点云处理)的开源项目,例如一些SLAM (如ORB-SLAM3, VINS-Mono等通常包含立体版本的后端点云生成环节) 或3D重建项目[^1][^2]。 🔍 **相关问题:** 1. **如何配置OpenCV中的StereoSGBM或StereoSGM算法以获得最佳视差图?** (涉及参数调整如P1, P2, minDisparity, numDisparities, uniquenessRatio, speckleWindowSize, speckleRange等) 2. **在使用PCL将视差图转换为点云时,有哪些提升点云质量的有效后处理方法?** (例如滤波、噪声去除、孔洞填补) 3. **除了SGM算法,OpenCV还提供哪些其他的立体匹配算法?它们在PCL工作流中如何应用?** 4. **如何对使用OpenCV+PCL生成的3D点云进行配准和融合(例如用ICP算法)?** [^4] 5. **在PCL中如何进行点云表面重建(如泊松重建)以实现平滑的3D模型输出?** [^1]: 如引用中提到的类似“beaupreda/semi-global-matching”项目展示了Python层面的SGM实现,其原理可参考;OpenCV则是更工业级的实现库。 [^2]: PCL在立体匹配流程中的主要作用是利用其他库(如OpenCV)生成的视差图进行点云计算和后期处理,而非直接实现最匹配本身。 [^4]: 如引用中提到的点云配准算法(ICP, NDT)正是PCL用于多视角点云融合的关键工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值