Local submodel reconstruction, alignment

pull/979/head
Piero Toffanin 2019-04-23 18:01:14 -04:00
rodzic 277b60c22d
commit 3087af2775
5 zmienionych plików z 62 dodań i 31 usunięć

Wyświetl plik

@ -2,6 +2,7 @@
OpenSfM related utils OpenSfM related utils
""" """
import os
from opendm import io from opendm import io
from opendm import log from opendm import log
from opendm import system 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): 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 # convert back to bundler's format
system.run('%s/bin/export_bundler %s' % system.run('%s/bin/export_bundler %s' %
(context.opensfm_path, opensfm_project_path)) (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) 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 = []): def setup(args, images_path, opensfm_path, photos, gcp_path=None, append_config = []):
""" """
Setup a OpenSfM project 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: with open(config_filename, 'w') as fout:
fout.write("\n".join(config)) 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') matched_done_file = io.join_paths(opensfm_project_path, 'matching_done.txt')
if not io.file_exists(matched_done_file) or rerun: if not io.file_exists(matched_done_file) or rerun:
run('extract_metadata', opensfm_project_path) run('extract_metadata', opensfm_project_path)

Wyświetl plik

@ -373,11 +373,9 @@ class ODM_Stage:
""" """
Does this stage need to be rerun? Does this stage need to be rerun?
""" """
return (self.args.rerun is not None and return (self.args.rerun is not None and self.args.rerun == self.name) or \
self.args.rerun == self.name) or \
(self.args.rerun_all) or \ (self.args.rerun_all) or \
(self.args.rerun_from is not None and (self.args.rerun_from is not None and self.name in self.args.rerun_from)
self.name in self.args.rerun_from)
def run(self, outputs = {}): def run(self, outputs = {}):
start_time = system.now_raw() start_time = system.now_raw()

0
run.py 100644 → 100755
Wyświetl plik

Wyświetl plik

@ -28,34 +28,15 @@ class ODMOpenSfMStage(types.ODM_Stage):
output_file = tree.opensfm_reconstruction output_file = tree.opensfm_reconstruction
# check if reconstruction was done before # 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(): 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.setup(args, tree.dataset_raw, tree.opensfm, photos, gcp_path=tree.odm_georeferencing_gcp)
osfm.run_feature_matching(tree.opensfm, self.rerun()) osfm.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.reconstruction(tree.opensfm, self.rerun())
# Always export VisualSFM's reconstruction and undistort images # Always export VisualSFM's reconstruction and undistort images
# as we'll use these for texturing (after GSD estimation and resizing) # as we'll use these for texturing (after GSD estimation and resizing)

Wyświetl plik

@ -1,7 +1,9 @@
import os
from opendm import log from opendm import log
from opendm import osfm from opendm import osfm
from opendm import types from opendm import types
from opendm import io from opendm import io
from opensfm.large import metadataset
class ODMSplitStage(types.ODM_Stage): class ODMSplitStage(types.ODM_Stage):
def process(self, args, outputs): 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.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 # Create submodels
if not io.dir_exists(tree.submodels_path) or self.rerun(): 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) osfm.run("create_submodels", tree.opensfm)
else: else:
log.ODM_WARNING("Submodels directory already exist at: %s" % tree.submodels_path) 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) exit(1)
else: else:
log.ODM_INFO("Normal dataset, will process all at once.") log.ODM_INFO("Normal dataset, will process all at once.")