diff --git a/opendm/config.py b/opendm/config.py index e0394113..bcb99d0c 100644 --- a/opendm/config.py +++ b/opendm/config.py @@ -110,6 +110,12 @@ def config(): 'images based on GPS exif data. Set to 0 to skip ' 'pre-matching. Default: %(default)s') + parser.add_argument('--use-opensfm-pointcloud', + action='store_true', + default=False, + help='Use OpenSfM to compute the point cloud instead ' + 'of PMVS') + parser.add_argument('--cmvs-maxImages', metavar='', default=500, diff --git a/opendm/types.py b/opendm/types.py index 581d5753..edf524c3 100644 --- a/opendm/types.py +++ b/opendm/types.py @@ -360,6 +360,7 @@ class ODM_Tree(object): self.opensfm_bundle_list = io.join_paths(self.opensfm, 'list_r000.out') self.opensfm_image_list = io.join_paths(self.opensfm, 'image_list.txt') self.opensfm_reconstruction = io.join_paths(self.opensfm, 'reconstruction.json') + self.opensfm_model = io.join_paths(self.opensfm, 'depthmaps/merged.ply') # pmvs self.pmvs_rec_path = io.join_paths(self.pmvs, 'recon0') diff --git a/scripts/mvstex.py b/scripts/mvstex.py index fa860995..a893df22 100644 --- a/scripts/mvstex.py +++ b/scripts/mvstex.py @@ -84,14 +84,18 @@ class ODMMvsTexCell(ecto.Cell): 'skipHoleFilling': skipHoleFilling, 'keepUnseenFaces': keepUnseenFaces } - - log.ODM_DEBUG('Generating .nvm file from pmvs output: %s' - % '{nvm_file}'.format(**kwargs)) - - # Create .nvm camera file. - pmvs2nvmcams.run('{pmvs_folder}'.format(**kwargs), - '{nvm_file}'.format(**kwargs)) - + + if args.use_opensfm_pointcloud: + kwargs['nvm_file'] = io.join_paths(tree.opensfm, + "reconstruction.nvm") + else: + log.ODM_DEBUG('Generating .nvm file from pmvs output: %s' + % '{nvm_file}'.format(**kwargs)) + + # Create .nvm camera file. + pmvs2nvmcams.run('{pmvs_folder}'.format(**kwargs), + '{nvm_file}'.format(**kwargs)) + # run texturing binary system.run('{bin} {nvm_file} {model} {out_dir} ' '-d {dataTerm} -o {outlierRemovalType} ' diff --git a/scripts/odm_app.py b/scripts/odm_app.py index 008049a9..730165d9 100644 --- a/scripts/odm_app.py +++ b/scripts/odm_app.py @@ -110,20 +110,26 @@ class ODMApp(ecto.BlackBox): self.args[:] >> self.opensfm['args'], self.resize['photos'] >> self.opensfm['photos']] - # run cmvs - connections += [self.tree[:] >> self.cmvs['tree'], - self.args[:] >> self.cmvs['args'], - self.opensfm['reconstruction'] >> self.cmvs['reconstruction']] + if _p.args.use_opensfm_pointcloud: + # create odm mesh from opensfm point cloud + connections += [self.tree[:] >> self.meshing['tree'], + self.args[:] >> self.meshing['args'], + self.opensfm['reconstruction'] >> self.meshing['reconstruction']] + else: + # run cmvs + connections += [self.tree[:] >> self.cmvs['tree'], + self.args[:] >> self.cmvs['args'], + self.opensfm['reconstruction'] >> self.cmvs['reconstruction']] - # run pmvs - connections += [self.tree[:] >> self.pmvs['tree'], - self.args[:] >> self.pmvs['args'], - self.cmvs['reconstruction'] >> self.pmvs['reconstruction']] + # run pmvs + connections += [self.tree[:] >> self.pmvs['tree'], + self.args[:] >> self.pmvs['args'], + self.cmvs['reconstruction'] >> self.pmvs['reconstruction']] - # create odm mesh - connections += [self.tree[:] >> self.meshing['tree'], - self.args[:] >> self.meshing['args'], - self.pmvs['reconstruction'] >> self.meshing['reconstruction']] + # create odm mesh from pmvs point cloud + connections += [self.tree[:] >> self.meshing['tree'], + self.args[:] >> self.meshing['args'], + self.pmvs['reconstruction'] >> self.meshing['reconstruction']] # create odm texture connections += [self.tree[:] >> self.texturing['tree'], diff --git a/scripts/odm_georeferencing.py b/scripts/odm_georeferencing.py index 50f9fc39..00dbb9be 100644 --- a/scripts/odm_georeferencing.py +++ b/scripts/odm_georeferencing.py @@ -85,7 +85,6 @@ class ODMGeoreferencingCell(ecto.Cell): 'imgs': tree.dataset_raw, 'imgs_list': tree.opensfm_bundle_list, 'model': tree.odm_textured_model_obj, - 'pc': tree.pmvs_model, 'log': tree.odm_georeferencing_log, 'coords': tree.odm_georeferencing_coords, 'pc_geo': tree.odm_georeferencing_model_ply_geo, @@ -95,6 +94,10 @@ class ODMGeoreferencingCell(ecto.Cell): 'gcp': gcpfile, } + if args.use_opensfm_pointcloud: + kwargs['pc'] = tree.opensfm_model + else: + kwargs['pc'] = tree.pmvs_model if self.params.use_gcp and \ io.file_exists(gcpfile): diff --git a/scripts/odm_meshing.py b/scripts/odm_meshing.py index dc8f1973..1db4dab8 100644 --- a/scripts/odm_meshing.py +++ b/scripts/odm_meshing.py @@ -52,7 +52,6 @@ class ODMeshingCell(ecto.Cell): kwargs = { 'bin': context.odm_modules_path, - 'infile': tree.pmvs_model, 'outfile': tree.odm_mesh, 'log': tree.odm_meshing_log, 'max_vertex': self.params.max_vertex, @@ -60,6 +59,10 @@ class ODMeshingCell(ecto.Cell): 'samples': self.params.samples, 'solver': self.params.solver } + if args.use_opensfm_pointcloud: + kwargs['infile'] = tree.opensfm_model + else: + kwargs['infile'] = tree.pmvs_model # run meshing binary system.run('{bin}/odm_meshing -inputFile {infile} ' diff --git a/scripts/opensfm.py b/scripts/opensfm.py index 21d80221..6b98c4f4 100644 --- a/scripts/opensfm.py +++ b/scripts/opensfm.py @@ -48,9 +48,13 @@ class ODMOpenSfMCell(ecto.Cell): (args.rerun_from is not None and 'opensfm' in args.rerun_from) - # check if reconstruction was done before + if args.use_opensfm_pointcloud: + output_file = tree.opensfm_model + else: + output_file = tree.opensfm_reconstruction - if not io.file_exists(tree.opensfm_reconstruction) or rerun_cell: + # check if reconstruction was done before + if not io.file_exists(output_file) or rerun_cell: # create file list list_path = io.join_paths(tree.opensfm, 'image_list.txt') with open(list_path, 'w') as fout: @@ -77,31 +81,38 @@ class ODMOpenSfMCell(ecto.Cell): # run OpenSfM reconstruction system.run('PYTHONPATH=%s %s/bin/run_all %s' % (context.pyopencv_path, context.opensfm_path, tree.opensfm)) + if args.use_opensfm_pointcloud: + system.run('PYTHONPATH=%s %s/bin/opensfm export_visualsfm %s' % + (context.pyopencv_path, context.opensfm_path, tree.opensfm)) + system.run('PYTHONPATH=%s %s/bin/opensfm undistort %s' % + (context.pyopencv_path, context.opensfm_path, tree.opensfm)) + system.run('PYTHONPATH=%s %s/bin/opensfm compute_depthmaps %s' % + (context.pyopencv_path, context.opensfm_path, tree.opensfm)) else: log.ODM_WARNING('Found a valid OpenSfM file in: %s' % tree.opensfm_reconstruction) - # check if reconstruction was exported to bundler before + if not args.use_opensfm_pointcloud: + # check if reconstruction was exported to bundler before + if not io.file_exists(tree.opensfm_bundle_list) or rerun_cell: + # convert back to bundler's format + system.run('PYTHONPATH=%s %s/bin/export_bundler %s' % + (context.pyopencv_path, context.opensfm_path, tree.opensfm)) + else: + log.ODM_WARNING('Found a valid Bundler file in: %s' % + tree.opensfm_reconstruction) - if not io.file_exists(tree.opensfm_bundle_list) or rerun_cell: - # convert back to bundler's format - system.run('PYTHONPATH=%s %s/bin/export_bundler %s' % - (context.pyopencv_path, context.opensfm_path, tree.opensfm)) - else: - log.ODM_WARNING('Found a valid Bundler file in: %s' % - tree.opensfm_reconstruction) + # check if reconstruction was exported to pmvs before - # check if reconstruction was exported to pmvs before + if not io.file_exists(tree.pmvs_visdat) or rerun_cell: + # run PMVS converter + system.run('PYTHONPATH=%s %s/bin/export_pmvs %s --output %s' % + (context.pyopencv_path, context.opensfm_path, tree.opensfm, tree.pmvs)) + else: + log.ODM_WARNING('Found a valid CMVS file in: %s' % tree.pmvs_visdat) - if not io.file_exists(tree.pmvs_visdat) or rerun_cell: - # run PMVS converter - system.run('PYTHONPATH=%s %s/bin/export_pmvs %s --output %s' % - (context.pyopencv_path, context.opensfm_path, tree.opensfm, tree.pmvs)) - else: - log.ODM_WARNING('Found a valid CMVS file in: %s' % tree.pmvs_visdat) - - if args.time: - system.benchmark(start_time, tree.benchmarking, 'OpenSfM') + if args.time: + system.benchmark(start_time, tree.benchmarking, 'OpenSfM') log.ODM_INFO('Running ODM OpenSfM Cell - Finished') return ecto.OK if args.end_with != 'opensfm' else ecto.QUIT