2019-03-01 17:35:53 +00:00
|
|
|
import sys
|
2019-03-06 02:45:08 +00:00
|
|
|
import os
|
2015-11-26 12:15:02 +00:00
|
|
|
|
2015-11-20 10:00:43 +00:00
|
|
|
from opendm import log
|
2015-11-26 12:15:02 +00:00
|
|
|
from opendm import io
|
2015-11-20 10:00:43 +00:00
|
|
|
from opendm import system
|
|
|
|
from opendm import context
|
2018-08-11 16:45:21 +00:00
|
|
|
from opendm import gsd
|
2019-03-06 00:38:46 +00:00
|
|
|
from opendm import point_cloud
|
2019-04-22 19:14:39 +00:00
|
|
|
from opendm import types
|
2019-04-23 17:59:54 +00:00
|
|
|
from opendm import osfm
|
2016-02-26 18:50:12 +00:00
|
|
|
|
2019-04-22 19:14:39 +00:00
|
|
|
class ODMOpenSfMStage(types.ODM_Stage):
|
|
|
|
def process(self, args, outputs):
|
|
|
|
tree = outputs['tree']
|
|
|
|
reconstruction = outputs['reconstruction']
|
2018-01-26 19:38:26 +00:00
|
|
|
photos = reconstruction.photos
|
2015-11-26 12:15:02 +00:00
|
|
|
|
2015-11-27 16:51:21 +00:00
|
|
|
if not photos:
|
2016-03-08 18:26:58 +00:00
|
|
|
log.ODM_ERROR('Not enough photos in photos array to start OpenSfM')
|
2019-04-22 19:14:39 +00:00
|
|
|
exit(1)
|
2015-11-27 16:51:21 +00:00
|
|
|
|
2018-08-11 16:45:21 +00:00
|
|
|
if args.fast_orthophoto:
|
|
|
|
output_file = io.join_paths(tree.opensfm, 'reconstruction.ply')
|
|
|
|
elif args.use_opensfm_dense:
|
2016-09-30 13:08:56 +00:00
|
|
|
output_file = tree.opensfm_model
|
|
|
|
else:
|
|
|
|
output_file = tree.opensfm_reconstruction
|
2015-11-26 12:15:02 +00:00
|
|
|
|
2016-09-30 13:08:56 +00:00
|
|
|
# check if reconstruction was done before
|
2019-04-22 19:14:39 +00:00
|
|
|
if not io.file_exists(output_file) or self.rerun():
|
2015-12-30 14:36:56 +00:00
|
|
|
|
2019-04-23 18:45:47 +00:00
|
|
|
osfm.setup(args, tree.dataset_raw, tree.opensfm, photos, gcp_path=tree.odm_georeferencing_gcp)
|
2019-04-23 17:59:54 +00:00
|
|
|
|
2019-04-23 18:45:47 +00:00
|
|
|
osfm.run_feature_matching(tree.opensfm, self.rerun())
|
2017-03-22 22:22:24 +00:00
|
|
|
|
2019-04-22 19:14:39 +00:00
|
|
|
if not io.file_exists(tree.opensfm_tracks) or self.rerun():
|
2019-04-23 17:59:54 +00:00
|
|
|
osfm.run('create_tracks', tree.opensfm)
|
2017-03-22 22:22:24 +00:00
|
|
|
else:
|
|
|
|
log.ODM_WARNING('Found a valid OpenSfM tracks file in: %s' %
|
2017-04-04 16:54:40 +00:00
|
|
|
tree.opensfm_tracks)
|
2017-03-22 22:22:24 +00:00
|
|
|
|
2019-04-22 19:14:39 +00:00
|
|
|
if not io.file_exists(tree.opensfm_reconstruction) or self.rerun():
|
2019-04-23 17:59:54 +00:00
|
|
|
osfm.run('reconstruct', tree.opensfm)
|
2017-04-04 16:54:40 +00:00
|
|
|
else:
|
|
|
|
log.ODM_WARNING('Found a valid OpenSfM reconstruction file in: %s' %
|
|
|
|
tree.opensfm_reconstruction)
|
|
|
|
|
2019-03-01 17:35:53 +00:00
|
|
|
# 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. "
|
2019-03-03 21:41:03 +00:00
|
|
|
"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.")
|
2019-03-01 17:35:53 +00:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
2018-08-11 16:45:21 +00:00
|
|
|
# Always export VisualSFM's reconstruction and undistort images
|
|
|
|
# as we'll use these for texturing (after GSD estimation and resizing)
|
|
|
|
if not args.ignore_gsd:
|
|
|
|
image_scale = gsd.image_scale_factor(args.orthophoto_resolution, tree.opensfm_reconstruction)
|
|
|
|
else:
|
|
|
|
image_scale = 1.0
|
2017-04-04 16:54:40 +00:00
|
|
|
|
2019-04-22 19:14:39 +00:00
|
|
|
if not io.file_exists(tree.opensfm_reconstruction_nvm) or self.rerun():
|
2019-04-23 17:59:54 +00:00
|
|
|
osfm.run('export_visualsfm --image_extension png --scale_focal %s' % image_scale, tree.opensfm)
|
2018-08-11 16:45:21 +00:00
|
|
|
else:
|
|
|
|
log.ODM_WARNING('Found a valid OpenSfM NVM reconstruction file in: %s' %
|
|
|
|
tree.opensfm_reconstruction_nvm)
|
2018-06-27 18:32:49 +00:00
|
|
|
|
2018-08-11 16:45:21 +00:00
|
|
|
# These will be used for texturing
|
2019-04-23 17:59:54 +00:00
|
|
|
osfm.run('undistort --image_format png --image_scale %s' % image_scale, tree.opensfm)
|
2018-08-11 16:45:21 +00:00
|
|
|
|
|
|
|
# Skip dense reconstruction if necessary and export
|
|
|
|
# sparse reconstruction instead
|
|
|
|
if args.fast_orthophoto:
|
2019-04-23 17:59:54 +00:00
|
|
|
osfm.run('export_ply --no-cameras' % image_scale, tree.opensfm)
|
2018-08-11 16:45:21 +00:00
|
|
|
elif args.use_opensfm_dense:
|
|
|
|
# Undistort images at full scale in JPG
|
|
|
|
# (TODO: we could compare the size of the PNGs if they are < than depthmap_resolution
|
|
|
|
# and use those instead of re-exporting full resolution JPGs)
|
2019-04-23 17:59:54 +00:00
|
|
|
osfm.run('undistort', tree.opensfm)
|
|
|
|
osfm.run('compute_depthmaps', tree.opensfm)
|
2015-11-30 15:52:21 +00:00
|
|
|
else:
|
2017-03-22 22:22:24 +00:00
|
|
|
log.ODM_WARNING('Found a valid OpenSfM reconstruction file in: %s' %
|
2016-02-26 18:50:12 +00:00
|
|
|
tree.opensfm_reconstruction)
|
2015-12-10 11:01:41 +00:00
|
|
|
|
2016-09-30 14:11:10 +00:00
|
|
|
# check if reconstruction was exported to bundler before
|
2019-04-23 18:45:47 +00:00
|
|
|
osfm.export_bundler(tree.opensfm, tree.opensfm_bundle_list, self.rerun())
|
2016-09-30 13:08:56 +00:00
|
|
|
|
2018-04-19 02:03:54 +00:00
|
|
|
if reconstruction.georef:
|
2019-04-23 17:59:54 +00:00
|
|
|
osfm.run('export_geocoords --transformation --proj \'%s\'' % reconstruction.georef.projection.srs, tree.opensfm)
|