1、OpenMVS主要需要ColMap文件OpenMVS处理ColMap主要依赖下面3个文件和图像cameras.bin images.bin points3D.bin需要注意的是Colmap在用mapper指令稀疏重建重建的时候会生成一个sparse文件夹在用image_undistorter命令进行畸变校正的时候还会在dense目录下再生成一个sparse文件夹和畸变校正图像OpenMVS依赖的文件是dense目录下进行畸变校正后的图像和3个文件内容存放在下图中红框文件中这两组数据有什么区别呢下面说明一下绿色框中存放的images是采集的原始图像没有任何修改的图像。sparse中cameras.bin存放的是ColMap重建时设置的相机模型内参数比如OPENCV模型参数images.bin中存放的是2D特征点信息这些特征点坐标对应的是原图中的特征点坐标。dense目录下sparse的cameras.bin只可能存放PINHOLE相机模型参数这也是openMVS要求的模型格式images.bin中存放的2D特征点信息也是畸变校正后的坐标对应的是dense目录下image文件夹中畸变校正后图像中的坐标。这中个sparse目录下points3D.bin的坐标都是一样的。如果错误的将畸变校正前的图像和sparse数据传给openMVS比如ColMap重建时相机模型选择的是OPENCV就会报下面错误所以正确的做法是将dense目录下的图像和sparse信息传给openMVS:如果觉得sparse下只有.bin文件不方便分析可以用下面命令将.bin文件转换成.txt文件bin文件是二进制文件比存成txt文件会小大半。colmap model_converter--input_path/root/code/colmap-test/sparse/0--output_path/root/code/colmap-test/sparse/0--output_type TXT依次介绍上面需要的3个文件1.1 cameras.txt1.1.1 原始相机内参数这个相机内参数是mapper或者 pose_prior_mapper 执行完成后生成的直接与重建时选择的相机模型有关系。每个文件头部都有对应的说明详细解释一下CAMERA_ID1MODELOPENCV# 可以参考win下GUI版本里面包含多个相机模型支持的内参数数量也不相同结合自身情况选用WIDTH4032# 图像宽度HEIGHT3024# 图像高度PARAMS2991.4666977807562994.4631536536822201615120.078308503282122063-0.070017441516631737-0.000662990791039660770.00041831172793063476# 相机内参数分别对应 fx, fy, cx, cy, k1, k2, p1, p2OPENCV相机模型对应的8个内参数含义参数值含义fx2991.466697780756x轴焦距像素fy2994.4631536536822y轴焦距像素cx2016.0主点x坐标像素cy1512.0主点y坐标像素k10.078308503282122063径向畸变系数1k2-0.070017441516631737径向畸变系数2p1-0.0006629907903966077切向畸变系数1p20.00041831172793063476切向畸变系数21.1.2 畸变校正后相机内参数执行完image_undistorter命令后还会在dense目录下生成一个畸变校正后的相机内参数这个相机模型一定时PINHOLE类型对应的是畸变校正后的图像也是提供给openMVS的文件之一。各参数解释CAMERA_ID‌1‌MODEL‌PINHOLE‌WIDTH‌3940像素‌HEIGHT‌2952像素‌PARAMS[]‌‌f_x‌2991.47x方向焦距‌f_y‌2994.46y方向焦距‌c_x‌1970x方向主点坐标‌c_y‌1476y方向主点坐标1.2 images.txt1.2.1 对应于原始图像的2D特征点信息第一行为图像位置姿态信息大部分任务都是用同一个相机拍摄的所以ID一般都是1这里每幅图像位姿描述用的是四元数而不是欧拉角主要原因是欧拉角并不唯一在某些情况下存在死锁问题但是四元数是唯一的。字段值含义IMAGE_ID1图像ID从1开始QW0.00392278旋转四元数的实部QX0.83132478旋转四元数的x分量QY0.55576233旋转四元数的y分量QZ0.00345873旋转四元数的z分量TX-0.71253312相机位置X坐标米TY0.10803531相机位置Y坐标米TZ74.15576332相机位置Z坐标米CAMERA_ID1使用的相机模型ID对应cameras.txt中的IDNAMEDJI_20250721145626_0001_V.jpeg图像文件名第一行后面紧接着就是2D特征点信息重复(X, Y, POINT3D_ID)格式然后接着就是第2幅图像的位置姿态信息知道所有参与稀疏重建图像的位置姿态和2D特征点信息后存储完。有多少组图像就有多少组重复的结构信息。第一副图像中存储大量重复的0.984375 0.984375 -1显然都是些异常数据都可以删除。后面正常一些的数据如下图所示从上面数据中摘除一部分用于解释说明994.9026489257812529.519790649414062186841743.057617187532.919471740722656191021835.396606445312532.263530731201172198901850.887329101562532.366558074951172188161850.887329101562532.36655807495117218817其中994.90264892578125 29.519790649414062 18684表示3D点云中ID为18684的3D对应第1幅图像中特征点的像素坐标为(994.90264892578125 ,29.519790649414062)。这个文件主要说明了所有3D点对应于每幅图像中特征点的坐标。1.2.2 畸变校正后的2D特征点信息数据结构都是一样的但是特征点坐标会结合畸变参数做微调内容如下1.3 points3D.txt3D特征点是始终不变的只有一份。字段分解字段值含义POINT3D_ID13D点的唯一标识符X82.5805767222011583D点的X坐标米Y-10.9987411630723673D点的Y坐标米Z19.7100803008603693D点的Z坐标米R241点的红色分量0-255G175点的绿色分量0-255B135点的蓝色分量0-255ERROR0.66255870995074839重投影误差像素TRACK20 30 22 903 21 761 23 836 24 14829观测该点的图像列表其中Track格式如下格式:IMAGE_ID POINT2D_IDX IMAGE_ID POINT2D_IDX...示例:20302290321761238362414829其中20 30表示第20幅图像索引从1开始第30个特征点此时的3D点ID是1。验证可以看到images.txt中ID为20的图像中第31个特征点对应的3D点ID正好是1和points3D.txt中的POINT2D_IDX正好可以对应上。所以这个2D点索引30的起始索引是0。通过上面所有信息可知points3D.txt和images.txt的内容是有密切关联关系的images.txt中每个特征点顺序都是隐含索引信息的所以不能任意删除和调整顺序。思考如果只删除points3D.txt中的点images.txt中残留了已经删除的3D点ID会有影响吗2、手动构建openMVS输入存在的问题2.1 openMVS输入最小单元输入所需文件结构如下图所示sparse中的3个文件是txt和bin格式都可以所需命令/root/code/openMVS-2.3.0/make/bin/InterfaceCOLMAP \-i/root/code/colmap-test/sh24/dense \-o scene.mvs \--image-folder/root/code/colmap-test/sh24/dense/images \--working-folder.2.2 修正3D点云影响范围如果要对points3D.txt中的3D点云做修改搞清楚需要修改哪些内容。只修改points3D.txt文件根据x,y组成的polygen剔除polygen之外的点云发现之前执行失败的DensifyPointCloud这次执行成功了说明裁剪后有正面效果。但是发现另外一个问题稠密点云中那些之前在稀疏点云中被剔除的点又出现了。一开始怀疑是因为images.txt中存在的特征点信息没删除又被拿出来重建了需要将删除的3D点ID设置成-1执行这个操作后发现最终模型还是把删除的点重建出来了。最终发现是DensifyPointCloud命令导致的这个命令会通过深度图把删除的点云重建出来。rootb82aa725c09a:~/code/colmap-test/sh24/dense# /root/code/openMVS-2.3.0/make/bin/DensifyPointCloud scene.mvs17:06:47[App]OpenMVS x64 v2.3.017:06:47[App]Build date:Jan262026,10:08:4617:06:47[App]CPU:Montage Jintide(R)C5218R(80cores)17:06:47[App]RAM:251.49GB Physical Memory119.21GB Virtual Memory17:06:47[App]OS:Linux6.8.0-52-generic(x86_64)17:06:47[App]Disk:5.93TB(7.28TB)space17:06:47[App]SSEAVX compatible CPUOS detected17:06:47[App]Command line:DensifyPointCloud scene.mvs17:06:47[App]MapSMtoCoresforSM8.9isundefined;default to use64cores/SM17:06:47[App]MapSMtoCoresforSM8.9isundefined;default to use64cores/SM17:06:47[App]CUDA device0initialized:NVIDIA GeForce RTX4090(compute capability8.9;memory23.64GB)17:06:47[App]Camera model loaded:platform0;camera0;f0.759x0.760;poses2417:06:47[App]Scene loadedfrominterfaceformat(8ms):24images(24calibrated)witha total of266.21MPixels(11.09MPixels/image)14108points,0vertices,0faces17:06:47[App]The camera directions meanisunbalanced;the scene will be considered unbounded(no ROI)17:06:47[App]Point-cloud composed of14108pointswith:-visibility info(73151views-5.19views/point):0pointswith1-views(0.00%)510pointswith2views(3.61%)4805pointswith3views(34.06%)8793pointswith4views(62.33%)2min/5.18507mean(3.1186std)/21max17:06:48[App]Preparing imagesfordense reconstruction completed:24images(273ms)17:06:48[App]Selecting imagesfordense reconstruction completed:24images(24ms)Estimated depth-maps24(100%,8s182ms)Geometric-consistent estimated depth-maps24(100%,5s508ms)Geometric-consistent estimated depth-maps24(100%,5s977ms)Filtered depth-maps24(100%,2s612ms)Fused depth-maps24(100%,24s805ms)17:07:35[App]Depth-maps fusedandfiltered:24depth-maps,50782090depths,6845715points(13%%)(24s937ms)17:07:35[App]Densifying point-cloud completed:6845715points(48s42ms)17:07:38[App]Point-cloudscene_dense.plysaved:6845715points(2s429ms)17:07:41[App]Scene saved to interfaceformat(220ms):24images(24calibrated)14108points,0vertices,0faces17:07:42[App]MEMORYINFO:{17:07:42[App]VmPeak:27680932kB17:07:42[App]VmSize:21256148kB17:07:42[App]}ENDINFO-rw-r--r--1root root 894K Jan2816:53scene.mvs-rw-r--r--1root root 906K Jan2817:07scene_dense.mvs-rw-------1root root 452M Jan2817:07scene_dense.ply-rw-------1root root2.5M Jan2817:02scene_dense_mesh_refine.ply-rw-------1root root5.7M Jan2817:03scene_dense_mesh_refine_texture.ply-rw-r--r--1root root 64M Jan2817:03scene_dense_mesh_refine_texture0.png-rw-------1root root 266K Jan2816:54scene_mesh.ply因此通过下面指令即使手动删除点云最终还是会补全ROI外的模型/root/code/openMVS-2.3.0/make/bin/InterfaceCOLMAP-i/root/code/colmap-test/sh24/dense-o scene.mvs--image-folder/root/code/colmap-test/sh24/dense/images--working-folder./root/code/openMVS-2.3.0/make/bin/DensifyPointCloud scene.mvs/root/code/openMVS-2.3.0/make/bin/ReconstructMesh scene_dense.mvs-o scene_mesh.mvs/root/code/openMVS-2.3.0/make/bin/RefineMesh scene.mvs-m scene_mesh.ply-o scene_dense_mesh_refine.mvs/root/code/openMVS-2.3.0/make/bin/TextureMesh scene_dense.mvs-m scene_dense_mesh_refine.ply-o scene_dense_mesh_refine_texture.mvs跳过稠密重建用下面指令可以仅生成ROI内的模型/root/code/openMVS-2.3.0/make/bin/InterfaceCOLMAP-i/root/code/colmap-test/sh24/dense-o scene.mvs--image-folder/root/code/colmap-test/sh24/dense/images--working-folder./root/code/openMVS-2.3.0/make/bin/ReconstructMesh scene.mvs-o scene_mesh.mvs/root/code/openMVS-2.3.0/make/bin/RefineMesh scene.mvs-m scene_mesh.ply-o scene_dense_mesh_refine.mvs/root/code/openMVS-2.3.0/make/bin/TextureMesh scene.mvs-m scene_dense_mesh_refine.ply-o scene_dense_mesh_refine_texture.mvs通过给原图加mask实现裁剪功能 通过images.txt和 物理区域polygeon计算每幅图像的maskcd/root/code/colmap-test/dense-323_filter/dense# 指令1/root/code/openMVS-2.3.0/make/bin/InterfaceCOLMAP \-i/root/code/colmap-test/dense-323_filter/dense \-o scene.mvs \--image-folder/root/code/colmap-test/dense-323_filter/dense/images \--working-folder.# 指令2/root/code/openMVS-2.3.0/make/bin/DensifyPointCloud scene.mvs--mask-path/root/code/colmap-test/dense-323_filter/dense/masks--ignore-mask-label0--filter-point-cloud1# 指令3/root/code/openMVS-2.3.0/make/bin/ReconstructMesh scene_dense.mvs-o scene_mesh.mvs--min-point-distance5--decimate0.5--remove-spurious10--close-holes15--smooth1--max-threads $(nproc)--process-priority-1# 指令4/root/code/openMVS-2.3.0/make/bin/TextureMesh scene_dense.mvs-m scene_mesh.ply-o scene_dense_mesh_texture.mvs3、使用export_openmvs生成的scene.mvs实现带ROI的重建基本步骤拷贝scene.mvs拷贝scene.mvs指定路径的畸变校正后图像修改DensifyPointCloud源码解决non-empty maskName问题注意export_openmvs生成的图像后缀如下对应mask命名如下/root/code/openMVS-2.3.0/make/bin/DensifyPointCloud scene.mvs--mask-path./masks-2--ignore-mask-label0--filter-point-cloud1/root/code/openMVS-2.3.0/make/bin/ReconstructMesh scene_dense.mvs-o scene_mesh.mvs--min-point-distance5--decimate0.5--remove-spurious10--close-holes15--smooth1--max-threads $(nproc)--process-priority-1/root/code/openMVS-2.3.0/make/bin/TextureMesh scene_dense.mvs-m scene_mesh.ply-o scene_dense_mesh_texture.mvs出现non-empty maskName问题的原因是scene.mvs中包含了maskName而且又找不到报错了。要么改scene.mvs生成代码要么改openMVS源码。4、效果5、补充OpenMVS提速# 这里提速的重要参数是--max-resolution深度图的分辨率对重建的速度和效果影响最大从深度图文件尺寸就可以看出来/root/code/OpenMVS230/openMVS/make/bin/DensifyPointCloud scene.mvs--filter-point-cloud1--max-resolution960# 这里提速的重要参数--decimate 0.3和--smooth 2/root/code/OpenMVS230/openMVS/make/bin//ReconstructMesh scene_dense.mvs-o scene_mesh.mvs--min-point-distance5--decimate0.3--remove-spurious5--close-holes100--smooth2--max-threads $(nproc)--process-priority-1# 这里提速的重要参数是--resolution-level1表示分辨率减半/root/code/OpenMVS230/openMVS/make/bin//TextureMesh scene_dense.mvs-m scene_mesh.ply-o scene_dense_mesh_texture.mvs--decimate0.2--max-threads $(nproc)--resolution-level1在OpenMVS阶段DensifyPointCloud一般是耗时最严重的如果用GPU速度能提升1-2倍与设备的性能挂钩。在Colmap阶段patch_match_stereo是最耗时的其次是pose_prior_mapperpatch_match_stereo要求必须有GPU所以Colmap默认安装GPU版本如果只用Colmap生成稀疏点cmake时可以选择CPU配置