From 99bbff7ce52c9500adb1fa043cc3b64cc44a7071 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Tue, 23 Apr 2019 18:01:14 -0400 Subject: [PATCH] Local submodel reconstruction, alignment Former-commit-id: 3087af2775fa9fb55d8445263e1247662de740fe --- opendm/osfm.py | 30 ++++++++++++++++++++++++++++-- opendm/types.py | 6 ++---- run.py | 0 scripts/run_opensfm.py | 27 ++++----------------------- scripts/splitmerge.py | 30 ++++++++++++++++++++++++++++-- 5 files changed, 62 insertions(+), 31 deletions(-) mode change 100644 => 100755 run.py diff --git a/opendm/osfm.py b/opendm/osfm.py index 1a23eb30..d74642d9 100644 --- a/opendm/osfm.py +++ b/opendm/osfm.py @@ -2,6 +2,7 @@ OpenSfM related utils """ +import os from opendm import io from opendm import log from opendm import system @@ -13,7 +14,7 @@ def run(command, opensfm_project_path): def export_bundler(opensfm_project_path, destination_bundle_file, rerun=False): - if not io.file_exists(destination_bundle_file) or self.rerun(): + if not io.file_exists(destination_bundle_file) or rerun: # convert back to bundler's format system.run('%s/bin/export_bundler %s' % (context.opensfm_path, opensfm_project_path)) @@ -21,6 +22,31 @@ def export_bundler(opensfm_project_path, destination_bundle_file, rerun=False): log.ODM_WARNING('Found a valid Bundler file in: %s' % destination_bundle_file) +def reconstruct(opensfm_project_path, rerun=False): + tracks_file = os.path.join(opensfm_project_path, 'tracks.csv') + reconstruction_file = os.path.join(opensfm_project_path, 'reconstruction.json') + + if not io.file_exists(tracks_file) or rerun: + run('create_tracks', opensfm_project_path) + else: + log.ODM_WARNING('Found a valid OpenSfM tracks file in: %s' % tracks_file) + + if not io.file_exists(reconstruction_file) or rerun: + run('reconstruct', opensfm_project_path) + else: + log.ODM_WARNING('Found a valid OpenSfM reconstruction file in: %s' % reconstruction_file) + + # Check that a reconstruction file has been created + if not io.file_exists(reconstruction_file): + log.ODM_ERROR("The program could not process this dataset using the current settings. " + "Check that the images have enough overlap, " + "that there are enough recognizable features " + "and that the images are in focus. " + "You could also try to increase the --min-num-features parameter." + "The program will now exit.") + raise Exception("Reconstruction could not be generated") + + def setup(args, images_path, opensfm_path, photos, gcp_path=None, append_config = []): """ Setup a OpenSfM project @@ -82,7 +108,7 @@ def setup(args, images_path, opensfm_path, photos, gcp_path=None, append_config with open(config_filename, 'w') as fout: fout.write("\n".join(config)) -def run_feature_matching(opensfm_project_path, rerun=False): +def feature_matching(opensfm_project_path, rerun=False): matched_done_file = io.join_paths(opensfm_project_path, 'matching_done.txt') if not io.file_exists(matched_done_file) or rerun: run('extract_metadata', opensfm_project_path) diff --git a/opendm/types.py b/opendm/types.py index b7e5ab99..5a1c98ca 100644 --- a/opendm/types.py +++ b/opendm/types.py @@ -373,11 +373,9 @@ class ODM_Stage: """ Does this stage need to be rerun? """ - return (self.args.rerun is not None and - self.args.rerun == self.name) or \ + return (self.args.rerun is not None and self.args.rerun == self.name) or \ (self.args.rerun_all) or \ - (self.args.rerun_from is not None and - self.name in self.args.rerun_from) + (self.args.rerun_from is not None and self.name in self.args.rerun_from) def run(self, outputs = {}): start_time = system.now_raw() diff --git a/run.py b/run.py old mode 100644 new mode 100755 diff --git a/scripts/run_opensfm.py b/scripts/run_opensfm.py index 87faeba4..647886db 100644 --- a/scripts/run_opensfm.py +++ b/scripts/run_opensfm.py @@ -28,34 +28,15 @@ class ODMOpenSfMStage(types.ODM_Stage): output_file = tree.opensfm_reconstruction # check if reconstruction was done before + # TODO: more granularity for each step (setup/featurematch/reconstruction/etc.) + if not io.file_exists(output_file) or self.rerun(): osfm.setup(args, tree.dataset_raw, tree.opensfm, photos, gcp_path=tree.odm_georeferencing_gcp) - osfm.run_feature_matching(tree.opensfm, self.rerun()) - - if not io.file_exists(tree.opensfm_tracks) or self.rerun(): - osfm.run('create_tracks', tree.opensfm) - else: - log.ODM_WARNING('Found a valid OpenSfM tracks file in: %s' % - tree.opensfm_tracks) - - if not io.file_exists(tree.opensfm_reconstruction) or self.rerun(): - osfm.run('reconstruct', tree.opensfm) - else: - log.ODM_WARNING('Found a valid OpenSfM reconstruction file in: %s' % - tree.opensfm_reconstruction) - - # Check that a reconstruction file has been created - if not io.file_exists(tree.opensfm_reconstruction): - log.ODM_ERROR("The program could not process this dataset using the current settings. " - "Check that the images have enough overlap, " - "that there are enough recognizable features " - "and that the images are in focus. " - "You could also try to increase the --min-num-features parameter." - "The program will now exit.") - sys.exit(1) + osfm.feature_matching(tree.opensfm, self.rerun()) + osfm.reconstruction(tree.opensfm, self.rerun()) # Always export VisualSFM's reconstruction and undistort images # as we'll use these for texturing (after GSD estimation and resizing) diff --git a/scripts/splitmerge.py b/scripts/splitmerge.py index 60c8e2df..cbb86dfc 100644 --- a/scripts/splitmerge.py +++ b/scripts/splitmerge.py @@ -1,7 +1,9 @@ +import os from opendm import log from opendm import osfm from opendm import types from opendm import io +from opensfm.large import metadataset class ODMSplitStage(types.ODM_Stage): def process(self, args, outputs): @@ -23,7 +25,7 @@ class ODMSplitStage(types.ODM_Stage): osfm.setup(args, tree.dataset_raw, tree.opensfm, photos, gcp_path=tree.odm_georeferencing_gcp, append_config=config) - osfm.run_feature_matching(tree.opensfm, self.rerun()) + osfm.feature_matching(tree.opensfm, self.rerun()) # Create submodels if not io.dir_exists(tree.submodels_path) or self.rerun(): @@ -34,8 +36,32 @@ class ODMSplitStage(types.ODM_Stage): osfm.run("create_submodels", tree.opensfm) else: log.ODM_WARNING("Submodels directory already exist at: %s" % tree.submodels_path) - + + # TODO: on a network workflow we probably stop here + # and let NodeODM take over + # exit(0) + + # Find paths of all submodels + mds = metadataset.MetaDataSet(tree.opensfm) + submodel_paths = [os.path.abspath(p) for p in mds.get_submodel_paths()] + + # Reconstruct each submodel + log.ODM_INFO("Dataset has been split into %s submodels. Reconstructing each submodel..." % len(submodel_paths)) + + for sp in submodel_paths: + log.ODM_INFO("Reconstructing %s" % sp) + osfm.reconstruct(sp, self.rerun()) + + # Align + log.ODM_INFO("Aligning submodels...") + osfm.run('align_submodels', tree.opensfm) + + # Dense reconstruction for each submodel + # TODO + exit(1) else: log.ODM_INFO("Normal dataset, will process all at once.") + +