diff --git a/SuperBuild/CMakeLists.txt b/SuperBuild/CMakeLists.txt index f1bb3b89..940ff9dd 100644 --- a/SuperBuild/CMakeLists.txt +++ b/SuperBuild/CMakeLists.txt @@ -173,3 +173,13 @@ externalproject_add(dem2mesh BUILD_COMMAND make INSTALL_COMMAND "" ) + +externalproject_add(dem2points + GIT_REPOSITORY https://github.com/OpenDroneMap/dem2points.git + GIT_TAG master + SOURCE_DIR ${SB_SOURCE_DIR}/dem2points + UPDATE_COMMAND "" + BUILD_IN_SOURCE 1 + BUILD_COMMAND make + INSTALL_COMMAND "" +) \ No newline at end of file diff --git a/opendm/context.py b/opendm/context.py index d3a1559f..53edb9d8 100644 --- a/opendm/context.py +++ b/opendm/context.py @@ -29,6 +29,8 @@ smvs_path = os.path.join(superbuild_path, 'src', 'elibs', 'smvs', 'app', 'smvsre poisson_recon_path = os.path.join(superbuild_path, 'src', 'PoissonRecon', 'Bin', 'Linux', 'PoissonRecon') dem2mesh_path = os.path.join(superbuild_path, 'src', 'dem2mesh', 'dem2mesh') +dem2points_path = os.path.join(superbuild_path, 'src', 'dem2points', 'dem2points') + # define mvstex path mvstex_path = os.path.join(superbuild_path, "install/bin/texrecon") diff --git a/opendm/mesh.py b/opendm/mesh.py index 3c24ba41..155f3934 100644 --- a/opendm/mesh.py +++ b/opendm/mesh.py @@ -8,7 +8,7 @@ from opendm import context from scipy import signal, ndimage import numpy as np -def create_25dmesh(inPointCloud, outMesh, dsm_radius=0.07, dsm_resolution=0.05, depth=8, samples=1, maxVertexCount=100000, verbose=False, max_workers=None): +def create_25dmesh(inPointCloud, outMesh, dsm_radius=0.07, dsm_resolution=0.05, depth=8, samples=1, maxVertexCount=100000, verbose=False, max_workers=None, method='gridded'): # Create DSM from point cloud # Create temporary directory @@ -35,7 +35,17 @@ def create_25dmesh(inPointCloud, outMesh, dsm_radius=0.07, dsm_resolution=0.05, max_workers=max_workers ) - mesh = dem_to_mesh(os.path.join(tmp_directory, 'mesh_dsm.tif'), outMesh, maxVertexCount, verbose) + if method == 'gridded': + mesh = dem_to_mesh_gridded(os.path.join(tmp_directory, 'mesh_dsm.tif'), outMesh, maxVertexCount, verbose) + elif method == 'poisson': + dsm_points = dem_to_points(os.path.join(tmp_directory, 'mesh_dsm.tif'), os.path.join(tmp_directory, 'dsm_points.ply'), verbose) + mesh = screened_poisson_reconstruction(dsm_points, outMesh, depth=depth, + samples=samples, + maxVertexCount=maxVertexCount, + threads=max_workers, + verbose=verbose) + else: + raise 'Not a valid method: ' + method # Cleanup tmp if os.path.exists(tmp_directory): @@ -43,7 +53,28 @@ def create_25dmesh(inPointCloud, outMesh, dsm_radius=0.07, dsm_resolution=0.05, return mesh -def dem_to_mesh(inGeotiff, outPointCloud, maxVertexCount, verbose=False): + +def dem_to_points(inGeotiff, outPointCloud, verbose=False): + log.ODM_INFO('Sampling points from DSM: %s' % inGeotiff) + + kwargs = { + 'bin': context.dem2points_path, + 'outfile': outPointCloud, + 'infile': inGeotiff, + 'verbose': '-verbose' if verbose else '' + } + + system.run('{bin} -inputFile {infile} ' + '-outputFile {outfile} ' + '-skirtHeightThreshold 1.5 ' + '-skirtIncrements 0.2 ' + '-skirtHeightCap 100 ' + ' {verbose} '.format(**kwargs)) + + return outPointCloud + + +def dem_to_mesh_gridded(inGeotiff, outPointCloud, maxVertexCount, verbose=False): log.ODM_INFO('Creating mesh from DSM: %s' % inGeotiff) kwargs = { diff --git a/scripts/odm_meshing.py b/scripts/odm_meshing.py index 64457b19..0ff6bf38 100644 --- a/scripts/odm_meshing.py +++ b/scripts/odm_meshing.py @@ -96,7 +96,7 @@ class ODMeshingCell(ecto.Cell): dsm_radius *= 2 log.ODM_DEBUG('ODM 2.5D DSM resolution: %s' % dsm_resolution) - + mesh.create_25dmesh(infile, tree.odm_25dmesh, dsm_radius=dsm_radius, dsm_resolution=dsm_resolution, @@ -104,7 +104,8 @@ class ODMeshingCell(ecto.Cell): maxVertexCount=self.params.max_vertex, samples=self.params.samples, verbose=self.params.verbose, - max_workers=args.max_concurrency) + max_workers=args.max_concurrency, + method='poisson' if args.fast_orthophoto else 'gridded') else: log.ODM_WARNING('Found a valid ODM 2.5D Mesh file in: %s' % tree.odm_25dmesh)