Merge pull request #1201 from pierotofy/221

Improved orthophotos, added --pc-quality flag
pull/1205/head v2.2.1
Piero Toffanin 2020-11-15 00:34:39 -05:00 zatwierdzone przez GitHub
commit 786833d185
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
10 zmienionych plików z 62 dodań i 29 usunięć

Wyświetl plik

@ -29,7 +29,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
language: [ 'cpp', 'python' ] language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more... # Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection

Wyświetl plik

@ -9,7 +9,7 @@ ExternalProject_Add(${_proj_name}
#--Download step-------------- #--Download step--------------
DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}/${_proj_name} DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}/${_proj_name}
GIT_REPOSITORY https://github.com/OpenDroneMap/mvs-texturing GIT_REPOSITORY https://github.com/OpenDroneMap/mvs-texturing
GIT_TAG 200 GIT_TAG 221
#--Update/Patch step---------- #--Update/Patch step----------
UPDATE_COMMAND "" UPDATE_COMMAND ""
#--Configure step------------- #--Configure step-------------

Wyświetl plik

@ -1 +1 @@
2.2.0 2.2.1

Wyświetl plik

@ -235,7 +235,7 @@ def config(argv=None, parser=None):
action=StoreValue, action=StoreValue,
type=float, type=float,
default=640, 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. ' 'but produce denser point clouds. '
'Default: %(default)s')) 'Default: %(default)s'))
@ -357,6 +357,15 @@ def config(argv=None, parser=None):
'Use 0 to disable cropping. ' 'Use 0 to disable cropping. '
'Default: %(default)s')) 'Default: %(default)s'))
parser.add_argument('--pc-quality',
metavar='<string>',
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', parser.add_argument('--pc-classify',
action=StoreTrue, action=StoreTrue,
nargs=0, nargs=0,
@ -446,17 +455,6 @@ def config(argv=None, parser=None):
help=('Data term: [area, gmi]. Default: ' help=('Data term: [area, gmi]. Default: '
'%(default)s')) '%(default)s'))
parser.add_argument('--texturing-nadir-weight',
metavar='<integer: 0 <= x <= 32>',
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', parser.add_argument('--texturing-outlier-removal-type',
metavar='<string>', metavar='<string>',
action=StoreValue, action=StoreValue,

Wyświetl plik

@ -9,6 +9,8 @@ from opendm import log
from opendm import system from opendm import system
from opendm import context from opendm import context
from opendm import camera 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 metadataset
from opensfm.large import tools from opensfm.large import tools
from opensfm.actions import undistort from opensfm.actions import undistort
@ -145,6 +147,7 @@ class OSFMContext:
# Compute feature_process_size # Compute feature_process_size
feature_process_size = 2048 # default feature_process_size = 2048 # default
if 'resize_to_is_set' in args: if 'resize_to_is_set' in args:
# Legacy # Legacy
log.ODM_WARNING("Legacy option --resize-to (this might be removed in a future version). Use --feature-quality instead.") 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, 'low': 0.125,
'lowest': 0.0675, 'lowest': 0.0675,
} }
# Find largest photo dimension
max_dim = 0 max_dim = find_largest_photo_dim(photos)
for p in photos:
if p.width is None:
continue
max_dim = max(max_dim, max(p.width, p.height))
if max_dim > 0: if max_dim > 0:
log.ODM_INFO("Maximum photo dimensions: %spx" % str(max_dim)) log.ODM_INFO("Maximum photo dimensions: %spx" % str(max_dim))
@ -170,6 +169,8 @@ class OSFMContext:
else: else:
log.ODM_WARNING("Cannot compute max image dimensions, going with defaults") log.ODM_WARNING("Cannot compute max image dimensions, going with defaults")
depthmap_resolution = get_depthmap_resolution(args, photos)
# create config file for OpenSfM # create config file for OpenSfM
config = [ config = [
"use_exif_size: no", "use_exif_size: no",
@ -180,7 +181,7 @@ class OSFMContext:
"matching_gps_neighbors: %s" % matcher_neighbors, "matching_gps_neighbors: %s" % matcher_neighbors,
"matching_gps_distance: %s" % args.matcher_distance, "matching_gps_distance: %s" % args.matcher_distance,
"depthmap_method: %s" % args.opensfm_depthmap_method, "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_patch_sd: %s" % args.opensfm_depthmap_min_patch_sd,
"depthmap_min_consistent_views: %s" % args.opensfm_depthmap_min_consistent_views, "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'), "optimize_camera_parameters: %s" % ('no' if args.use_fixed_camera_params or args.cameras else 'yes'),

Wyświetl plik

@ -15,6 +15,15 @@ import xmltodict as x2d
from opendm import get_image_size from opendm import get_image_size
from xml.parsers.expat import ExpatError 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: class ODM_Photo:
"""ODMPhoto - a class for ODMPhotos""" """ODMPhoto - a class for ODMPhotos"""

23
opendm/utils.py 100644
Wyświetl plik

@ -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

Wyświetl plik

@ -91,7 +91,6 @@ class ODMMvsTexStage(types.ODM_Stage):
'keepUnseenFaces': keepUnseenFaces, 'keepUnseenFaces': keepUnseenFaces,
'toneMapping': self.params.get('tone_mapping'), 'toneMapping': self.params.get('tone_mapping'),
'nadirMode': nadir, 'nadirMode': nadir,
'nadirWeight': 2 ** args.texturing_nadir_weight - 1,
'nvm_file': r['nvm_file'] 'nvm_file': r['nvm_file']
} }
@ -111,8 +110,7 @@ class ODMMvsTexStage(types.ODM_Stage):
'{skipLocalSeamLeveling} ' '{skipLocalSeamLeveling} '
'{skipHoleFilling} ' '{skipHoleFilling} '
'{keepUnseenFaces} ' '{keepUnseenFaces} '
'{nadirMode} ' '{nadirMode}'.format(**kwargs))
'-n {nadirWeight}'.format(**kwargs))
if args.optimize_disk_space: if args.optimize_disk_space:
cleanup_files = [ cleanup_files = [

Wyświetl plik

@ -6,6 +6,7 @@ from opendm import system
from opendm import context from opendm import context
from opendm import point_cloud from opendm import point_cloud
from opendm import types from opendm import types
from opendm.utils import get_depthmap_resolution
from opendm.osfm import OSFMContext from opendm.osfm import OSFMContext
class ODMOpenMVSStage(types.ODM_Stage): class ODMOpenMVSStage(types.ODM_Stage):
@ -39,15 +40,17 @@ class ODMOpenMVSStage(types.ODM_Stage):
depthmaps_dir = os.path.join(tree.openmvs, "depthmaps") depthmaps_dir = os.path.join(tree.openmvs, "depthmaps")
if not io.dir_exists(depthmaps_dir): if not io.dir_exists(depthmaps_dir):
os.mkdir(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 resolution_level = 0
else: 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 = [ config = [
" --resolution-level %s" % int(resolution_level), " --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-resolution %s" % int(outputs['undist_image_max_size']),
"--max-threads %s" % args.max_concurrency, "--max-threads %s" % args.max_concurrency,
'-w "%s"' % depthmaps_dir, '-w "%s"' % depthmaps_dir,

Wyświetl plik

@ -10,6 +10,7 @@ from opendm import context
from opendm import gsd from opendm import gsd
from opendm import point_cloud from opendm import point_cloud
from opendm import types from opendm import types
from opendm.utils import get_depthmap_resolution
from opendm.osfm import OSFMContext from opendm.osfm import OSFMContext
from opendm import multispectral from opendm import multispectral
@ -60,7 +61,7 @@ class ODMOpenSfMStage(types.ODM_Stage):
# since the undistorted images are used for MVS # since the undistorted images are used for MVS
outputs['undist_image_max_size'] = max( 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()), 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(): if not io.file_exists(updated_config_flag_file) or self.rerun():