OpenDroneMap-ODM/stages/mve.py

103 wiersze
4.5 KiB
Python
Czysty Zwykły widok Historia

import shutil, os, glob, math
from opendm import log
from opendm import io
from opendm import system
from opendm import context
from opendm import point_cloud
from opendm import types
from opendm.osfm import OSFMContext
class ODMMveStage(types.ODM_Stage):
def process(self, args, outputs):
# get inputs
tree = outputs['tree']
reconstruction = outputs['reconstruction']
photos = reconstruction.photos
if not photos:
log.ODM_ERROR('Not enough photos in photos array to start MVE')
exit(1)
# check if reconstruction was done before
if not io.file_exists(tree.mve_model) or self.rerun():
# mve makescene wants the output directory
# to not exists before executing it (otherwise it
# will prompt the user for confirmation)
if io.dir_exists(tree.mve):
shutil.rmtree(tree.mve)
# run mve makescene
if not io.dir_exists(tree.mve_views):
nvm_file = tree.opensfm_reconstruction_nvm
if reconstruction.multi_camera:
# Reconstruct only the primary band
primary = reconstruction.multi_camera[0]
nvm_file = os.path.join(tree.opensfm, "undistorted", "reconstruction_%s.nvm" % primary['name'].lower())
system.run('%s "%s" "%s"' % (context.makescene_path, nvm_file, tree.mve), env_vars={'OMP_NUM_THREADS': args.max_concurrency})
self.update_progress(10)
# Compute mve output scale based on depthmap_resolution
max_pixels = args.depthmap_resolution * args.depthmap_resolution
if outputs['undist_image_max_size'] * outputs['undist_image_max_size'] <= max_pixels:
mve_output_scale = 0
else:
ratio = float(outputs['undist_image_max_size'] * outputs['undist_image_max_size']) / float(max_pixels)
mve_output_scale = int(math.ceil(math.log(ratio) / math.log(4.0)))
dmrecon_config = [
"-s%s" % mve_output_scale,
"--progress=fancy",
"--local-neighbors=2",
# "--filter-width=3",
]
# Run MVE's dmrecon
log.ODM_INFO("Running dense reconstruction. This might take a while.")
# TODO: find out why MVE is crashing at random
# MVE *seems* to have a race condition, triggered randomly, regardless of dataset
# https://gist.github.com/pierotofy/6c9ce93194ba510b61e42e3698cfbb89
# Temporary workaround is to retry the reconstruction until we get it right
# (up to a certain number of retries).
retry_count = 1
while retry_count < 10:
try:
system.run('%s %s "%s"' % (context.dmrecon_path, ' '.join(dmrecon_config), tree.mve), env_vars={'OMP_NUM_THREADS': args.max_concurrency})
break
except Exception as e:
if str(e) == "Child returned 134" or str(e) == "Child returned 1":
retry_count += 1
log.ODM_WARNING("Caught error code, retrying attempt #%s" % retry_count)
else:
raise e
self.update_progress(90)
scene2pset_config = [
"-F%s" % mve_output_scale,
'-mmask'
]
# run scene2pset
system.run('%s %s "%s" "%s"' % (context.scene2pset_path, ' '.join(scene2pset_config), tree.mve, tree.mve_model), env_vars={'OMP_NUM_THREADS': args.max_concurrency})
# run cleanmesh (filter points by MVE confidence threshold)
if args.mve_confidence > 0:
mve_filtered_model = io.related_file_path(tree.mve_model, postfix=".filtered")
system.run('%s -t%s --no-clean --component-size=0 "%s" "%s"' % (context.meshclean_path, min(1.0, args.mve_confidence), tree.mve_model, mve_filtered_model), env_vars={'OMP_NUM_THREADS': args.max_concurrency})
if io.file_exists(mve_filtered_model):
os.remove(tree.mve_model)
os.rename(mve_filtered_model, tree.mve_model)
else:
log.ODM_WARNING("Couldn't filter MVE model (%s does not exist)." % mve_filtered_model)
if args.optimize_disk_space:
shutil.rmtree(tree.mve_views)
else:
log.ODM_WARNING('Found a valid MVE reconstruction file in: %s' %
tree.mve_model)