kopia lustrzana https://github.com/OpenDroneMap/ODM
Point to 061 branch in OpenDroneMap/OpenSfM, undistort logic adaptation
Former-commit-id: 05d0706da1
pull/1161/head
rodzic
f02cbc7225
commit
3249a196fa
|
@ -8,8 +8,8 @@ ExternalProject_Add(${_proj_name}
|
|||
STAMP_DIR ${_SB_BINARY_DIR}/stamp
|
||||
#--Download step--------------
|
||||
DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}
|
||||
GIT_REPOSITORY https://github.com/mapillary/OpenSfM/
|
||||
GIT_TAG 00655397be3e27c490492ae01197bf66c51fa493
|
||||
GIT_REPOSITORY https://github.com/OpenDroneMap/OpenSfM/
|
||||
GIT_TAG 061
|
||||
#--Update/Patch step----------
|
||||
UPDATE_COMMAND git submodule update --init --recursive
|
||||
#--Configure step-------------
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import os
|
||||
import json
|
||||
import numpy as np
|
||||
import math
|
||||
from repoze.lru import lru_cache
|
||||
from opendm import log
|
||||
|
||||
|
@ -20,6 +21,29 @@ def rounded_gsd(reconstruction_json, default_value=None, ndigits=0, ignore_gsd=F
|
|||
return default_value
|
||||
|
||||
|
||||
def image_max_size(photos, target_resolution, reconstruction_json, gsd_error_estimate = 0.1, ignore_gsd=False):
|
||||
"""
|
||||
:param photos images database
|
||||
:param target_resolution resolution the user wants have in cm / pixel
|
||||
:param reconstruction_json path to OpenSfM's reconstruction.json
|
||||
:param gsd_error_estimate percentage of estimated error in the GSD calculation to set an upper bound on resolution.
|
||||
:param ignore_gsd if set to True, simply return the largest side of the largest image in the images database.
|
||||
:return A dimension in pixels calculated by taking the image_scale_factor and applying it to the size of the largest image.
|
||||
Returned value is never higher than the size of the largest side of the largest image.
|
||||
"""
|
||||
max_width = 0
|
||||
max_height = 0
|
||||
if ignore_gsd:
|
||||
isf = 1.0
|
||||
else:
|
||||
isf = image_scale_factor(target_resolution, reconstruction_json, gsd_error_estimate)
|
||||
|
||||
for p in photos:
|
||||
max_width = max(p.width, max_width)
|
||||
max_height = max(p.height, max_height)
|
||||
|
||||
return int(math.ceil(max(max_width, max_height) * isf))
|
||||
|
||||
def image_scale_factor(target_resolution, reconstruction_json, gsd_error_estimate = 0.1):
|
||||
"""
|
||||
:param target_resolution resolution the user wants have in cm / pixel
|
||||
|
|
|
@ -3,6 +3,7 @@ OpenSfM related utils
|
|||
"""
|
||||
|
||||
import os, shutil, sys
|
||||
import yaml
|
||||
from opendm import io
|
||||
from opendm import log
|
||||
from opendm import system
|
||||
|
@ -85,6 +86,7 @@ class OSFMContext:
|
|||
"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 else 'yes'),
|
||||
"undistorted_image_format: png" # mvs-texturing exhibits artifacts with JPG
|
||||
]
|
||||
|
||||
if has_alt:
|
||||
|
@ -109,7 +111,7 @@ class OSFMContext:
|
|||
|
||||
# write config file
|
||||
log.ODM_DEBUG(config)
|
||||
config_filename = io.join_paths(self.opensfm_project_path, 'config.yaml')
|
||||
config_filename = self.get_config_file_path()
|
||||
with open(config_filename, 'w') as fout:
|
||||
fout.write("\n".join(config))
|
||||
|
||||
|
@ -121,6 +123,9 @@ class OSFMContext:
|
|||
else:
|
||||
log.ODM_WARNING("%s already exists, not rerunning OpenSfM setup" % list_path)
|
||||
|
||||
def get_config_file_path(self):
|
||||
return io.join_paths(self.opensfm_project_path, 'config.yaml')
|
||||
|
||||
def extract_metadata(self, rerun=False):
|
||||
metadata_dir = self.path("exif")
|
||||
if not io.dir_exists(metadata_dir) or rerun:
|
||||
|
@ -157,6 +162,23 @@ class OSFMContext:
|
|||
def path(self, *paths):
|
||||
return os.path.join(self.opensfm_project_path, *paths)
|
||||
|
||||
def update_config(self, cfg_dict):
|
||||
cfg_file = self.get_config_file_path()
|
||||
log.ODM_DEBUG("Updating %s" % cfg_file)
|
||||
if os.path.exists(cfg_file):
|
||||
try:
|
||||
with open(cfg_file) as fin:
|
||||
cfg = yaml.safe_load(fin)
|
||||
for k, v in cfg_dict.items():
|
||||
cfg[k] = v
|
||||
log.ODM_DEBUG("%s: %s" % (k, v))
|
||||
with open(cfg_file, 'w') as fout:
|
||||
fout.write(yaml.dump(cfg, default_flow_style=False))
|
||||
except Exception as e:
|
||||
log.ODM_WARNING("Cannot update configuration file %s: %s" % (cfg_file, str(e)))
|
||||
else:
|
||||
log.ODM_WARNING("Tried to update configuration, but %s does not exist." % cfg_file)
|
||||
|
||||
def save_absolute_image_list_to(self, file):
|
||||
"""
|
||||
Writes a copy of the image_list.txt file and makes sure that all paths
|
||||
|
|
|
@ -42,29 +42,26 @@ class ODMOpenSfMStage(types.ODM_Stage):
|
|||
else:
|
||||
output_file = tree.opensfm_reconstruction
|
||||
|
||||
# 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
|
||||
|
||||
if not io.file_exists(tree.opensfm_reconstruction_nvm) or self.rerun():
|
||||
octx.run('export_visualsfm --image_extension png --scale_focal %s' % image_scale)
|
||||
else:
|
||||
log.ODM_WARNING('Found a valid OpenSfM NVM reconstruction file in: %s' %
|
||||
tree.opensfm_reconstruction_nvm)
|
||||
octx.update_config({'undistorted_image_max_size': gsd.image_max_size(photos, args.orthophoto_resolution, tree.opensfm_reconstruction, ignore_gsd=args.ignore_gsd)})
|
||||
|
||||
# These will be used for texturing
|
||||
undistorted_images_path = octx.path("undistorted")
|
||||
|
||||
if not io.dir_exists(undistorted_images_path) or self.rerun():
|
||||
octx.run('undistort --image_format png --image_scale %s' % image_scale)
|
||||
octx.run('undistort')
|
||||
else:
|
||||
log.ODM_WARNING("Found an undistorted directory in %s" % undistorted_images_path)
|
||||
|
||||
self.update_progress(80)
|
||||
|
||||
if not io.file_exists(tree.opensfm_reconstruction_nvm) or self.rerun():
|
||||
octx.run('export_visualsfm')
|
||||
else:
|
||||
log.ODM_WARNING('Found a valid OpenSfM NVM reconstruction file in: %s' %
|
||||
tree.opensfm_reconstruction_nvm)
|
||||
|
||||
self.update_progress(85)
|
||||
|
||||
# Skip dense reconstruction if necessary and export
|
||||
# sparse reconstruction instead
|
||||
if args.fast_orthophoto:
|
||||
|
@ -74,11 +71,8 @@ class ODMOpenSfMStage(types.ODM_Stage):
|
|||
log.ODM_WARNING("Found a valid PLY reconstruction in %s" % output_file)
|
||||
|
||||
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)
|
||||
if not io.file_exists(output_file) or self.rerun():
|
||||
octx.run('undistort')
|
||||
#octx.run('undistort') # TODO can we use PNGs here?
|
||||
octx.run('compute_depthmaps')
|
||||
else:
|
||||
log.ODM_WARNING("Found a valid dense reconstruction in %s" % output_file)
|
||||
|
|
Ładowanie…
Reference in New Issue