Point to 061 branch in OpenDroneMap/OpenSfM, undistort logic adaptation

Former-commit-id: 05d0706da1
pull/1161/head
Piero Toffanin 2019-05-30 15:58:37 -04:00
rodzic f02cbc7225
commit 3249a196fa
4 zmienionych plików z 60 dodań i 20 usunięć

Wyświetl plik

@ -8,8 +8,8 @@ ExternalProject_Add(${_proj_name}
STAMP_DIR ${_SB_BINARY_DIR}/stamp STAMP_DIR ${_SB_BINARY_DIR}/stamp
#--Download step-------------- #--Download step--------------
DOWNLOAD_DIR ${SB_DOWNLOAD_DIR} DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}
GIT_REPOSITORY https://github.com/mapillary/OpenSfM/ GIT_REPOSITORY https://github.com/OpenDroneMap/OpenSfM/
GIT_TAG 00655397be3e27c490492ae01197bf66c51fa493 GIT_TAG 061
#--Update/Patch step---------- #--Update/Patch step----------
UPDATE_COMMAND git submodule update --init --recursive UPDATE_COMMAND git submodule update --init --recursive
#--Configure step------------- #--Configure step-------------

Wyświetl plik

@ -1,6 +1,7 @@
import os import os
import json import json
import numpy as np import numpy as np
import math
from repoze.lru import lru_cache from repoze.lru import lru_cache
from opendm import log from opendm import log
@ -20,6 +21,29 @@ def rounded_gsd(reconstruction_json, default_value=None, ndigits=0, ignore_gsd=F
return default_value 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): def image_scale_factor(target_resolution, reconstruction_json, gsd_error_estimate = 0.1):
""" """
:param target_resolution resolution the user wants have in cm / pixel :param target_resolution resolution the user wants have in cm / pixel

Wyświetl plik

@ -3,6 +3,7 @@ OpenSfM related utils
""" """
import os, shutil, sys import os, shutil, sys
import yaml
from opendm import io from opendm import io
from opendm import log from opendm import log
from opendm import system from opendm import system
@ -85,6 +86,7 @@ class OSFMContext:
"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 else 'yes'), "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: if has_alt:
@ -109,7 +111,7 @@ class OSFMContext:
# write config file # write config file
log.ODM_DEBUG(config) 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: with open(config_filename, 'w') as fout:
fout.write("\n".join(config)) fout.write("\n".join(config))
@ -121,6 +123,9 @@ class OSFMContext:
else: else:
log.ODM_WARNING("%s already exists, not rerunning OpenSfM setup" % list_path) 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): def extract_metadata(self, rerun=False):
metadata_dir = self.path("exif") metadata_dir = self.path("exif")
if not io.dir_exists(metadata_dir) or rerun: if not io.dir_exists(metadata_dir) or rerun:
@ -157,6 +162,23 @@ class OSFMContext:
def path(self, *paths): def path(self, *paths):
return os.path.join(self.opensfm_project_path, *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): def save_absolute_image_list_to(self, file):
""" """
Writes a copy of the image_list.txt file and makes sure that all paths Writes a copy of the image_list.txt file and makes sure that all paths

Wyświetl plik

@ -42,29 +42,26 @@ class ODMOpenSfMStage(types.ODM_Stage):
else: else:
output_file = tree.opensfm_reconstruction output_file = tree.opensfm_reconstruction
# Always export VisualSFM's reconstruction and undistort images octx.update_config({'undistorted_image_max_size': gsd.image_max_size(photos, args.orthophoto_resolution, tree.opensfm_reconstruction, ignore_gsd=args.ignore_gsd)})
# 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)
# These will be used for texturing # These will be used for texturing
undistorted_images_path = octx.path("undistorted") undistorted_images_path = octx.path("undistorted")
if not io.dir_exists(undistorted_images_path) or self.rerun(): 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: else:
log.ODM_WARNING("Found an undistorted directory in %s" % undistorted_images_path) log.ODM_WARNING("Found an undistorted directory in %s" % undistorted_images_path)
self.update_progress(80) 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 # Skip dense reconstruction if necessary and export
# sparse reconstruction instead # sparse reconstruction instead
if args.fast_orthophoto: 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) log.ODM_WARNING("Found a valid PLY reconstruction in %s" % output_file)
elif args.use_opensfm_dense: 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(): 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') octx.run('compute_depthmaps')
else: else:
log.ODM_WARNING("Found a valid dense reconstruction in %s" % output_file) log.ODM_WARNING("Found a valid dense reconstruction in %s" % output_file)