数据集获得sparse点云流程

参考文献

官方教程Reconstruct sparse/dense model from known camera poses

命令行实现colmap重建教程

一个博客,这个详细一些

一个CSDN教程

数据集结果

数据集起始文件结果如下,全部按照MVSNet的格式进行整理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|-DTU/TangksAndTemples/ETH
|-scan1/Barn/Pipes
|-cams_1/Cameras/cams
|-000000000_cam.txt
|-000000001_cam.txt
|-images/Rectified
|-000000000.jpg
|-000000001.jpg
|-pair.txt
|-scan2/Horse/Pipes
|-cams_1/Cameras
|-000000000_cam.txt
|-000000001_cam.txt
|-images/Rectified
|-000000000.jpg
|-000000001.jpg
|-pair.txt

然后我们需要给每个场景进行带有内参和外参的colmap重建,需要整理数据集为

这里的points3D中是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|-DTU/TangksAndTemples/ETH
|-scan1/Barn/Pipes
|-cams_1/Cameras/cams
|-000000000_cam.txt
|-000000001_cam.txt
|-images/Rectified
|-000000000.jpg
|-000000001.jpg
|-pair.txt
|-sparse
|-cameras.txt
|-images.txt
|-points3D.txt
|-cameras.bin
|-images.bin
|-points3D.bin
|-database.db
|-scan2/Horse/Pipes
|-cams_1/Cameras
|-000000000_cam.txt
|-000000001_cam.txt
|-images/Rectified
|-000000000.jpg
|-000000001.jpg
|-pair.txt
|-sparse
|-cameras.txt
|-images.txt
|-points3D.txt
|-cameras.bin
|-images.bin
|-points3D.bin
|-database.db

这里的points3D.txt是3D点在世界坐标系的位置

1
2
3
4
5
6
7
# 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: 1036, mean track length: 3.8918918918918921
2 -1.3957412836335021 1.8049754607316797 4.9114450798390585 24 22 22 0.72640773112634027 11 121 10 221 9 1613 8 245 1 2510 6 1423
3 -1.4186712335114928 1.8120053633058233 4.9084050784748019 23 23 21 0.19545865106993152 11 124 10 226 9 382 5 575 4 780 8 247 15 131
4 -1.2162532145741844 2.0057585956697221 4.9572628838538826 42 35 35 0.47492741304268571 11 157 10 250 15 157
5 -1.8061267272971728 2.0678045789053181 5.0269647802379271 43 37 36 0.21593440587055518 11 167 10 955 9 560 15 180

这里的cameras.txt是每个相机的参数

1
2
3
4
5
6
7
8
# Camera list with one line of data per camera:
# CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]
# Number of cameras: 4
1 PINHOLE 1280 720 771.904 771.896 639.993 360.001
2 PINHOLE 640 512 771.904 771.896 639.993 360.001
3 PINHOLE 640 512 771.904 771.896 639.993 360.001
4 PINHOLE 640 512 771.904 771.896 639.993 360.001

这里的images.txt是每个图像的外参数,然后每个图像提取出来的特征点位置,这里的point3D_ID如果是-1,就是没有匹配上的点

1
2
3
4
5
6
# 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: 15, mean observations per image: 268.80000000000001
1 0.82562511718783926 0.3186731052518712 -0.29317321155800641 -0.36171824101427485 3.5578020730366213 -0.1387624712454856 2.5706829819425114 1 rect_001_1_r5000.png
428.02169799804688 1.4250074625015259 -1 76.619407653808594 2.4704034328460693 -1 227.20037841796875 2.4733092784881592 -1 534.3265380859375 2.5114526748657227 -1 这里太长了不复制了

创建流程(DTU)

1.首先执行特征提取和特征匹配创建数据库

这一步不涉及相机位姿和相机内参,但是注意这里的相机内参是按照PINHOLE的形式

1
2
3
4
5
6
colmap feature_extractor \
--database_path ./scan1/database.db \
--image_path ./scan1/images \
--ImageReader.camera_model PINHOLE

colmap exhaustive_matcher --database_path ./scan1/database.db

注意特征提取是并行的,按照完成特征提取完成的顺序colmap对图像进行排序,比如00000048.jpg图像对应的id可能是17,然后这样她的camera_id也是17

2.获得图像和ID和camera_id的对应关系并保存到txt文件

这里修改了colmap的脚本script/python/database.py

运行的时候,需要一个输出路径

1
python database.py --database_path ../testOnlyUseColmap/database.db --output_txt ../image_map.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def export_image_map(database_path, output_txt):
conn = sqlite3.connect(database_path)
cursor = conn.cursor()
cursor.execute("SELECT image_id, camera_id, name FROM images")
rows = cursor.fetchall()
conn.close()
with open(output_txt, "w") as f:
for row in rows:
image_id, camera_id, name = row
f.write(f"{image_id} {camera_id} {name}\n")
print(f"导出完成: {output_txt}")

def main():
import argparse
import os

parser = argparse.ArgumentParser()
parser.add_argument("--database_path", type=str, default="database.db")
parser.add_argument("--output_txt", type=str, default="image_map.txt")

# Open the database.
db = COLMAPDatabase.connect(args.database_path)

# For convenience, try creating all the tables upfront.
db.create_tables()
cameras = db.get_cameras()
if cameras:
print("打印相机的列表,对应的相机参数")
print("WARNING: database already contains cameras, will not modify them.")
print("Cameras found:")
for camera_id, camera in cameras.items():
print(f" Camera ID {camera_id}: {camera}")
else:
print("数据集没有保存相机")
images = db.get_images()
if images:
print("打印图像的列表,对应的id和camera_id")
for iid, img in images.items():
print(f"Image ID {iid}: {img['name']} -> Camera {img['camera_id']}")
else:
print("数据集没有保存图像")

args = parser.parse_args()
export_image_map(args.database_path, args.output_txt)
db.close()

3.创建一个满足ID顺序的cameras.txt

利用刚才的txt对应文件,并传入保存了cam参数的文件夹,创建一个满足要求的cameras.txt

1
python creatCameraColmapOrderFromMVS.py --cams_folder cams_1 --images_folder images  --image_map image_map.txt --output_file colmapTemp/new_cameras.txt

4.将cameras.txt更新到数据库

利用刚才的cameras.txt,根据官方对cameara参数进行更新

1
python updateDatabaseCamera.py --database_path database.db --cameras_txt colmapTemp/new_cameras.txt

5.构建images.txt

利用刚才的image_map.txt,以及真实的相机参数,创建一个images.txt

这里注意DTU数据集的pose是w2c的,而colmap也是标准的w2c,所以不需要转化,另外他们的相机视野都是opencv系的

1
python createExtrinsicColmapOrderFromMVS.py --cams_folder cams_1 --image_map image_map.txt --output_file colmapTemp/images.txt

6.执行三角测量获得稀疏点云

首先需要注意把创建好的cameras.txt和images.txt到同一个目录下,并在该目录下创建一个points3D.txt,这里保存的文件夹是scan1/colmapTemp

然后需要创建一个保存文件夹比如sparse

1
colmap point_triangulator --database_path scan1/database.db --image_path scan1/images  --input_path scan1/colmapTemp  --output_path scan1/sparse

7.转化稀疏点云从bin到txt

1
2
3
colmap model_converter --input_path scan1/sparse \
--output_path scan1/sparse \
--output_type TXT

批量处理

批量处理DTU数据集,DTU数据集下有多个文件夹,每个文件夹是一个场景,每个场景有一个图像文件夹叫做images或者Rectified,里面都是000000000.jpg这样的文件。然后有一个相机参数文件夹,叫做cams_1或者Cameras或者cams,里面都是000000000_cam.txt这样的文件。然后你需写一个脚本传入DTU的主文件夹,列出其中所有场景文件夹并检查每个文件夹是否正确的保存了这些文件。

然后在每个文件夹下执行,比如scan1目录下

colmap feature_extractor --database_path ./scan1/fakesparse/database.db --image_path ./scan1/images --ImageReader.camera_model PINHOLE

colmap exhaustive_matcher --database_path ./scan1/fakesparse/database.db

这两个命令同时也会创建一个fakesparse/database.db

然后

python database.py --database_path ./scan1/fakesparse/database.db --output_txt ./scan1/fakesparse/image_map.txt

然后

python creatCameraColmapOrderFromMVS.py --cams_folder ./scan1/fakesparse/cams_1 --images_folder ./scan1/fakesparse/images --image_map ./scan1/fakesparse/image_map.txt --output_file ./scan1/fakesparse/cameras.txt

然后

python updateDatabaseCamera.py --database_path ./scan1/fakesparse/database.db --cameras_txt ./scan1/fakesparse/cameras.txt

然后

python createExtrinsicColmapOrderFromMVS.py --cams_folder ./scan1/cams_1 --image_map ./scan1/fakesparse/image_map.txt --output_file ./scan1/fakesparse/images.txt

然后

然后创建一个points3D.txt文件

然后

colmap point_triangulator --database_path ./scan1/fakesparse/database.db --image_path ./scan1/images --input_path ./scan1/fakesparse/ --output_path ./scan1/sparse/

然后

colmap model_converter --input_path ./scan1/sparse/ --output_path ./scan1/sparse/

最后的脚本

1
python batch_dtu_colmap.py --root /path/to/DTU/ --scripts_dir ./  

其他工具

  1. 检查相机外参是否正确,可以修改里面是否为w2c还是c2w
1
python checkImagePose.py 
  1. 将points3D结果转化为ply文件然后用meshlab等可视化
1
python convertTXTPointToply.py