多视角三维重建C++实战:从特征匹配到增量式重建全流程详解

📅 发布时间:2026/8/31 15:17:43
多视角三维重建C++实战:从特征匹配到增量式重建全流程详解 简介本资源是一个面向计算机视觉学习者与三维重建开发者的C实战项目聚焦多视角三维重建核心算法实现适用于机器人导航、虚拟现实、工业检测等实际场景适合具备OpenCV、PCL基础的中高级开发者深入理解三维重建全流程。压缩包共469个文件含402个hpp头文件封装核心算法模块如立体匹配、点云优化、区域生长、22个h接口定义、10个cpp实现文件及多个工程配置vcxproj/sln和可执行程序exe辅以armadillo矩阵库支持与meshlab可视化脚本整体7.32MB结构清晰、模块解耦度高。已有197人学习下载提供从相机标定、特征匹配、三维点云生成到噪声滤除与模型渲染的完整链路源码所有关键步骤均通过独立可编译模块实现便于调试、替换与二次开发。 前阵子把一个基于C实现的多视角三维重建算法项目完整跑通并调完趁着热乎劲把整个过程整理成一篇实战笔记。这里说的“三维重建”不是Unity里那种拿模型做渲染而是真正从一组不同角度拍摄的照片里通过特征匹配、相机位姿估计、三角化这些步骤把场景恢复成一个三维点云。这个项目附带的源码给了我一个很好的参照但真正跑起来后才发现算法流程的骨架人人都知道真正拉开差距的是每个环节的工程细节。这篇文章不会跟你念教科书而是围绕项目源码按实际开发顺序把环境搭建、核心模块、增量式重建流程、参数调优和踩坑记录全部过一遍。适合想从零理解多视角三维重建、同时想把C代码真正跑起来的人。1. 这个项目解决的核心问题从二维图像集合恢复三维结构1.1 多视角三维重建的完整处理链路先把这个领域里常说的“多视角三维重建”讲清楚。它做的事其实很朴素你拿着相机围着一个物体或者一片场景从不同角度拍若干张照片程序通过分析这些二维图像之间的对应关系反推出拍摄时相机在空间中的位置、姿态以及场景中每个可见点对应的三维坐标。所有这些三维点拼在一起就成了一个带真实尺度关系的稀疏点云。在我拿到的这个项目里处理链路大致是这样的输入一组图像 - 特征提取 - 特征匹配 - 几何验证 - 估计相机位姿 - 三角化出初始三维点 - 逐步注册更多图像 - 光束法平差优化 - 输出点云文件。你可以把这条路理解成在“玩拼图”每张图像是一块拼图特征点就是拼图上的图案和颜色匹配就是把相同图案对上位姿估计是算出每块拼图在桌面上的位置和朝向三角化则是把两个视角下同一个点的位置用几何方法还原成立体坐标。整个过程从两张图开始不断把新的图放进这个三维坐标体系里最后形成一张覆盖整个场景的稀疏点云。1.2 项目源码的模块划分和整体数据流这个项目拿回来后我第一件事不是急着编译而是先整体看一遍目录结构。典型的多视角重建C项目源码一般会按下面的模块划分。模块主要职责在源码里常见的文件命名数据IO读取图像、写点云文件、加载相机参数ImageReader、PlyWriter、CameraIO特征模块特征点提取和描述子计算FeatureExtractor、DescriptorMatcher几何模块基础矩阵/本质矩阵估计、位姿分解、三角化FundamentalMatrix、EssentialMatrix、Triangulation重建核心初始对选择、增量注册、点云管理、BAReconstruction、Map、Frame、BundleAdjustment工具模块日志、时间统计、命令行解析Logger、CmdParser这个软件架构基本就是完整三维重建系统COLMAP的缩小版如果你以后去看COLMAP或者OpenMVG会发现结构高度相似。理解了这个模块划分你读代码的时候就知道该把精力放在哪个文件上改功能也不会牵一发动全身。1.3 为什么说C实现是这类项目的合理选择可能有人会问Python生态里也有OpenCV和PyTorch3D为什么还要用C写这种项目我的观点是三维重建不是简单的模型调用它要处理的是海量特征点、大规模矩阵运算和反复的优化迭代C在性能和控制力上有天然优势。尤其是在BA这种针对几万甚至几十万参数做优化的环节同样的算法用C实现可能比纯Python快一个数量级。对于“优质项目实战”这个定位来说C还能让你把每一块内存分配、线程使用都看清楚学习价值高得多。2. 环境与编译拿到源码后的第一道关2.1 依赖库选型OpenCV、Eigen、Ceres的版本搭配每次拿到一个C项目我都要先看它的CMakeLists.txt因为依赖库版本不对后面会浪费大量时间。这个三维重建项目主要依赖四样东西OpenCV负责图像读写和特征提取Eigen负责矩阵运算Ceres Solver负责光束法平差这类非线性优化还有一些小工具库比如gflags和glog负责命令行参数和日志。比较稳妥的版本搭配如下依赖库推荐版本注意事项OpenCV4.5.x需要contrib模块SIFT在contrib的xfeatures2d里Eigen3.3.x或3.4.x纯头文件库安装容易Ceres Solver2.1.x对Eigen版本有要求需3.3CMake3.10以上老版本可能不支持部分语法C编译器GCC 7 / MSVC 2019建议支持C17这里要特别提醒一个坑OpenCV 4.x里SIFT和SURF并不在默认模块里而是在opencv_contrib的xfeatures2d模块中。如果你发现代码里写了cv::SIFT::create()但编译报错说找不到SIFT那大概率是OpenCV没带contrib一起装。Ubuntu下可以通过sudo apt install libopencv-contrib-dev解决Windows下则建议直接下载官方带contrib的预编译包。2.2 CMake编译步骤和最小配置如果你拿到手的源码已经带了CMakeLists.txt那标准流程就是三步cd 项目目录 mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease make -j$(nproc)如果项目里没给CMakeLists.txt自己补一份也不难核心就是把几个库的头文件和库文件路径指对cmake_minimum_required(VERSION 3.10) project(Reconstruction) set(CMAKE_CXX_STANDARD 17) find_package(OpenCV REQUIRED) find_package(Eigen3 REQUIRED) find_package(Ceres REQUIRED) add_executable(run_reconstruction src/main.cpp) target_include_directories(run_reconstruction PRIVATE ${OpenCV_INCLUDE_DIRS} ${EIGEN3_INCLUDE_DIR} ${CERES_INCLUDE_DIRS}) target_link_libraries(run_reconstruction PRIVATE ${OpenCV_LIBS} ${CERES_LIBRARIES})编译时建议直接用Release模式因为Debug模式下一旦特征点数量上到几千匹配和BA会慢到让你怀疑人生。我当时第一次跑Debug版本一个100张图的序列跑了半个多小时换成Release后直接降到几分钟。2.3 编译阶段常踩的坑OpenCV链接、Ceres依赖、C标准编译链接阶段最容易出现的问题有三类。第一类是C标准不一致。有些老项目用C11有些用C17如果代码里用了std::filesystem这类新特性而CMake里没指定C17编译就会报错。拿到项目先看一眼源码里有没有#include filesystem或者结构化绑定有就直接给C17。第二类是Ceres和Eigen版本冲突。Ceres 2.x对Eigen 3.3以下的版本不兼容而且会强制要求使用LAPACK和BLAS。如果你在Linux上编译时提示找不到SuiteSparse可以用sudo apt install libsuitesparse-dev装上。这里是Ceres的硬依赖不能跳过。第三类是链接顺序。如果CMakeLists是手写的链接OpenCV库时通常没有太大问题但Ceres库偶尔会被glog和gflags的依赖搅乱。最省事的办法是不要手动写target_link_libraries里的库顺序直接复用find_package生成的变量让CMake自己处理。3. 核心算法模块拆解特征、匹配、位姿估计、三角化3.1 特征提取与匹配SIFT/ORB的选择和误匹配过滤三维重建的第一步是让程序“看见”图像上的特征点。特征点不是随便找几个角点就行它需要在不同视角下保持稳定比如同一个桌角从正面看和从侧面看它的局部纹理结构要能被描述成相似的向量。多视角重建里用得最多的还是SIFT因为它对尺度变化、旋转和光照变化都有很强的鲁棒性。ORB速度更快但在视角变化比较大的情况下容易产生误匹配项目如果追求重建完整性SIFT更靠谱。我在这类项目里一般这样写特征提取和匹配cv::Ptrcv::Feature2D extractor cv::SIFT::create(0, 3, 0.04, 10); std::vectorcv::KeyPoint kpts1, kpts2; cv::Mat desc1, desc2; extractor-detectAndCompute(img1, cv::noArray(), kpts1, desc1); extractor-detectAndCompute(img2, cv::noArray(), kpts2, desc2); cv::BFMatcher matcher(cv::NORM_L2); std::vectorstd::vectorcv::DMatch knnMatches; matcher.knnMatch(desc1, desc2, knnMatches, 2); std::vectorcv::DMatch goodMatches; for (size_t i 0; i knnMatches.size(); i) { if (knnMatches[i][0].distance 0.75f * knnMatches[i][1].distance) { goodMatches.push_back(knnMatches[i][0]); } }这里最关键的参数是0.75也就是最近邻距离比测试。它的思路很直接对第一个图里的特征点在第二个图里找两个最相似的特征点。如果最相似的距离明显小于第二相似的距离说明这个匹配是“独一无二”的可信度高如果两个候选距离差不多那这个点很可能出现在重复纹理区域直接丢掉。这个阈值调整到0.7到0.8之间都算合理0.75是我常用的起点。3.2 相机位姿估计本质矩阵的估计与SVD分解有了匹配点接下来要恢复两张照片之间的相机运动也就是旋转矩阵R和平移向量t。这里有个二选一的判断如果相机内参已知用本质矩阵E如果内参未知只能用基础矩阵F。这个项目一般会先给一个相机内参或者提供一张标定结果文件所以我直接用本质矩阵做。OpenCV把这一步封装得很简单cv::Mat E cv::findEssentialMat(points1, points2, K, cv::RANSAC, 0.999, 1.0); cv::Mat R, t, mask; cv::recoverPose(E, points1, points2, K, R, t, mask);但如果你只是调API会错过整个算法里最有意思的部分。本质矩阵有一个重要性质它的奇异值形式必须是[σ, σ, 0]。当我们用SVD分解E时E U Σ V^T然后根据U和V的取值可以组合出四种可能的R和t其中只有一种能保证两个相机前方都能看到三维点。recoverPose内部做的就是这件事把四种组合都试一遍用三角化后的点判断正深度数量留下正确的那组。findEssentialMat里的0.999是置信度1.0是RANSAC内点距离阈值单位是像素。这个阈值不能太大不然会把匹配质量很差的点也当成内点导致E估计被污染。3.3 三角化从二维对应点到三维点知道两张照片的相机位姿后就可以把同一个三维点在两个图像上的投影做反向延长线求两条射线在空间中的交点这个过程叫三角化。由于图像噪声的存在两条射线基本不会真正相交所以实际是在找距离两条射线都最近的点。OpenCV的cv::triangulatePoints可以直接完成这一步cv::Mat P1(3, 4); cv::Mat R1 cv::Mat::eye(3, 3, CV_64F); cv::Mat t1 cv::Mat::zeros(3, 1, CV_64F); P1(cv::Rect(0, 0, 3, 3)) R1.clone(); P1(cv::Rect(3, 0, 1, 3)) t1.clone(); cv::Mat P2(3, 4); P2(cv::Rect(0, 0, 3, 3)) R; P2(cv::Rect(3, 0, 1, 3)) t; P2 K * P2; cv::Mat points4D; cv::triangulatePoints(K * P1, P2, points1.t(), points2.t(), points4D);这里要提醒一点triangulatePoints用的是齐次坐标输出也是4维齐次坐标。转成三维坐标时要记得把前三维除以第四维也就是X x / wY y / wZ z / w。我见过不少新手直接拿前三维当结果生成的点云全挤在一个平面上怎么调都不对。三角化得到的点质量参差不齐。通常还要检查两个视角之间的夹角夹角太小意味着两条射线方向几乎平行一个像素的误差会被放大成很大的位置偏移。很多实现会直接丢弃夹角小于1度的点。4. 增量式重建的工程实现从两视图扩展到多视图4.1 初始图像对的挑选策略两张图能重建出一小块点云但完整场景需要不断加入新图像。这个项目采取的是经典的增量式结构从运动恢复流程也就是先选一对图像重建出初始点云和位姿然后一张一张把剩余图像注册进来。初始图像对选得好不好直接决定后面整个重建能不能顺利展开。选配对数量最多的图像对是直觉做法但不够严谨因为有些图像对虽然匹配点很多却是在同一位置附近拍的也就是基线太短。基线短时三角化几何退化恢复出的三维点深度误差极大后面所有新图像都会基于一套扭曲的三维结构往下加最后重建结果整体变形。我处理这个问题时会先把所有图像对的匹配数量算出来按数量从多到少排个序然后从前往后找第一个本质矩阵分解后旋转角足够大的图像对旋转角在5度到30度之间比较理想。这个逻辑在源码里对应一个类似“选择初始对”的函数跑起来后你就知道这一步选错了后面全是灾难。4.2 新增图像注册PnP求解与位姿优化有了初始点云后新增一张图像不再需要和所有旧图像做双视图几何可以用更高效的PnP方案。思路是在新图像里提取特征点与已有的三维地图点建立2D-3D对应关系然后通过已知的三维点和对应的二维投影位置反算出新图像相机的位姿。只要拿到至少4组2D-3D对应点就可以用OpenCV的solvePnPstd::vectorcv::Point3f objectPoints; // 已重建的三维点 std::vectorcv::Point2f imagePoints; // 新增图像中的像素坐标 cv::Mat rvec, tvec, inliers; cv::solvePnPRansac(objectPoints, imagePoints, K, cv::noArray(), rvec, tvec, false, 100, 8.0, 0.99, inliers);false参数表示不用畸变系数这里默认图像已经做过畸变校正。RANSAC会把匹配错误的对应点作为外点剔除掉100是迭代次数8.0是重投影误差阈值。这个阈值我一般设置在4到12像素之间设置得太小会把一些噪声大的正确匹配也踢掉导致新图像被误判为“配准失败”。新图像注册进来之后会带来一批新的三维点这些点是通过新图像与已有图像之间的匹配三角化出来的。整个地图在这个阶段会快速膨胀但位置精度还很粗糙需要靠光束法平差把误差摊开。4.3 光束法平差BA全局一致性的关键光束法平差是整个重建系统里最核心也最吃计算量的环节。它的目标是让所有三维点投影到每张图像上的位置尽量靠近实际观测到的像素位置。一句话概括调整相机位姿和三维点坐标让所有重投影误差的整体平方和最小。用Ceres实现一个重投影误差项大概长这样struct ReprojectionError { ReprojectionError(double fx, double fy, double cx, double cy, double observed_x, double observed_y) : fx_(fx), fy_(fy), cx_(cx), cy_(cy), observed_x_(observed_x), observed_y_(observed_y) {} template typename T bool operator()(const T* const camera, const T* const point3d, T* residual) const { // camera 里存的是旋转向量3自由度 平移3自由度 T p[3]; ceres::AngleAxisRotatePoint(camera, point3d, p); p[0] camera[3]; p[1] camera[4]; p[2] camera[5]; T xp p[0] / p[2]; T yp p[1] / p[2]; residual[0] T(fx_) * xp T(cx_) - T(observed_x_); residual[1] T(fy_) * yp T(cy_) - T(observed_y_); return true; } double fx_, fy_, cx_, cy_, observed_x_, observed_y_; };实际项目中还有畸变参数和更多自由度但核心就是这个残差模式。BA不是只跑一次。最常用的策略是局部BA和全局BA结合每注册完一张新图像对与该图像可见的局部地图做一次优化控制误差增长每注册完10到20张图像对整个地图做一次全局BA把累积漂移摊平。这个过程会消耗大量CPU你会发现Ceres在Release和Debug下的速度差异非常明显所以跑完整数据集前一定要确认是Release构建。5. 实测运行与参数调优记录5.1 用自带数据集跑通全流程的具体步骤这个项目解压后通常会带一组示例图片一般是针对某个小物体绕一圈拍的十几张图。我建议第一次跑不要直接换自己的数据集先用自带的把流程跑通确认输出点云没有严重变形再换数据。假设项目编译出来的可执行文件叫run_reconstruction常见用法是这样./run_reconstruction \ --image_path ./data/images \ --output_path ./result.ply \ --camera_intrinsics ./data/intrinsics.txt如果项目没有提供相机内参文件有些实现会自动从EXIF信息里估计焦距并在点云输出时顺带打印出估计到的内参矩阵。打开生成的结果我一般用MeshLab或者Cloud Compare。正常结果应该能看到三维点的轮廓和相机的位置标记如果点云呈一个平面多半是初始图像对基线太短或者相机内参给错了。跑通之后再尝试用自己的图像集。拍摄时要注意让物体在画面里占足够大的面积相邻图像之间的视角变化不要太剧烈最好保证每张图和前后两张图有大量重叠区域。离得太远或者拍得太少后面配准基本会失败。5.2 对重建结果影响最大的几个参数实际调参时我反复试下来以下参数对结果影响最大参数含义推荐范围调整效果每张图最大特征数特征提取阶段保留特征点数量2000-4000太少重建不完整太多匹配耗时剧增最近邻距离比筛选匹配的Lowe阈值0.7-0.8越小越严格越大召回越多RANSAC阈值本质矩阵/基础矩阵内点误差0.5-2.0像素过小丢正确点过大多误匹配最小三角化夹角三角化时两视角夹角下限1-3度过小产生深度噪声点BA迭代次数Ceres求解器的最大迭代次数50-200次数太少优化不充分全局BA触发间隔每注册多少张图跑一次全局BA10-20太频繁耗时间太稀疏漂移变大我给一个实际经验当图像数量在30张左右时每张图保留3000个特征点、最近邻距离比设0.75、RANSAC阈值设1.0像素通常能平衡重建完整度和精度。如果场景是弱纹理的白墙或者水面建议把特征数提高到4000同时把最近邻距离比调到0.8避免匹配数量过少导致无法注册下一张图。5.3 内存管理和多线程优化思路这个项目跑大一点的数据集时最容易崩的不是算法逻辑而是内存。图像对特征匹配结果如果全部保存在内存里数据量会爆炸式增长。比如30张图每张3000个特征两两匹配产生的匹配结果条数是可观的在Debug模式下内存占用轻松超过好几GB。解决办法一般是只保留匹配数量排在前面的若干图像对比如最多保留前20对避免全图匹配矩阵吃满内存。另一个优化点是并行化。SIFT特征提取天然适合并行每个图像独立算可以用OpenMP加两行#pragma omp parallel for schedule(dynamic) for (int i 0; i numImages; i) { extractFeatures(images[i], features[i]); }但要注意OpenCV的SIFT在同一个实例上被多个线程同时调用是不安全的最好每个线程单独创建一个SIFT实例。特征匹配也类似如果用一个全局的Matcher实例做多线程匹配可能会遇到数据竞争轻则结果有偏差重则直接崩溃。点云输出的IO也值得注意。PLY文本格式可读性好但点多了之后保存很慢。建议输出二进制PLY一个几百MB的点云文件能在几秒内写完而文本格式可能要一分钟以上。这个项目源码里如果写的是std::ofstream逐个点写文本可以考虑改成二进制流写入。6. 源码阅读路线与扩展建议6.1 推荐阅读顺序从入口到核心模块很多人拿到一个C项目就先从main函数读起但三维重建这种系统直接读main很容易被一堆函数调用绕晕。我建议按“数据结构 - 主流程 - 关键算法”的顺序读。先看项目里定义的数据结构比如表示一张图像的Frame类、表示一组三维点的Map类、表示相机的Camera类。搞清楚这些数据结构里存了哪些字段为什么这么设计后面理解算法就顺了。比如Frame里除了图像路径一般还会存位姿、关键点、描述子、可见三维点索引。Map里则会存所有三维点和每个点的观测列表即哪些图像在哪个像素位置看到过它。然后看main函数或者调度的程序入口理清整个流程的调用顺序。这一步不用细抠每个实现只要把“特征提取之后接匹配匹配之后接几何验证几何验证之后接增量重建”这个链条画出来就行。最后再钻进具体算法比如本质矩阵SVD分解、PnP RANSAC、Ceres残差定义逐行理解。这样读代码你会比直接从头看到尾高效很多至少不会被某个细节卡住而丧失全局视野。6.2 可以继续扩展的方向稠密重建、网格化、纹理映射稀疏点云只是第一步如果想得到更适合展示和落地的模型后续扩展空间还很大。最自然的扩展是稠密重建。稀疏点云只保留特征点整体密度不够视觉上就是一堆零散的点。你可以接OpenMVS或者自写PatchMatch多视图立体匹配为每张图估计深度图再融合成稠密点云。这样重建出来的物体轮廓和表面细节会丰富得多。第二个方向是网格化。拿到稠密点云后用泊松重建或Delaunay三角化生成三角网格就能得到一个可以导入建模软件的三维mesh。泊松重建对点云噪声比较敏感稠密点云质量不够好的话可以先做一次统计滤波。第三个方向是纹理映射。网格重建出来后表面还没有颜色需要从原始图像中为每个三角面片挑选合适的视角把对应的图像纹理贴上去。这个方向涉及到选择最优视角、处理遮挡、颜色一致性调整是完整三维模型流程里最贴近商业应用的一环。源码会给你的框架打一个很好的底子后续往这几个方向扩展都会很顺。7. 实战中踩过的坑7.1 焦距估计与内参矩阵的初始化这个坑我印象最深。多视角三维重建在不给相机内参的情况下也可以勉强运行但结果非常不可控。内参矩阵里的fx和fy如果只是随便设个值重建出来的场景会呈曲面状弯曲一个平面墙可能变成凸面镜里的画面。如果你从EXIF里读焦距计算公式要搞清楚。很多手机和相机在EXIF里存的是35mm等效焦距而实际需要的fx是这样算的fx (等效焦距mm / 36mm) * 图像宽度像素。数字36mm是传统35mm胶片的感光宽度。如果你的照片是4000像素宽等效焦距是26mm那fx大约就是(26 / 36) * 4000 ≈ 2889。fy在像素为正方形的情况下一般等于fx主点cx和cy就取图像宽度和高度的一半。这个项目里如果没有标定文件至少要用这个公式把焦距初始化好。如果你用的是鱼眼镜头或者超广角畸变校正也不可忽略否则无法得到可靠的稀疏点云。7.2 匹配阈值和极线约束的配合特征匹配阶段我发现只靠最近邻距离比还不够。即使设了0.75在重复纹理或者低纹理场景里依然会混入不少误匹配。更可靠的做法是先用基础矩阵或本质矩阵估计的RANSAC做一轮几何过滤把那些违反极线约束的匹配点删掉。具体来说得到基础矩阵F之后一个匹配对(x1, x2)是否合理要看它到极线的距离是否在阈值范围内。这个距离叫Sampson距离公式是(x2^T F x1)^2除以两条极线系数的平方和。如果阈值设成1个像素那几乎所有正确匹配都能保留而误匹配大概率会被剔除。但这里要小心RANSAC基础矩阵估计本身就需要一个合理的初始匹配集合。如果最近邻距离比设得太严比如0.5很多正确匹配被提前删掉RANSAC反而找不到足够多的内点来支撑一个稳定的几何模型。所以我的经验是最近邻距离比稍微放宽到0.8把RANSAC阈值收紧到1.0像素整体效果更好。7.3 尺度漂移问题尺度漂移是增量式重建里非常头疼的问题。理论上三维重建的全局尺度应该一致但实际中由于每张图像都带有噪声误差会随着图像的逐步注册而累积最后可能导致场景的一端被拉伸另一端被压缩。我遇到过一次很典型的案例一个环形拍摄的物体重建结束时起点和终点本来应该重合的相机位姿出现了明显偏差。这种情况常见于初始图像对基线太小、匹配质量差、或者全局BA执行得太少。解决办法有三招第一初始对一定要选基线适中、匹配多的组合第二每注册一张图就做一次局部BA第三不要省全局BA每10到20张图执行一次。如果你的数据集很大全局BA跑得很慢可以考虑只对附近重叠区域做局部优化但一定要有定期全局优化的机制作为兜底。另外尺度漂移还会受到相机内参错误的影响。如果fx和fy设得不符合实际情况三维点深度的误差会被系统性地放大最终表现为整体模型变形。先保证内参准确再谈其他优化顺序不能反。最后说点实在的感受。跑完这个基于C的多视角三维重建项目最大的收获不是学会调用某个函数而是把整个pipeline的因果彻底理顺了。以前在教程里看到结构从运动恢复这个词总觉得是个黑盒真正动手把源码编译、跑通、调参、修bug之后才发现每一步都有明确的几何含义。这种底层逻辑的把握是只看论文和调Python接口给不了的。如果你也在研究三维重建建议拿到这份源码后别急着往上堆新功能先按上面说的思路把环境和数据流跑顺再慢慢啃核心算法。等你亲手把一个稀疏点云可视化出来的那一刻会觉得前面踩的坑都值了。本文还有配套的精品资源点击获取