diff --git a/SuperBuild/cmake/External-MvsTexturing.cmake b/SuperBuild/cmake/External-MvsTexturing.cmake index fff13360..d49b2096 100644 --- a/SuperBuild/cmake/External-MvsTexturing.cmake +++ b/SuperBuild/cmake/External-MvsTexturing.cmake @@ -9,7 +9,7 @@ ExternalProject_Add(${_proj_name} #--Download step-------------- DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}/${_proj_name} GIT_REPOSITORY https://github.com/OpenDroneMap/mvs-texturing - GIT_TAG 200 + GIT_TAG 221 #--Update/Patch step---------- UPDATE_COMMAND "" #--Configure step------------- diff --git a/VERSION b/VERSION index ccbccc3d..c043eea7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.0 +2.2.1 diff --git a/opendm/config.py b/opendm/config.py index ece64784..85b8adc6 100755 --- a/opendm/config.py +++ b/opendm/config.py @@ -235,7 +235,7 @@ def config(argv=None, parser=None): action=StoreValue, type=float, default=640, - help=('Controls the density of the point cloud by setting the resolution of the depthmap images. Higher values take longer to compute ' + help=('Legacy option (use --pc-quality instead). Controls the density of the point cloud by setting the resolution of the depthmap images. Higher values take longer to compute ' 'but produce denser point clouds. ' 'Default: %(default)s')) @@ -357,6 +357,15 @@ def config(argv=None, parser=None): 'Use 0 to disable cropping. ' 'Default: %(default)s')) + parser.add_argument('--pc-quality', + metavar='', + action=StoreValue, + default='medium', + choices=['ultra', 'high', 'medium', 'low'], + help=('Set point cloud quality. Higher quality generates better, denser point clouds, but requires more memory and takes longer. Each step up in quality increases processing time roughly by a factor of 4x.' + 'Can be one of: %(choices)s. Default: ' + '%(default)s')) + parser.add_argument('--pc-classify', action=StoreTrue, nargs=0, @@ -446,17 +455,6 @@ def config(argv=None, parser=None): help=('Data term: [area, gmi]. Default: ' '%(default)s')) - parser.add_argument('--texturing-nadir-weight', - metavar='', - action=StoreValue, - default=16, - type=int, - help=('Affects orthophotos only. ' - 'Higher values result in sharper corners, but can affect color distribution and blurriness. ' - 'Use lower values for planar areas and higher values for urban areas. ' - 'The default value works well for most scenarios. Default: ' - '%(default)s')) - parser.add_argument('--texturing-outlier-removal-type', metavar='', action=StoreValue, diff --git a/opendm/osfm.py b/opendm/osfm.py index d49574ab..ead01c3e 100644 --- a/opendm/osfm.py +++ b/opendm/osfm.py @@ -9,6 +9,8 @@ from opendm import log from opendm import system from opendm import context from opendm import camera +from opendm.utils import get_depthmap_resolution +from opendm.photo import find_largest_photo_dim from opensfm.large import metadataset from opensfm.large import tools from opensfm.actions import undistort @@ -145,6 +147,7 @@ class OSFMContext: # Compute feature_process_size feature_process_size = 2048 # default + if 'resize_to_is_set' in args: # Legacy log.ODM_WARNING("Legacy option --resize-to (this might be removed in a future version). Use --feature-quality instead.") @@ -157,12 +160,8 @@ class OSFMContext: 'low': 0.125, 'lowest': 0.0675, } - # Find largest photo dimension - max_dim = 0 - for p in photos: - if p.width is None: - continue - max_dim = max(max_dim, max(p.width, p.height)) + + max_dim = find_largest_photo_dim(photos) if max_dim > 0: log.ODM_INFO("Maximum photo dimensions: %spx" % str(max_dim)) @@ -170,6 +169,8 @@ class OSFMContext: else: log.ODM_WARNING("Cannot compute max image dimensions, going with defaults") + depthmap_resolution = get_depthmap_resolution(args, photos) + # create config file for OpenSfM config = [ "use_exif_size: no", @@ -180,7 +181,7 @@ class OSFMContext: "matching_gps_neighbors: %s" % matcher_neighbors, "matching_gps_distance: %s" % args.matcher_distance, "depthmap_method: %s" % args.opensfm_depthmap_method, - "depthmap_resolution: %s" % args.depthmap_resolution, + "depthmap_resolution: %s" % depthmap_resolution, "depthmap_min_patch_sd: %s" % args.opensfm_depthmap_min_patch_sd, "depthmap_min_consistent_views: %s" % args.opensfm_depthmap_min_consistent_views, "optimize_camera_parameters: %s" % ('no' if args.use_fixed_camera_params or args.cameras else 'yes'), diff --git a/opendm/photo.py b/opendm/photo.py index fc355869..cd99bb4f 100644 --- a/opendm/photo.py +++ b/opendm/photo.py @@ -15,6 +15,15 @@ import xmltodict as x2d from opendm import get_image_size from xml.parsers.expat import ExpatError +def find_largest_photo_dim(photos): + max_dim = 0 + for p in photos: + if p.width is None: + continue + max_dim = max(max_dim, max(p.width, p.height)) + + return max_dim + class ODM_Photo: """ODMPhoto - a class for ODMPhotos""" diff --git a/opendm/utils.py b/opendm/utils.py new file mode 100644 index 00000000..42cc2c6d --- /dev/null +++ b/opendm/utils.py @@ -0,0 +1,23 @@ +from opendm import log +from opendm.photo import find_largest_photo_dim + +def get_depthmap_resolution(args, photos): + if 'depthmap_resolution_is_set' in args: + # Legacy + log.ODM_WARNING("Legacy option --depthmap-resolution (this might be removed in a future version). Use --pc-quality instead.") + return int(args.depthmap_resolution) + else: + max_dim = find_largest_photo_dim(photos) + + pc_quality_scale = { + 'ultra': 0.5, + 'high': 0.25, + 'medium': 0.125, + 'low': 0.0675 + } + + if max_dim > 0: + return int(max_dim * pc_quality_scale[args.pc_quality]) + else: + log.ODM_WARNING("Cannot compute max image dimensions, going with default depthmap_resolution of 640") + return 640 # Sensible default diff --git a/stages/openmvs.py b/stages/openmvs.py index 961a86c7..35a9a9c8 100644 --- a/stages/openmvs.py +++ b/stages/openmvs.py @@ -6,6 +6,7 @@ from opendm import system from opendm import context from opendm import point_cloud from opendm import types +from opendm.utils import get_depthmap_resolution from opendm.osfm import OSFMContext class ODMOpenMVSStage(types.ODM_Stage): @@ -39,15 +40,17 @@ class ODMOpenMVSStage(types.ODM_Stage): depthmaps_dir = os.path.join(tree.openmvs, "depthmaps") if not io.dir_exists(depthmaps_dir): os.mkdir(depthmaps_dir) + + depthmap_resolution = get_depthmap_resolution(args, photos) - if outputs["undist_image_max_size"] <= args.depthmap_resolution: + if outputs["undist_image_max_size"] <= depthmap_resolution: resolution_level = 0 else: - resolution_level = math.floor(math.log(outputs['undist_image_max_size'] / float(args.depthmap_resolution)) / math.log(2)) + resolution_level = math.floor(math.log(outputs['undist_image_max_size'] / float(depthmap_resolution)) / math.log(2)) config = [ " --resolution-level %s" % int(resolution_level), - "--min-resolution %s" % int(args.depthmap_resolution), + "--min-resolution %s" % depthmap_resolution, "--max-resolution %s" % int(outputs['undist_image_max_size']), "--max-threads %s" % args.max_concurrency, '-w "%s"' % depthmaps_dir, diff --git a/stages/run_opensfm.py b/stages/run_opensfm.py index a5bf34c1..fee9e3d9 100644 --- a/stages/run_opensfm.py +++ b/stages/run_opensfm.py @@ -10,6 +10,7 @@ from opendm import context from opendm import gsd from opendm import point_cloud from opendm import types +from opendm.utils import get_depthmap_resolution from opendm.osfm import OSFMContext from opendm import multispectral @@ -60,7 +61,7 @@ class ODMOpenSfMStage(types.ODM_Stage): # since the undistorted images are used for MVS outputs['undist_image_max_size'] = max( gsd.image_max_size(photos, args.orthophoto_resolution, tree.opensfm_reconstruction, ignore_gsd=args.ignore_gsd, has_gcp=reconstruction.has_gcp()), - args.depthmap_resolution + get_depthmap_resolution(args, photos) ) if not io.file_exists(updated_config_flag_file) or self.rerun():