diff --git a/SuperBuild/cmake/External-OpenCV.cmake b/SuperBuild/cmake/External-OpenCV.cmake index 232059c9..6c19c461 100644 --- a/SuperBuild/cmake/External-OpenCV.cmake +++ b/SuperBuild/cmake/External-OpenCV.cmake @@ -7,8 +7,7 @@ ExternalProject_Add(${_proj_name} STAMP_DIR ${_SB_BINARY_DIR}/stamp #--Download step-------------- DOWNLOAD_DIR ${SB_DOWNLOAD_DIR} - URL https://github.com/Itseez/opencv/archive/2.4.11.zip - URL_MD5 b517e83489c709eee1d8be76b16976a7 + URL https://github.com/opencv/opencv/archive/3.4.6.zip #--Update/Patch step---------- UPDATE_COMMAND "" #--Configure step------------- diff --git a/opendm/config.py b/opendm/config.py index de33cc20..34d1c692 100644 --- a/opendm/config.py +++ b/opendm/config.py @@ -70,9 +70,9 @@ def config(): metavar='', default=2048, type=int, - help='Resizes images by the largest side for feature extraction. ' + help='Resizes images by the largest side for feature extraction purposes only. ' 'Set to -1 to disable. This does not affect the final orthophoto ' - ' resolution quality. Default: %(default)s') + ' resolution quality and will not resize the original images. Default: %(default)s') parser.add_argument('--end-with', '-e', metavar='', @@ -153,11 +153,11 @@ def config(): parser.add_argument('--camera-model', metavar='', default='auto', - choices=['auto', 'perspective', 'brown', 'fisheye'], + choices=['auto', 'perspective', 'brown', 'fisheye', 'spherical'], help=('Set a camera projection type. Manually setting a value ' 'can help improve geometric undistortion. By default the application ' 'tries to determine a projection type from the images metadata. Can be ' - 'set to one of: [auto, perspective, brown, fisheye]. Default: ' + 'set to one of: [auto, perspective, brown, fisheye, spherical]. Default: ' '%(default)s')) parser.add_argument('--max-concurrency', diff --git a/opendm/osfm.py b/opendm/osfm.py index a41e733e..ec8b9b4a 100644 --- a/opendm/osfm.py +++ b/opendm/osfm.py @@ -23,7 +23,7 @@ class OSFMContext: def export_bundler(self, destination_bundle_file, rerun=False): if not io.file_exists(destination_bundle_file) or rerun: # convert back to bundler's format - system.run('%s/bin/export_bundler "%s"' % + system.run('%s/bin/export_bundler --undistorted "%s"' % (context.opensfm_path, self.opensfm_project_path)) else: log.ODM_WARNING('Found a valid Bundler file in: %s' % destination_bundle_file) @@ -122,7 +122,6 @@ class OSFMContext: if not has_gps: log.ODM_INFO("No GPS information, using BOW matching") config.append("matcher_type: WORDS") - config.append("matching_bow_neighbors: %s" % args.matcher_neighbors) if has_alt: log.ODM_INFO("Altitude data detected, enabling it for GPS alignment") @@ -234,30 +233,6 @@ class OSFMContext: 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 - written in it are absolute paths and not relative paths. - """ - image_list_file = self.path("image_list.txt") - - if io.file_exists(image_list_file): - with open(image_list_file, 'r') as f: - content = f.read() - - lines = [] - for line in map(str.strip, content.split('\n')): - if line and not line.startswith("/"): - line = os.path.abspath(os.path.join(self.opensfm_project_path, line)) - lines.append(line) - - with open(file, 'w') as f: - f.write("\n".join(lines)) - - log.ODM_INFO("Wrote %s with absolute paths" % file) - else: - log.ODM_WARNING("No %s found, cannot create %s" % (image_list_file, file)) - def name(self): return os.path.basename(os.path.abspath(self.path(".."))) diff --git a/opendm/types.py b/opendm/types.py index 2079f62e..8d9b2577 100644 --- a/opendm/types.py +++ b/opendm/types.py @@ -259,9 +259,6 @@ class ODM_Tree(object): # mve self.mve_model = io.join_paths(self.mve, 'mve_dense_point_cloud.ply') - self.mve_path = io.join_paths(self.opensfm, 'mve') - self.mve_image_list = io.join_paths(self.mve_path, 'list.txt') - self.mve_bundle = io.join_paths(self.mve_path, 'bundle/bundle.out') self.mve_views = io.join_paths(self.mve, 'views') # filter points diff --git a/stages/mve.py b/stages/mve.py index f63beb10..b487251e 100644 --- a/stages/mve.py +++ b/stages/mve.py @@ -21,19 +21,6 @@ class ODMMveStage(types.ODM_Stage): # check if reconstruction was done before if not io.file_exists(tree.mve_model) or self.rerun(): - # cleanup if a rerun - if io.dir_exists(tree.mve_path) and self.rerun(): - shutil.rmtree(tree.mve_path) - - # make bundle directory - if not io.file_exists(tree.mve_bundle): - system.mkdir_p(tree.mve_path) - system.mkdir_p(io.join_paths(tree.mve_path, 'bundle')) - - octx = OSFMContext(tree.opensfm) - octx.save_absolute_image_list_to(tree.mve_image_list) - io.copy(tree.opensfm_bundle, tree.mve_bundle) - # mve makescene wants the output directory # to not exists before executing it (otherwise it # will prompt the user for confirmation) @@ -42,22 +29,16 @@ class ODMMveStage(types.ODM_Stage): # run mve makescene if not io.dir_exists(tree.mve_views): - system.run('%s "%s" "%s"' % (context.makescene_path, tree.mve_path, tree.mve), env_vars={'OMP_NUM_THREADS': args.max_concurrency}) + system.run('%s "%s" "%s"' % (context.makescene_path, tree.opensfm_reconstruction_nvm, tree.mve), env_vars={'OMP_NUM_THREADS': args.max_concurrency}) self.update_progress(10) # Compute mve output scale based on depthmap_resolution - max_width = 0 - max_height = 0 - for photo in photos: - max_width = max(photo.width, max_width) - max_height = max(photo.height, max_height) - max_pixels = args.depthmap_resolution * args.depthmap_resolution - if max_width * max_height <= max_pixels: + if outputs['undist_image_max_size'] * outputs['undist_image_max_size'] <= max_pixels: mve_output_scale = 0 else: - ratio = float(max_width * max_height) / float(max_pixels) + ratio = float(outputs['undist_image_max_size'] * outputs['undist_image_max_size']) / float(max_pixels) mve_output_scale = int(math.ceil(math.log(ratio) / math.log(4.0))) dmrecon_config = [ diff --git a/stages/run_opensfm.py b/stages/run_opensfm.py index 626e981d..67d720e7 100644 --- a/stages/run_opensfm.py +++ b/stages/run_opensfm.py @@ -44,11 +44,19 @@ class ODMOpenSfMStage(types.ODM_Stage): output_file = tree.opensfm_reconstruction updated_config_flag_file = octx.path('updated_config.txt') + + # Make sure it's capped by the depthmap-resolution arg, + # 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), + args.depthmap_resolution + ) + if not io.file_exists(updated_config_flag_file) or self.rerun(): - octx.update_config({'undistorted_image_max_size': gsd.image_max_size(photos, args.orthophoto_resolution, tree.opensfm_reconstruction, ignore_gsd=args.ignore_gsd)}) + octx.update_config({'undistorted_image_max_size': outputs['undist_image_max_size']}) octx.touch(updated_config_flag_file) - # These will be used for texturing + # These will be used for texturing / MVS undistorted_images_path = octx.path("undistorted") if not io.dir_exists(undistorted_images_path) or self.rerun(): @@ -59,7 +67,7 @@ class ODMOpenSfMStage(types.ODM_Stage): self.update_progress(80) if not io.file_exists(tree.opensfm_reconstruction_nvm) or self.rerun(): - octx.run('export_visualsfm --undistorted') + octx.run('export_visualsfm --undistorted --points') else: log.ODM_WARNING('Found a valid OpenSfM NVM reconstruction file in: %s' % tree.opensfm_reconstruction_nvm)