Colmap的安装和使用

COLMAP
COLMAP是一个开源三维重建工具
安装
Windows
从 GitHub发布页 GitHub Releases 下载预编译的二进制, 区分带CUDA和不带CUDA的版本.
Ubuntu
在 Ubuntu 22.04 下可以通过apt install colmap安装, 但是这样安装的是不带CUDA支持的版本
支持CUDA的版本需要通过编译安装, 可以参考的安装说明
- https://github.com/colmap/colmap/issues/2366
- https://github.com/dberga/nerfstudio/blob/main/INSTALL.md
注意不要被 Conda 的环境影响
Make sure you configure and compile from a consistent dev environment. It seems you are using anaconda. You probably want to start from a clean build folder and make sure you are not in a virtual anaconda environment.
编译步骤 (参考 https://github.com/dberga/nerfstudio/blob/main/INSTALL.md )
- 安装依赖
sudo apt-get install \
git \
cmake \
ninja-build \
build-essential \
libboost-program-options-dev \
libboost-filesystem-dev \
libboost-graph-dev \
libboost-system-dev \
libeigen3-dev \
libflann-dev \
libfreeimage-dev \
libmetis-dev \
libgoogle-glog-dev \
libgtest-dev \
libsqlite3-dev \
libglew-dev \
qtbase5-dev \
libqt5opengl5-dev \
libcgal-dev \
libceres-dev
导出仓库
git clone https://github.com/colmap/colmap.git
编译, 注意CMAKE_CUDA_ARCHITECTURES代表的是显卡硬件架构编号, rtx2080ti 对应75, rtx4060ti 对应89. 完整的CUDA硬件架构对应关系, 可以查看这两个页面 cuda-gpus, cuda-legacy-gpus
cd colmap
mkdir build
cd build
cmake .. -GNinja -DCMAKE_CUDA_ARCHITECTURES=75
sudo chown -R $(whoami) .
ninja -j1
sudo ninja install
使用
稀疏重建(Sparse Reconstruction)
稀疏重建(Sparse Reconstruction)流程通过从多张二维图像中恢复相机参数和稀疏三维点云, 是三维重建的核心步骤
- 输入: 一组多视角拍摄的二维图像.
- 输出
- 相机参数(内参、外参): 每张图像的拍摄位置, 朝向和焦距
- 稀疏点云: 场景中特征点(稀疏特征点)的三维坐标
COLMAP的稀疏重建流程分为
- Images
- Correspondence Search
- 特征提取 Feature Extraction
- 特征匹配 Matching
- Geometric Verification
- 增量式运动恢复结构 Incremental Structure-from-Motion, SFM (Loop)
- Image Registration
- Triangulation
- Bundle Adjustment
- Reconstruction
相机模型
文档: https://colmap.github.io/cameras.html
COLMAP 支持的相机模型有 PINHOLE系列, RADIAL系列, FISHEYE系列, OPENCV系列. 我们在使用选择合适的相机模型以获得最好的效果. 如果不清楚相机参数, 最好使用带畸变系数的模型例如默认的 SIMPLE_RAIDIAL. 如果已知相机没有畸变或畸变很小, 可以使用 SIMPLE_PINHOLE.
SFM (Structure from Motion) 运动恢复结构
SMF 运动恢复结构的目的是求解相机参数, 流程为
- Detect 2D features in images
- Match 2D features between images
- Generate 2D tracks from matches
- SFM model from 2D tracks
- SFM model refinement using bundle adjustment
将所有输入图片放到一个文件夹下, 按如下步骤依次执行
图像特征提取 Feature Extraction
从每张图像中提取可重复识别的局部特征点, 默认使用 SIFT(Scale-Invariant Feature Transform), 也可选其他特征(如SURF、ORB), 检测图像中的关键点(如角点、边缘), 为每个关键点计算出 Descriptor, 即一个特征向量(128维 for SIFT), 输出每张图像的特征点位置和 Descriptor, 存储为.bin或.h5文件
相机内参已知时, 可以直接通过命令行参数 ImageReader.camera_params 传给 COLMAP
相机内参已知
colmap feature_extractor \
--database_path ./database.db \
--image_path images \
--ImageReader.camera_model SIMPLE_PINHOLE \
--ImageReader.camera_params "1813.3334,1920,1080" \
--SiftExtraction.max_image_size 3840
其中
- database_path 设置工程数据文件的保存路径
- image_path 设置输入图像所在文件夹路径
- camera_model 设置相机模型
- camera_params 为 std::string 类型, 不同的模型有对应的表示方式. 参数及含义参考上面表格中的各种相机模型
- max_image_size 设置为大于图像最大边所对应的分辨率的值
相机内参未知
colmap feature_extractor \
--database_path ./database.db \
--image_path images \
--ImageReader.camera_model SIMPLE_PINHOLE \
--SiftExtraction.max_image_size 3840
图像特征匹配 Feature Matching
目标是找到不同图像中同一物理点的对应关系, 方式有
- 暴力匹配(Exhaustive Matching): 两两匹配所有图像, 适合少量图像.
- 词汇树匹配(VocabTree Matching): 基于图像相似性快速筛选候选匹配(默认).
- 空间匹配(Spatial Matching): 利用拍摄位置先验(如无人机序列).
colmap exhaustive_matcher --database_path $DATASET_PATH/database.db
- database_path 设置为特征点检测时工程数据文件保存的路径
增量式运动恢复结构 Incremental SFM
通过逐步添加图像, 求解并优化相机位姿和三维点位置
1. 初始化
- 选择一对初始图像(需有足够共视区域且匹配可靠)
- 计算基础矩阵(Fundamental Matrix), 恢复两图像的相对位姿
- 三角化生成初始三维点云
2. 增量注册
新图像注册
- 通过 PnP(Perspective-n-Point) 算法估计新图像的相机位姿(利用已有三维点与当前图像的2D匹配)
- 三角化新增的三维点.
全局优化(Bundle Adjustment, BA), 使用非线性优化(如Levenberg-Marquardt算法)同时优化所有相机参数和三维点, 最小化重投影误差(Reprojection Error)
3. 冗余过滤
剔除异常点(重投影误差过大)和 退化视图(如纯旋转拍摄的图像)
4. 命令
mkdir $DATASET_PATH/sparse
colmap mapper \
--database_path $DATASET_PATH/database.db \
--image_path $DATASET_PATH/images \
--output_path $DATASET_PATH/sparse \
--Mapper.ba_refine_principal_point true
输出结果
稀疏重建完成后, model 默认会被导出到 bin 文件中, 因为这样比较紧凑, 节省空间, 在$SPARSE_OUTPUT目录中生成以下文件
cameras.bin: 相机内参(焦距、畸变系数等).images.bin: 每张图像的外参(旋转矩阵、平移向量).points3D.bin: 稀疏三维点云(坐标、颜色、关联的图像特征).
可以使用 COLMAP 的模型转换功能将其转换成 txt 文件. 注意下面的指令中 input_path 和 output_path 是文件所在文件夹的路径, 而不是单个文件路径
colmap model_converter \
--input_path $DATASET_PATH/sparse/0 \
--output_path $DATASET_PATH/sparse \
--output_type TXT
相机内参 cameras.txt 格式如下
# Camera list with one line of data per camera:
# CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]
# Number of cameras: 3
1 SIMPLE_PINHOLE 3072 2304 2559.81 1536 1152
2 PINHOLE 3072 2304 2560.56 2560.56 1536 1152
3 SIMPLE_RADIAL 3072 2304 2559.69 1536 1152 -0.0218531
相机外参, 包含旋转和平移, 以及每张图片中特征点在图像中的二维坐标及其对应的三维稀疏点索引images.txt 格式如下, 注意这里的旋转保存为单位四元数形式, 与 Eigen::Quaterniond 格式相同
# Image list with two lines of data per image:
# IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME
# POINTS2D[] as (X, Y, POINT3D_ID)
# Number of images: 2, mean observations per image: 2
1 0.851773 0.0165051 0.503764 -0.142941 -0.737434 1.02973 3.74354 1 P1180141.JPG
2362.39 248.498 58396 1784.7 268.254 59027 1784.7 268.254 -1
2 0.851773 0.0165051 0.503764 -0.142941 -0.737434 1.02973 3.74354 1 P1180142.JPG
1190.83 663.957 23056 1258.77 640.354 59070
稀疏三维点云中三维空间点的信息 points3D.txt 格式如下
# 3D point list with one line of data per point:
# POINT3D_ID, X, Y, Z, R, G, B, ERROR, TRACK[] as (IMAGE_ID, POINT2D_IDX)
# Number of points: 3, mean track length: 3.3334
63390 1.67241 0.292931 0.609726 115 121 122 1.33927 16 6542 15 7345 6 6714 14 7227
63376 2.01848 0.108877 -0.0260841 102 209 250 1.73449 16 6519 15 7322 14 7212 8 3991
63371 1.71102 0.28566 0.53475 245 251 249 0.612829 118 4140 117 4473
如果需要进一步 rectify, 可以把参数输入到 OpenCV 的 stereoRectify() 函数中, 之后 initUndistortRectifyMap(), 最后使用 remap() 函数进行重映射 从而得到矫正的结果.
查看 3D Gaussian Splatting 的数据集
在gaussian-splatting中convert.py会使用colmap生成稀疏点云, 结果与输入的图片存储在同一个大目录下(原始输入图片在input子目录), 可以通过colmap打开数据集查看结果. colmap的菜单设计比较令人费解, 操作步骤是
- File -> Open Project, 选择 distorted/sparse/0/project.ini
project.ini 里面有结果数据集 database_path, image_path 对应的路径 - Import Model
弹出窗口会显示 cameras.bin, frames.bin, images.bin, points3D.bin 这些文件所在的目录, 直接点Open
附: 相关知识
三角化(Triangulation)生成初始三维点云
三角化是 SFM 的核心步骤, 它通过多视角图像中的匹配点对, 计算出对应三维空间点的坐标
三角化的基本思想
输入
- 至少两幅图像中 同一物理点 的二维观测(匹配点对).
- 两幅图像的相机投影矩阵(已知相机内参和外参).
输出
- 该匹配点对对应的 三维空间点坐标(X, Y, Z).
通过两条来自不同相机的 反向投影射线 (即从相机光心出发穿过图像点的直线), 找到它们在三维空间中的 交点 (由于噪声和误差, 实际需用最小二乘法逼近).
代码示例
使用 OpenCV 实现
import numpy as np
import cv2
def triangulate_points(p1, p2, P1, P2):
"""
三角化匹配点对
:param p1: 图像1中的点(Nx2数组)
:param p2: 图像2中的点(Nx2数组)
:param P1: 相机1的投影矩阵(3x4)
:param P2: 相机2的投影矩阵(3x4)
:return: 三维点(Nx3数组)
"""
p1_hom = cv2.convertPointsToHomogeneous(p1)[:, 0, :] # 转为齐次坐标
p2_hom = cv2.convertPointsToHomogeneous(p2)[:, 0, :]
points_4d = cv2.triangulatePoints(P1, P2, p1_hom.T, p2_hom.T)
points_3d = cv2.convertPointsFromHomogeneous(points_4d.T)[:, 0, :]
return points_3d
# 示例:假设已知相机投影矩阵和匹配点
P1 = np.array([[1000, 0, 320, 0], [0, 1000, 240, 0], [0, 0, 1, 0]]) # 相机1(世界坐标系)
P2 = np.array([[1000, 0, 320, -100], [0, 1000, 240, 0], [0, 0, 1, 0]]) # 相机2(X方向平移)
p1 = np.array([[320, 240]]) # 图像1中的点(主点)
p2 = np.array([[320, 240]]) # 图像2中的相同点
points_3d = triangulate_points(p1, p2, P1, P2)
print("三维点坐标:", points_3d) # 预期输出接近 [0, 0, 深度]
在 Ubuntu 22.04 下可以通过`apt install colmap`安装, 但是这样安装的是不带CUDA支持的版本, 支持CUDA的版本需要通过编译安装, 可以参考的安装说明
浙公网安备 33010602011771号