Colmap的安装和使用

2025-08-28_19-16

COLMAP

COLMAP是一个开源三维重建工具

安装

Windows

从 GitHub发布页 GitHub Releases 下载预编译的二进制, 区分带CUDA和不带CUDA的版本.

Ubuntu

在 Ubuntu 22.04 下可以通过apt install colmap安装, 但是这样安装的是不带CUDA支持的版本

支持CUDA的版本需要通过编译安装, 可以参考的安装说明

注意不要被 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 )

  1. 安装依赖
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 运动恢复结构的目的是求解相机参数, 流程为

  1. Detect 2D features in images
  2. Match 2D features between images
  3. Generate 2D tracks from matches
  4. SFM model from 2D tracks
  5. 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. 增量注册

新图像注册

  1. 通过 PnP(Perspective-n-Point) 算法估计新图像的相机位姿(利用已有三维点与当前图像的2D匹配)
  2. 三角化新增的三维点.

全局优化(Bundle Adjustment, BA), 使用非线性优化(如Levenberg-Marquardt算法)同时优化所有相机参数和三维点, 最小化重投影误差(Reprojection Error)

\[ \min \sum \| \text{观测点} * \text{投影(3D点→2D图像)} \|^2 \]

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的菜单设计比较令人费解, 操作步骤是

  1. File -> Open Project, 选择 distorted/sparse/0/project.ini
    project.ini 里面有结果数据集 database_path, image_path 对应的路径
  2. 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, 深度]

posted on 2025-04-07 07:55  Milton  阅读(2798)  评论(0)    收藏  举报

导航