0
点赞
收藏
分享

微信扫一扫

【三维重建】OpenMVS代码解析-点云稠密化(1)

搬砖的小木匠 2022-02-02 阅读 296

综述

现在是2022年的春节期间,终于有一个大片的时间进行学习和自我充电。OpenMVS是三维重建的重要和经典开源库,网上关于OpenMVS的介绍基本都是配置和使用,几乎没有逐行的代码解析,所以我打算借自学的这段时间做这件事情,当然了,限于本人能力有限,博客内容都是本人的理解,所以必然会出现对代码的错误理解,欢迎随时批评指正。OpenMVS解析这个系列博客,如有转载,请与我本人确认并注明出处。

代码地址:GitHub - cdcseacave/openMVS: open Multi-View Stereo reconstruction library

OpenMVS到底干了什么事情?

它所处的阶段是三维重建后半部分,它需要的输入是位姿,稀疏点云,它在这基础上,对点云进行稠密化,然后把点云转化为曲面,再对曲面进行优化,最后加上纹理。

工程结构

OpenMVS-master
    ->apps
    ->build
    ->docker
    ->docs
    ->libs
        -->Common
        -->IO
        -->MVS
        -->Math
        

很明显,OpenMVS的执行入口是在apps目录下,相关算法在libs目录下。在apps目录下,可以看到OpenMVS可以接收来自colmap,Mateshape,OpenMVG,VisualSFM的数据,或者是文件数据。

首先介绍的是OpenMVS的第一步:点云稠密化,他在DensifyPointCloud.cpp文件中。

1. main()

进入到DensifyPointCloud.cpp文件,看看在main()里面究竟干了那些事情。代码里面接收了一些指令参数,会根据不同的指令执行不同的过程。以下内容的具体实现会在后面的文章里介绍。

1.1 功能一:在曲面上进行点云采样的功能

    //option1:  enable uniformly samples points on a mesh 
	Scene scene(OPT::nMaxThreads);
	if (OPT::fSampleMesh != 0) {
		// sample input mesh and export the obtained point-cloud
		//load .ply of .obj pointcloud
		if (!scene.mesh.Load(MAKE_PATH_SAFE(OPT::strInputFileName))) 
			return EXIT_FAILURE;
		TD_TIMER_START();

		PointCloud pointcloud;
		if (OPT::fSampleMesh > 0)   // set points density
			scene.mesh.SamplePoints(OPT::fSampleMesh, 0, pointcloud);
		else                                        // set points number
			scene.mesh.SamplePoints((unsigned)ROUND2INT(-OPT::fSampleMesh), pointcloud);

		VERBOSE("Sample mesh completed: %u points (%s)", pointcloud.GetSize(), TD_TIMER_GET_FMT().c_str());
		pointcloud.Save(MAKE_PATH_SAFE(Util::getFileFullName(OPT::strOutputFileName))+_T(".ply"));
		Finalize();
		return EXIT_SUCCESS;
	}

首先创建了scene对象,这个对象是执行点云稠密化的最重要的工具。在这里,如果外界输入的指令是在曲面上进行点云采样,那么将会执行这个部分的代码。首先,他会加载曲面模型文件,即scene.mesh.Load(input_path);然后进行点云采样工作,即scene.mesh.SamplePoints(pointcloud);最后把采集的点云保存出来,即pointcloud.Save(output_path)。

1.2 导入图片和里程计

	// load and estimate a dense point-cloud
	// input images and poses
	if (!scene.Load(MAKE_PATH_SAFE(OPT::strInputFileName)))
		return EXIT_FAILURE;
    //  input mesh
	if (!OPT::strMeshFileName.empty())
		scene.mesh.Load(MAKE_PATH_SAFE(OPT::strMeshFileName));
	if (scene.pointcloud.IsEmpty() && OPT::strViewNeighborsFileName.empty() && scene.mesh.IsEmpty()) {
		VERBOSE("error: empty initial point-cloud");
		return EXIT_FAILURE;
	}

1.3 功能二:降采样

	//option2:  split the scene in sub-scenes such that each sub-scene surface does not exceed the given maximum sampling area (0 - disabled)
	if (OPT::fMaxSubsceneArea > 0) {
		// split the scene in sub-scenes by maximum sampling area
		Scene::ImagesChunkArr chunks;
		// downsampling depth pixels and images and get pintcloud
		scene.Split(chunks, OPT::fMaxSubsceneArea);
		//  save each chunk as a .mvs
		scene.ExportChunks(chunks, Util::getFilePath(MAKE_PATH_SAFE(OPT::strOutputFileName)), (ARCHIVE_TYPE)OPT::nArchiveType);
		Finalize();
		return EXIT_SUCCESS;
	}

对每一张照片都在像素层级上进行降采样,同时在照片层级上也进行降采样,把那些距离很近,区别不大的照片删掉一部分。然后把整个过程分割成若干个chunk,每一个chunk保存成一个.mvs文件。

1.4 功能三:根据是否可见对点云进行过滤

	//option3: filter dense point-cloud based on visibility (0 - disabled)
	if (OPT::thFilterPointCloud < 0) {
		// filter point-cloud based on camera-point visibility intersections
		scene.PointCloudFilter(OPT::thFilterPointCloud);
		// save
		const String baseFileName(MAKE_PATH_SAFE(Util::getFileFullName(OPT::strOutputFileName))+_T("_filtered"));
		scene.Save(baseFileName+_T(".mvs"), (ARCHIVE_TYPE)OPT::nArchiveType);
		scene.pointcloud.Save(baseFileName+_T(".ply"));
		Finalize();
		return EXIT_SUCCESS;
	}

1.5 功能四:根据观测次数输出过滤后的点云

	//option4: export points with >= number of views (0 - disabled)
	if (OPT::nExportNumViews && scene.pointcloud.IsValid()) {
		// export point-cloud containing only points with N+ views
		const String baseFileName(MAKE_PATH_SAFE(Util::getFileFullName(OPT::strOutputFileName)));
		scene.pointcloud.SaveNViews(baseFileName+String::FormatString(_T("_%dviews.ply"), OPT::nExportNumViews), (IIndex)OPT::nExportNumViews);
		Finalize();
		return EXIT_SUCCESS;
	}

1.6 默认功能:(核心)点云稠密化

	//option default: dense reconstruction
	if ((ARCHIVE_TYPE)OPT::nArchiveType != ARCHIVE_MVS) {
       // for each image,  find its neighbor images
		if (!OPT::strViewNeighborsFileName.empty())
			scene.LoadViewNeighbors(MAKE_PATH_SAFE(OPT::strViewNeighborsFileName));
		TD_TIMER_START();
		if (!scene.DenseReconstruction(OPT::nFusionMode)) {
			if (ABS(OPT::nFusionMode) != 1)
				return EXIT_FAILURE;
			VERBOSE("Depth-maps estimated (%s)", TD_TIMER_GET_FMT().c_str());
			Finalize();
			return EXIT_SUCCESS;
		}
		VERBOSE("Densifying point-cloud completed: %u points (%s)", scene.pointcloud.GetSize(), TD_TIMER_GET_FMT().c_str());
	}

1.7 输出结果

	// save the final point-cloud
	const String baseFileName(MAKE_PATH_SAFE(Util::getFileFullName(OPT::strOutputFileName)));
	scene.Save(baseFileName+_T(".mvs"), (ARCHIVE_TYPE)OPT::nArchiveType);
	scene.pointcloud.Save(baseFileName+_T(".ply"));
	#if TD_VERBOSE != TD_VERBOSE_OFF
	if (VERBOSITY_LEVEL > 2)
		scene.ExportCamerasMLP(baseFileName+_T(".mlp"), baseFileName+_T(".ply"));
	#endif

	Finalize();
	return EXIT_SUCCESS;
举报

相关推荐

0 条评论