十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

COLMAP 三角化:2D 匹配点是怎么变成 3D 点云的?

COLMAP 三角化:2D 匹配点是怎么变成 3D 点云的? COLMAP 三角化:2D 匹配点是怎么变成 3D 点云的?【免费下载链接】colmapCOLMAP - Structure-from-Motion and Multi-View Stereo项目地址: https://gitcode.com/GitHub_Trending/co/colmap你拍了 30 张照片,跑完 SfM,点云却是空的——多半不是特征没匹配上,而是 COLMAP 三角化这一步把点全部判死刑了。这篇带你从几何直觉一路读到源码,讲清楚三角化在算什么、在哪一步被触发、哪些默认参数会让点消失,以及该往哪里调。先建立直觉:三角化到底在算什么闭上左眼、伸出右手食指,再换左眼——手指跳了一下。你刚才就在做三角化:同一个指尖在两只眼睛里落在不同位置,大脑用两条视线交叉出它的空间位置。手机 AR 把虚拟杯子钉在桌面边缘,也是同一套机制。精确一点说:两个已知位姿的相机,各提供一条从投影中心穿过 2D 特征点的视线,两条射线在空间中相交(数值上是最小二乘意义的最接近)处,就是这个 3D 点。整个几何关系只有一个硬约束:$$\min\big(\angle(\mathbf{r}_1,\mathbf{r}2)\big) \ge \theta{\min}$$两条视线之间的夹角(取锐角一侧)必须足够大。白话翻译:基线太短或两图视角差太小,射线几乎平行,交点会甩到几千米外,深度误差爆炸——这是点云消失的头号原因。在 COLMAP 里,这一步的求法叫 DLT(直接线性变换):把每个观测写成一个关于齐次坐标 3D 点的线性约束,堆成超定方程组,用 SVD 取最小奇异值对应的右奇异向量。两视图入口是TriangulatePoint,多视图入口是TriangulateMultiViewPoint,实现都在 src/colmap/geometry/triangulation.cc。打开源码:一次三角化调用经过了哪些模块别急着读实现,先跟一遍调用链,从注册一张新图这个用户动作出发:注册图像:新图加入场景,先用已有点做绝对位姿微调,这一步本身就要现场三角化一批点;触发增量三角化:位姿定了,遍历该图上还没 3D 坐标的 2D 点,顺 correspondence graph 把同一特征在其他图像里的观测找齐;进入估计器:观测装好位姿后交给 RANSAC 框架,内点集确定后做最终求解;两视图 / 多视图分支:2 个观测直接解 4×4 线性系统,≥3 个观测累加正规方程;角度 正深度校验:不合格的点直接丢,不进场景;写入场景图:点变成Track(跨图观测链),参与后续 BA。三个关键文件,各一句话:src/colmap/estimators/triangulation.cc——TriangulationEstimatorEstimateTriangulation,RANSAC 鲁棒估计与内点掩码的出口;src/colmap/sfm/incremental_triangulator.cc——决定什么时候、拿哪些观测去三角化,分新点和补全已有 track两条路;src/colmap/geometry/triangulation.cc——纯几何层,DTL 求解与夹角计算,不碰任何场景状态。分支逻辑长这样(示意,非完整实现):if (point_data.size() 2) { TriangulatePoint(pose1, pose2, pt1, pt2, xyz); // 两视图 DLT } else { TriangulateMultiViewPoint(cams, pts, xyz); // 累加正规方程 }工程细节:那些让点云消失的坑 坑一:最小三角化角度卡掉了大量点现象:重建出来的点云稀疏,像撒了一把芝麻,远处大面积空白。根因:射线夹角小的观测对,深度对角度噪声极其敏感,点算出来就是飞点。COLMAP 默认处理:注册后过滤用filter_min_tri_angle 1.5(度),初始对选择用init_min_tri_angle 16,选局部 BA 图像时用ba_local_min_tri_angle 6——同一个角度在不同阶段用不同阈值,定义见 src/colmap/sfm/incremental_mapper.h。你可以怎么调:在MAPPER段的 config 文件里,近距离小基线场景(桌面、文物)把filter_min_tri_angle降到 1,远距离大场景升到 3~5 抑制飞点;init_min_tri_angle一般别动,除非你的初始对基线天然就短。坑二:三角化点落在相机后面现象:点云边缘出现一团鬼影点,或注册反复失败。根因:射线不严格相交时,最小二乘解可能落在投影中心后方,这种点几何上无意义。COLMAP 默认处理:正深度(手性)约束是硬性检查,一行判断:return (cam_from_world.row(2) * xyz.homogeneous()) 0;你可以怎么调:这个没有开关,但它是上游姿态质量的报警器——如果大面积点被判负深度,说明位姿或内参估错了,去查 BA 残差而不是调三角化参数。坑三:错误匹配混进观测,把点带跑现象:个别 3D 点离群很远,或者某条 track 上明明有匹配却三角化失败。根因:特征匹配本身有错配,一条错误射线混入观测集,射线交叉位置就偏了。COLMAP 默认处理:EstimateTriangulation内部跑 LORANSAC,默认max_error 2°、confidence 0.9999、min_inlier_ratio 0.02、max_num_trials 10000(见 src/colmap/estimators/triangulation.h),非内点观测不进 track。你可以怎么调:纹理弱、重复纹理多的场景可以把max_error放宽到 3~4°;反过来想压脏点,把补全阶段的complete_max_reproj_error从默认 4 像素收紧到 2 像素。坑四:BA 之后观测残差超标被剪掉现象:点云整体糊,track 长度普遍偏短(大量 2 视图 track)。根因:BA 会移动 3D 点,一些观测的重投影残差随之变大,超过阈值就被从 track 里剔除,点失去支撑。COLMAP 默认处理:filter_max_reproj_error 4.0像素。你可以怎么调:想保留更多观测就调到 5~6,精度优先就收到 2~3,配合filter_min_tri_angle一起用,别只动一个。放进完整 Pipeline:三角化在哪一步被触发增量式 SfM 的时间线是这样的:特征提取 匹配,写入 database;选初始对,估计第一对相机位姿(此时用 16° 的角度阈值筛对);逐张注册新图:绝对位姿 →现场三角化建点;增量三角化器补全:新点 老 track 的新观测;局部 BA → 收敛后回到 3,直到没有可注册的图;全局 BA 剪枝收尾。和上下游的衔接各一句话:注册阶段拿位姿残差当三角化的输入(先用已有点定姿,再三角化),BA 阶段拿三角化产出的 3D 点当优化变量——BA 收敛后点动了,下一轮局部 BA 选图时还会重新算夹角。常见问题 下一步 只有一张图能三角化吗?不能。TriangulationEstimator的最小采样数是 2,少于两条射线就没有交叉,数学上无解。单目视频重建靠的是时序上的多视图,本质不变。全景相机也能走这套流程吗?能。普通版 DLT 假设观测能写进归一化平面,鱼眼/等距柱状全景做不到;COLMAP 提供了接收单位方向向量(bearing ray)的TriangulateMultiViewPoint重载和TriangulationEstimator::PointData里的cam_ray字段,全球方向都能表达。两视图三角化精度一定差吗?相对差。观测少、对位姿误差敏感,所以 COLMAP 会尽量把 track 扩到多视图;ignore_two_view_tracks选项还能在补全阶段直接放弃只有两个视图的 track,牺牲点数换质量。三角化和 BA 的区别是什么?三角化是一次线性求解,假设位姿已知,算出点;BA 是非线性优化,同时精修位姿和点,迭代收敛。前者快但听位姿的话,后者贵但互相校正——COLMAP 两个都跑,三角化负责造点,BA 负责磨点。想继续往深处走,有三个方向:稠密重建部分看 src/colmap/mvs/,了解稠密化如何接在稀疏点后面;想用脚本驱动重建,看 python/pycolmap/ 的 Python 接口;想完全控制流程,照着 python/examples/custom_incremental_pipeline.py 自己写一条 pipeline,三角化就是你在里面显式插入的一行调用。跑一遍再回头看这份调用链,你会发现点云里每一个绿色小点,都是这么一路被筛出来的。【免费下载链接】colmapCOLMAP - Structure-from-Motion and Multi-View Stereo项目地址: https://gitcode.com/GitHub_Trending/co/colmap创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表