kopia lustrzana https://github.com/OpenDroneMap/ODM
Merged origin/master
commit
cf259688fe
14
README.md
14
README.md
|
@ -216,6 +216,20 @@ If you have questions, join the developer's chat at https://community.opendronem
|
|||
2. Submit a pull request with detailed changes and test results
|
||||
3. Have fun!
|
||||
|
||||
### Credits
|
||||
|
||||
ODM makes use of [several libraries](https://github.com/OpenDroneMap/ODM/blob/master/snap/snapcraft.yaml#L36) and other awesome open source projects to perform its tasks. Among them we'd like to highlight:
|
||||
|
||||
- [OpenSfM](https://github.com/mapillary/OpenSfM)
|
||||
- [OpenMVS](https://github.com/cdcseacave/openMVS/)
|
||||
- [PDAL](https://github.com/PDAL/PDAL)
|
||||
- [Entwine](https://entwine.io/)
|
||||
- [MVS Texturing](https://github.com/nmoehrle/mvs-texturing)
|
||||
- [GRASS GIS](https://grass.osgeo.org/)
|
||||
- [GDAL](https://gdal.org/)
|
||||
- [PoissonRecon](https://github.com/mkazhdan/PoissonRecon)
|
||||
|
||||
|
||||
### Citation
|
||||
|
||||
> *OpenDroneMap Authors* ODM - A command line toolkit to generate maps, point clouds, 3D models and DEMs from drone, balloon or kite images. **OpenDroneMap/ODM GitHub Page** 2020; [https://github.com/OpenDroneMap/ODM](https://github.com/OpenDroneMap/ODM)
|
||||
|
|
|
@ -20,7 +20,7 @@ ExternalProject_Add(${_proj_name}
|
|||
#--Download step--------------
|
||||
DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}
|
||||
GIT_REPOSITORY https://github.com/OpenDroneMap/openMVS
|
||||
GIT_TAG 240
|
||||
GIT_TAG 244
|
||||
#--Update/Patch step----------
|
||||
UPDATE_COMMAND ""
|
||||
#--Configure step-------------
|
||||
|
|
4
VERSION
4
VERSION
|
@ -1 +1,5 @@
|
|||
<<<<<<< HEAD
|
||||
2.4.6
|
||||
=======
|
||||
2.4.5
|
||||
>>>>>>> origin/master
|
||||
|
|
|
@ -354,7 +354,14 @@ def config(argv=None, parser=None):
|
|||
action=StoreValue,
|
||||
type=float,
|
||||
default=0,
|
||||
help='Filters the point cloud by keeping only a single point around a radius N (in meters). This can be useful to limit the output resolution of the point cloud. Set to 0 to disable sampling. '
|
||||
help='Filters the point cloud by keeping only a single point around a radius N (in meters). This can be useful to limit the output resolution of the point cloud and remove duplicate points. Set to 0 to disable sampling. '
|
||||
'Default: %(default)s')
|
||||
|
||||
parser.add_argument('--pc-tile',
|
||||
action=StoreTrue,
|
||||
nargs=0,
|
||||
default=False,
|
||||
help='Reduce the memory usage needed for depthmap fusion by splitting large scenes into tiles. Turn this on if your machine doesn\'t have much RAM and/or you\'ve set --pc-quality to high or ultra. Experimental. '
|
||||
'Default: %(default)s')
|
||||
|
||||
parser.add_argument('--smrf-scalar',
|
||||
|
|
|
@ -9,6 +9,7 @@ from opendm import types
|
|||
from opendm.utils import get_depthmap_resolution
|
||||
from opendm.osfm import OSFMContext
|
||||
from opendm.multispectral import get_primary_band_name
|
||||
from opendm.point_cloud import fast_merge_ply
|
||||
|
||||
class ODMOpenMVSStage(types.ODM_Stage):
|
||||
def process(self, args, outputs):
|
||||
|
@ -23,17 +24,26 @@ class ODMOpenMVSStage(types.ODM_Stage):
|
|||
|
||||
# check if reconstruction was done before
|
||||
if not io.file_exists(tree.openmvs_model) or self.rerun():
|
||||
if io.dir_exists(tree.openmvs):
|
||||
shutil.rmtree(tree.openmvs)
|
||||
if self.rerun():
|
||||
if io.dir_exists(tree.openmvs):
|
||||
shutil.rmtree(tree.openmvs)
|
||||
|
||||
# export reconstruction from opensfm
|
||||
octx = OSFMContext(tree.opensfm)
|
||||
cmd = 'export_openmvs'
|
||||
octx.run(cmd)
|
||||
openmvs_scene_file = os.path.join(tree.openmvs, "scene.mvs")
|
||||
if not io.file_exists(openmvs_scene_file) or self.rerun():
|
||||
octx = OSFMContext(tree.opensfm)
|
||||
cmd = 'export_openmvs'
|
||||
octx.run(cmd)
|
||||
else:
|
||||
log.ODM_WARNING("Found existing %s" % openmvs_scene_file)
|
||||
|
||||
self.update_progress(10)
|
||||
|
||||
depthmaps_dir = os.path.join(tree.openmvs, "depthmaps")
|
||||
|
||||
if io.dir_exists(depthmaps_dir) and self.rerun():
|
||||
shutil.rmtree(depthmaps_dir)
|
||||
|
||||
if not io.dir_exists(depthmaps_dir):
|
||||
os.mkdir(depthmaps_dir)
|
||||
|
||||
|
@ -43,6 +53,14 @@ class ODMOpenMVSStage(types.ODM_Stage):
|
|||
else:
|
||||
resolution_level = int(round(math.log(outputs['undist_image_max_size'] / float(depthmap_resolution)) / math.log(2)))
|
||||
|
||||
log.ODM_INFO("Running dense reconstruction. This might take a while.")
|
||||
|
||||
log.ODM_INFO("Estimating depthmaps")
|
||||
|
||||
densify_ini_file = os.path.join(tree.openmvs, 'config.ini')
|
||||
with open(densify_ini_file, 'w+') as f:
|
||||
f.write("Optimize = 0\n") # Disable depth-maps re-filtering
|
||||
|
||||
config = [
|
||||
" --resolution-level %s" % int(resolution_level),
|
||||
"--min-resolution %s" % depthmap_resolution,
|
||||
|
@ -50,31 +68,101 @@ class ODMOpenMVSStage(types.ODM_Stage):
|
|||
"--max-threads %s" % args.max_concurrency,
|
||||
"--number-views-fuse 2",
|
||||
'-w "%s"' % depthmaps_dir,
|
||||
"-v 0",
|
||||
"-v 0"
|
||||
]
|
||||
|
||||
log.ODM_INFO("Running dense reconstruction. This might take a while.")
|
||||
|
||||
# TODO: add support for image masks
|
||||
|
||||
if args.pc_tile:
|
||||
config.append("--fusion-mode 1")
|
||||
|
||||
system.run('%s "%s" %s' % (context.omvs_densify_path,
|
||||
os.path.join(tree.openmvs, 'scene.mvs'),
|
||||
openmvs_scene_file,
|
||||
' '.join(config)))
|
||||
|
||||
self.update_progress(85)
|
||||
files_to_remove = []
|
||||
|
||||
# Filter points
|
||||
scene_dense = os.path.join(tree.openmvs, 'scene_dense.mvs')
|
||||
if os.path.exists(scene_dense):
|
||||
if args.pc_tile:
|
||||
log.ODM_INFO("Computing sub-scenes")
|
||||
config = [
|
||||
"--filter-point-cloud -1",
|
||||
'-i "%s"' % scene_dense,
|
||||
"-v 0"
|
||||
"--sub-scene-area 660000",
|
||||
"--max-threads %s" % args.max_concurrency,
|
||||
'-w "%s"' % depthmaps_dir,
|
||||
"-v 0",
|
||||
]
|
||||
system.run('%s %s' % (context.omvs_densify_path, ' '.join(config)))
|
||||
system.run('%s "%s" %s' % (context.omvs_densify_path,
|
||||
openmvs_scene_file,
|
||||
' '.join(config)))
|
||||
|
||||
scene_files = glob.glob(os.path.join(tree.openmvs, "scene_[0-9][0-9][0-9][0-9].mvs"))
|
||||
if len(scene_files) == 0:
|
||||
log.ODM_ERROR("No OpenMVS scenes found. This could be a bug, or the reconstruction could not be processed.")
|
||||
exit(1)
|
||||
|
||||
log.ODM_INFO("Fusing depthmaps for %s scenes" % len(scene_files))
|
||||
|
||||
scene_ply_files = []
|
||||
|
||||
for sf in scene_files:
|
||||
p, _ = os.path.splitext(sf)
|
||||
scene_ply = p + "_dense_dense_filtered.ply"
|
||||
scene_dense_mvs = p + "_dense.mvs"
|
||||
|
||||
files_to_remove += [scene_ply, sf, scene_dense_mvs]
|
||||
scene_ply_files.append(scene_ply)
|
||||
|
||||
if not io.file_exists(scene_ply) or self.rerun():
|
||||
# Fuse
|
||||
config = [
|
||||
'--resolution-level %s' % int(resolution_level),
|
||||
'--min-resolution %s' % depthmap_resolution,
|
||||
'--max-resolution %s' % int(outputs['undist_image_max_size']),
|
||||
'--dense-config-file "%s"' % densify_ini_file,
|
||||
'--number-views-fuse 2',
|
||||
'--max-threads %s' % args.max_concurrency,
|
||||
'-w "%s"' % depthmaps_dir,
|
||||
'-v 0',
|
||||
]
|
||||
|
||||
try:
|
||||
system.run('%s "%s" %s' % (context.omvs_densify_path, sf, ' '.join(config)))
|
||||
|
||||
# Filter
|
||||
system.run('%s "%s" --filter-point-cloud -1 -v 0' % (context.omvs_densify_path, scene_dense_mvs))
|
||||
except:
|
||||
log.ODM_WARNING("Sub-scene %s could not be reconstructed, skipping..." % sf)
|
||||
|
||||
if not io.file_exists(scene_ply):
|
||||
scene_ply_files.pop()
|
||||
log.ODM_WARNING("Could not compute PLY for subscene %s" % sf)
|
||||
else:
|
||||
log.ODM_WARNING("Found existing dense scene file %s" % scene_ply)
|
||||
|
||||
# Merge
|
||||
log.ODM_INFO("Merging %s scene files" % len(scene_ply_files))
|
||||
if len(scene_ply_files) == 0:
|
||||
log.ODM_ERROR("Could not compute dense point cloud (no PLY files available).")
|
||||
if len(scene_ply_files) == 1:
|
||||
# Simply rename
|
||||
os.rename(scene_ply_files[0], tree.openmvs_model)
|
||||
log.ODM_INFO("%s --> %s"% (scene_ply_files[0], tree.openmvs_model))
|
||||
else:
|
||||
# Merge
|
||||
fast_merge_ply(scene_ply_files, tree.openmvs_model)
|
||||
else:
|
||||
log.ODM_WARNING("Cannot find scene_dense.mvs, dense reconstruction probably failed. Exiting...")
|
||||
exit(1)
|
||||
# Filter all at once
|
||||
scene_dense = os.path.join(tree.openmvs, 'scene_dense.mvs')
|
||||
if os.path.exists(scene_dense):
|
||||
config = [
|
||||
"--filter-point-cloud -1",
|
||||
'-i "%s"' % scene_dense,
|
||||
"-v 0"
|
||||
]
|
||||
system.run('%s %s' % (context.omvs_densify_path, ' '.join(config)))
|
||||
else:
|
||||
log.ODM_WARNING("Cannot find scene_dense.mvs, dense reconstruction probably failed. Exiting...")
|
||||
exit(1)
|
||||
|
||||
# TODO: add support for image masks
|
||||
|
||||
self.update_progress(95)
|
||||
|
||||
|
@ -84,7 +172,7 @@ class ODMOpenMVSStage(types.ODM_Stage):
|
|||
os.path.join(tree.openmvs, 'scene_dense_dense_filtered.mvs'),
|
||||
octx.path("undistorted", "tracks.csv"),
|
||||
octx.path("undistorted", "reconstruction.json")
|
||||
]
|
||||
] + files_to_remove
|
||||
for f in files:
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
|
|
Ładowanie…
Reference in New Issue