kopia lustrzana https://github.com/OpenDroneMap/ODM
Remove MVE, handle image masks
rodzic
e38cc753d2
commit
f31355e3ce
|
@ -120,19 +120,6 @@ endforeach()
|
|||
include(ProcessorCount)
|
||||
ProcessorCount(nproc)
|
||||
|
||||
## Add mve Build
|
||||
|
||||
externalproject_add(mve
|
||||
GIT_REPOSITORY https://github.com/OpenDroneMap/mve.git
|
||||
GIT_TAG 210
|
||||
UPDATE_COMMAND ""
|
||||
SOURCE_DIR ${SB_SOURCE_DIR}/elibs/mve
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_COMMAND make -j${nproc}
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
|
||||
externalproject_add(poissonrecon
|
||||
GIT_REPOSITORY https://github.com/mkazhdan/PoissonRecon.git
|
||||
GIT_TAG ce5005ae3094d902d551a65a8b3131e06f45e7cf
|
||||
|
|
|
@ -27,12 +27,6 @@ opensfm_path = os.path.join(superbuild_path, "src/opensfm")
|
|||
# define orb_slam2 path
|
||||
orb_slam2_path = os.path.join(superbuild_path, "src/orb_slam2")
|
||||
|
||||
# define mve join_paths
|
||||
makescene_path = os.path.join(superbuild_path, 'src', 'elibs', 'mve', 'apps', 'makescene', 'makescene') #TODO: don't install in source
|
||||
dmrecon_path = os.path.join(superbuild_path, 'src', 'elibs', 'mve', 'apps', 'dmrecon', 'dmrecon')
|
||||
scene2pset_path = os.path.join(superbuild_path, 'src', 'elibs', 'mve', 'apps', 'scene2pset', 'scene2pset')
|
||||
meshclean_path = os.path.join(superbuild_path, 'src', 'elibs', 'mve', 'apps', 'meshclean', 'meshclean')
|
||||
|
||||
poisson_recon_path = os.path.join(superbuild_path, 'src', 'PoissonRecon', 'Bin', 'Linux', 'PoissonRecon')
|
||||
dem2mesh_path = os.path.join(superbuild_path, 'src', 'dem2mesh', 'dem2mesh')
|
||||
dem2points_path = os.path.join(superbuild_path, 'src', 'dem2points', 'dem2points')
|
||||
|
|
|
@ -213,7 +213,6 @@ class ODM_Tree(object):
|
|||
# whole reconstruction process.
|
||||
self.dataset_raw = io.join_paths(self.root_path, 'images')
|
||||
self.opensfm = io.join_paths(self.root_path, 'opensfm')
|
||||
self.mve = io.join_paths(self.root_path, 'mve')
|
||||
self.openmvs = io.join_paths(self.opensfm, 'undistorted', 'openmvs')
|
||||
self.odm_meshing = io.join_paths(self.root_path, 'odm_meshing')
|
||||
self.odm_texturing = io.join_paths(self.root_path, 'odm_texturing')
|
||||
|
@ -241,10 +240,6 @@ class ODM_Tree(object):
|
|||
self.opensfm_model = io.join_paths(self.opensfm, 'undistorted/depthmaps/merged.ply')
|
||||
self.opensfm_transformation = io.join_paths(self.opensfm, 'geocoords_transformation.txt')
|
||||
|
||||
# mve
|
||||
self.mve_model = io.join_paths(self.mve, 'mve_dense_point_cloud.ply')
|
||||
self.mve_views = io.join_paths(self.mve, 'views')
|
||||
|
||||
# OpenMVS
|
||||
self.openmvs_model = io.join_paths(self.openmvs, 'scene_dense.ply')
|
||||
|
||||
|
|
2
run.py
2
run.py
|
@ -60,7 +60,7 @@ if __name__ == '__main__':
|
|||
quote(os.path.join(args.project_path, "opensfm")),
|
||||
quote(os.path.join(args.project_path, "odm_filterpoints")),
|
||||
quote(os.path.join(args.project_path, "odm_texturing_25d")),
|
||||
quote(os.path.join(args.project_path, "mve")),
|
||||
quote(os.path.join(args.project_path, "openmvs")),
|
||||
quote(os.path.join(args.project_path, "entwine_pointcloud")),
|
||||
quote(os.path.join(args.project_path, "submodels")),
|
||||
]))
|
||||
|
|
|
@ -110,7 +110,7 @@ class ODMLoadDatasetStage(types.ODM_Stage):
|
|||
p.set_mask(find_mask(f, masks))
|
||||
photos += [p]
|
||||
dataset_list.write(photos[-1].filename + '\n')
|
||||
|
||||
|
||||
# Check if a geo file is available
|
||||
if tree.odm_geo_file is not None and os.path.exists(tree.odm_geo_file):
|
||||
log.ODM_INFO("Found image geolocation file")
|
||||
|
@ -134,6 +134,22 @@ class ODMLoadDatasetStage(types.ODM_Stage):
|
|||
|
||||
log.ODM_INFO('Found %s usable images' % len(photos))
|
||||
|
||||
# TODO: add support for masks in OpenMVS
|
||||
has_mask = False
|
||||
for p in photos:
|
||||
if p.mask is not None:
|
||||
has_mask = True
|
||||
break
|
||||
|
||||
if has_mask and not args.use_opensfm_dense:
|
||||
log.ODM_WARNING("Image masks found, will use OpenSfM for dense reconstruction")
|
||||
args.use_opensfm_dense = True
|
||||
|
||||
# Remove OpenMVS from pipeline. Yep.
|
||||
opensfm_stage = self.next_stage.next_stage.next_stage
|
||||
opensfm_stage.next_stage = opensfm_stage.next_stage.next_stage
|
||||
opensfm_stage.next_stage.prev_stage = opensfm_stage
|
||||
|
||||
# Create reconstruction object
|
||||
reconstruction = types.ODM_Reconstruction(photos)
|
||||
|
||||
|
|
102
stages/mve.py
102
stages/mve.py
|
@ -1,102 +0,0 @@
|
|||
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)
|
Ładowanie…
Reference in New Issue