mirror of
https://code.it4i.cz/sccs/easyconfigs-it4i.git
synced 2025-04-07 23:42:12 +01:00

new file: i/IRODS/IRODS-0.7.3.eb new file: l/libxc/libxc-5.1.5-intel-2020a.eb new file: n/NodeODM/NodeODM-2.2.0-GCCcore-11.3.0.eb new file: o/ODM/ODM-2.8.7/.dockerignore new file: o/ODM/ODM-2.8.7/.github/workflows/publish-docker-and-wsl.yaml new file: o/ODM/ODM-2.8.7/.github/workflows/publish-docker-gpu.yaml new file: o/ODM/ODM-2.8.7/.github/workflows/publish-snap.yml new file: o/ODM/ODM-2.8.7/.github/workflows/publish-windows.yml new file: o/ODM/ODM-2.8.7/.github/workflows/test-build-prs.yaml new file: o/ODM/ODM-2.8.7/.gitignore new file: o/ODM/ODM-2.8.7/.gitmodules new file: o/ODM/ODM-2.8.7/CNAME new file: o/ODM/ODM-2.8.7/CONTRIBUTING.md new file: o/ODM/ODM-2.8.7/Dockerfile new file: o/ODM/ODM-2.8.7/LICENSE new file: o/ODM/ODM-2.8.7/README.md new file: o/ODM/ODM-2.8.7/SuperBuild/CMakeLists.txt new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-Ceres.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-Entwine.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-FPCFilter.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-GFlags.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-Hexer.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-LASzip.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-MvsTexturing.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-Obj2Tiles.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-OpenCV.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-OpenMVS.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-OpenSfM.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-PCL.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-PDAL.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-PyPopsift.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/External-Untwine.cmake new file: o/ODM/ODM-2.8.7/SuperBuild/cmake/ExternalProject-Setup.cmake new file: o/ODM/ODM-2.8.7/VERSION new file: o/ODM/ODM-2.8.7/code_of_conduct.md new file: o/ODM/ODM-2.8.7/configure.py new file: o/ODM/ODM-2.8.7/configure.sh new file: o/ODM/ODM-2.8.7/console.bat new file: o/ODM/ODM-2.8.7/contrib/blender/README.md new file: o/ODM/ODM-2.8.7/contrib/blender/common.py new file: o/ODM/ODM-2.8.7/contrib/blender/odm_photo.py new file: o/ODM/ODM-2.8.7/contrib/blender/odm_video.py new file: o/ODM/ODM-2.8.7/contrib/blender/photo_360.blend new file: o/ODM/ODM-2.8.7/contrib/blender/photo_vr.blend new file: o/ODM/ODM-2.8.7/contrib/grass/README.md new file: o/ODM/ODM-2.8.7/contrib/grass/odm_grass.py new file: o/ODM/ODM-2.8.7/contrib/mergepreview/README.md new file: o/ODM/ODM-2.8.7/contrib/mergepreview/mergepreview.py new file: o/ODM/ODM-2.8.7/contrib/ndvi/README.md new file: o/ODM/ODM-2.8.7/contrib/ndvi/agricultural_indices.py new file: o/ODM/ODM-2.8.7/contrib/ndvi/ndvi.py new file: o/ODM/ODM-2.8.7/contrib/ndvi/rename_sentera_agx710_multispectral_tif.py new file: o/ODM/ODM-2.8.7/contrib/orthorectify/README.md new file: o/ODM/ODM-2.8.7/contrib/orthorectify/orthorectify.py new file: o/ODM/ODM-2.8.7/contrib/orthorectify/run.sh new file: o/ODM/ODM-2.8.7/contrib/pc2dem/README.md new file: o/ODM/ODM-2.8.7/contrib/pc2dem/pc2dem.py new file: o/ODM/ODM-2.8.7/contrib/resize/README.md new file: o/ODM/ODM-2.8.7/contrib/resize/requirements.txt new file: o/ODM/ODM-2.8.7/contrib/resize/resize.py new file: o/ODM/ODM-2.8.7/contrib/shell/odm_exif2utm.sh new file: o/ODM/ODM-2.8.7/contrib/visveg/readme.md new file: o/ODM/ODM-2.8.7/contrib/visveg/vegind.py new file: o/ODM/ODM-2.8.7/docker/README new file: o/ODM/ODM-2.8.7/docker/g++ new file: o/ODM/ODM-2.8.7/docker/gcc new file: o/ODM/ODM-2.8.7/docs/issue_template.md new file: o/ODM/ODM-2.8.7/gpu.Dockerfile new file: o/ODM/ODM-2.8.7/innosetup.iss new file: o/ODM/ODM-2.8.7/licenses/libext_copyright.txt new file: o/ODM/ODM-2.8.7/licenses/libx11_copyright.txt new file: o/ODM/ODM-2.8.7/licenses/license.md new file: o/ODM/ODM-2.8.7/odm_docker_readme.txt new file: o/ODM/ODM-2.8.7/opendm/__init__.py new file: o/ODM/ODM-2.8.7/opendm/boundary.py new file: o/ODM/ODM-2.8.7/opendm/camera.py new file: o/ODM/ODM-2.8.7/opendm/cogeo.py new file: o/ODM/ODM-2.8.7/opendm/concurrency.py new file: o/ODM/ODM-2.8.7/opendm/config.py new file: o/ODM/ODM-2.8.7/opendm/context.py new file: o/ODM/ODM-2.8.7/opendm/cropper.py new file: o/ODM/ODM-2.8.7/opendm/cutline.py new file: o/ODM/ODM-2.8.7/opendm/dem/__init__.py new file: o/ODM/ODM-2.8.7/opendm/dem/commands.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/__init__.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/bounds/__init__.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/bounds/types.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/bounds/utils.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/extra_dimensions/__init__.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/extra_dimensions/dimension.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/extra_dimensions/distance_dimension.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/extra_dimensions/extended_dimension.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/extra_dimensions/partition_dimension.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/grid/__init__.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/grid/builder.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/io/__init__.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/io/las_io.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/partition/__init__.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/partition/one_partition.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/partition/partition_plan.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/partition/quad_partitions.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/partition/selector.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/partition/surrounding_partitions.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/point_cloud.py new file: o/ODM/ODM-2.8.7/opendm/dem/ground_rectification/rectify.py new file: o/ODM/ODM-2.8.7/opendm/dem/merge.py new file: o/ODM/ODM-2.8.7/opendm/dem/pdal.py new file: o/ODM/ODM-2.8.7/opendm/dem/utils.py new file: o/ODM/ODM-2.8.7/opendm/dls.py new file: o/ODM/ODM-2.8.7/opendm/entwine.py new file: o/ODM/ODM-2.8.7/opendm/gcp.py new file: o/ODM/ODM-2.8.7/opendm/geo.py new file: o/ODM/ODM-2.8.7/opendm/get_image_size.py new file: o/ODM/ODM-2.8.7/opendm/gpu.py new file: o/ODM/ODM-2.8.7/opendm/gsd.py new file: o/ODM/ODM-2.8.7/opendm/io.py new file: o/ODM/ODM-2.8.7/opendm/location.py new file: o/ODM/ODM-2.8.7/opendm/log.py new file: o/ODM/ODM-2.8.7/opendm/loghelpers.py new file: o/ODM/ODM-2.8.7/opendm/mesh.py new file: o/ODM/ODM-2.8.7/opendm/multispectral.py new file: o/ODM/ODM-2.8.7/opendm/nvm.py new file: o/ODM/ODM-2.8.7/opendm/ogctiles.py new file: o/ODM/ODM-2.8.7/opendm/orthophoto.py new file: o/ODM/ODM-2.8.7/opendm/osfm.py new file: o/ODM/ODM-2.8.7/opendm/photo.py new file: o/ODM/ODM-2.8.7/opendm/point_cloud.py new file: o/ODM/ODM-2.8.7/opendm/progress.py new file: o/ODM/ODM-2.8.7/opendm/pseudogeo.py new file: o/ODM/ODM-2.8.7/opendm/remote.py new file: o/ODM/ODM-2.8.7/opendm/report/dsm_gradient.png new file: o/ODM/ODM-2.8.7/opendm/report/overlap_color_map.txt new file: o/ODM/ODM-2.8.7/opendm/report/overlap_diagram_legend.png new file: o/ODM/ODM-2.8.7/opendm/rollingshutter.py new file: o/ODM/ODM-2.8.7/opendm/shots.py new file: o/ODM/ODM-2.8.7/opendm/system.py new file: o/ODM/ODM-2.8.7/opendm/thermal.py new file: o/ODM/ODM-2.8.7/opendm/thermal_tools/__init__.py new file: o/ODM/ODM-2.8.7/opendm/thermal_tools/dji_unpack.py new file: o/ODM/ODM-2.8.7/opendm/thermal_tools/flir_unpack.py new file: o/ODM/ODM-2.8.7/opendm/thermal_tools/thermal_utils.py new file: o/ODM/ODM-2.8.7/opendm/tiles/color_relief.txt new file: o/ODM/ODM-2.8.7/opendm/tiles/gdal2tiles.py new file: o/ODM/ODM-2.8.7/opendm/tiles/hsv_merge.py new file: o/ODM/ODM-2.8.7/opendm/tiles/tiler.py new file: o/ODM/ODM-2.8.7/opendm/types.py new file: o/ODM/ODM-2.8.7/opendm/utils.py new file: o/ODM/ODM-2.8.7/opendm/vendor/__init__.py new file: o/ODM/ODM-2.8.7/opendm/vendor/gdal_fillnodata.py new file: o/ODM/ODM-2.8.7/portable.Dockerfile new file: o/ODM/ODM-2.8.7/requirements.txt new file: o/ODM/ODM-2.8.7/run.bat new file: o/ODM/ODM-2.8.7/run.py new file: o/ODM/ODM-2.8.7/run.sh new file: o/ODM/ODM-2.8.7/snap/snapcraft.yaml new file: o/ODM/ODM-2.8.7/snap/snapcraft21.yaml new file: o/ODM/ODM-2.8.7/stages/__init__.py new file: o/ODM/ODM-2.8.7/stages/dataset.py new file: o/ODM/ODM-2.8.7/stages/mvstex.py new file: o/ODM/ODM-2.8.7/stages/odm_app.py new file: o/ODM/ODM-2.8.7/stages/odm_dem.py new file: o/ODM/ODM-2.8.7/stages/odm_filterpoints.py new file: o/ODM/ODM-2.8.7/stages/odm_georeferencing.py new file: o/ODM/ODM-2.8.7/stages/odm_meshing.py new file: o/ODM/ODM-2.8.7/stages/odm_orthophoto.py new file: o/ODM/ODM-2.8.7/stages/odm_postprocess.py new file: o/ODM/ODM-2.8.7/stages/odm_report.py new file: o/ODM/ODM-2.8.7/stages/openmvs.py new file: o/ODM/ODM-2.8.7/stages/run_opensfm.py new file: o/ODM/ODM-2.8.7/stages/splitmerge.py new file: o/ODM/ODM-2.8.7/start-dev-env.sh new file: o/ODM/ODM-2.8.7/test.sh new file: o/ODM/ODM-2.8.7/tests/assets/.gitignore new file: o/ODM/ODM-2.8.7/tests/assets/gcp_extras.txt new file: o/ODM/ODM-2.8.7/tests/assets/gcp_latlon_south.txt new file: o/ODM/ODM-2.8.7/tests/assets/gcp_latlon_valid.txt new file: o/ODM/ODM-2.8.7/tests/assets/gcp_michigan_feet_valid.txt new file: o/ODM/ODM-2.8.7/tests/assets/gcp_utm_north_valid.txt new file: o/ODM/ODM-2.8.7/tests/assets/images/DJI_0002.JPG new file: o/ODM/ODM-2.8.7/tests/assets/reconstruction.json new file: o/ODM/ODM-2.8.7/tests/assets/sample.json new file: o/ODM/ODM-2.8.7/tests/test_camera.py new file: o/ODM/ODM-2.8.7/tests/test_gcp.py new file: o/ODM/ODM-2.8.7/tests/test_osfm.py new file: o/ODM/ODM-2.8.7/tests/test_remote.py new file: o/ODM/ODM-2.8.7/tests/test_types.py new file: o/ODM/ODM-2.8.7/vcpkg-requirements.txt new file: o/ODM/ODM-2.8.7/win32env.bat new file: o/ODM/ODM-2.8.7/winrun.bat new file: o/ODM/v2.8.7.tar.gz new file: y/Yambo/Yambo-5.1.0-intel-2020a.eb new file: y/Yambo/Yambo-5.1.0-intel-2020a.eb.bak_20220715124556_61837 new file: y/Yambo/Yambo-5.1.0-intel-2021a.eb.old deleted: y/Yambo/Yambo-5.1.0-intel-2021a.eb
354 lines
13 KiB
Python
Executable File
354 lines
13 KiB
Python
Executable File
import os
|
|
import sys
|
|
import rasterio
|
|
import numpy
|
|
import math
|
|
import time
|
|
import shutil
|
|
from opendm.system import run
|
|
from opendm import point_cloud
|
|
from opendm import io
|
|
from opendm import system
|
|
from opendm.concurrency import get_max_memory, parallel_map
|
|
from scipy import ndimage
|
|
from datetime import datetime
|
|
from opendm.vendor.gdal_fillnodata import main as gdal_fillnodata
|
|
from opendm import log
|
|
try:
|
|
import Queue as queue
|
|
except:
|
|
import queue
|
|
import threading
|
|
|
|
from .ground_rectification.rectify import run_rectification
|
|
from . import pdal
|
|
|
|
try:
|
|
# GDAL >= 3.3
|
|
from osgeo_utils.gdal_proximity import main as gdal_proximity
|
|
except ModuleNotFoundError:
|
|
# GDAL <= 3.2
|
|
try:
|
|
from osgeo.utils.gdal_proximity import main as gdal_proximity
|
|
except:
|
|
pass
|
|
|
|
def classify(lasFile, scalar, slope, threshold, window, verbose=False):
|
|
start = datetime.now()
|
|
|
|
try:
|
|
pdal.run_pdaltranslate_smrf(lasFile, lasFile, scalar, slope, threshold, window, verbose)
|
|
except:
|
|
log.ODM_WARNING("Error creating classified file %s" % lasFile)
|
|
|
|
log.ODM_INFO('Created %s in %s' % (lasFile, datetime.now() - start))
|
|
return lasFile
|
|
|
|
def rectify(lasFile, debug=False, reclassify_threshold=5, min_area=750, min_points=500):
|
|
start = datetime.now()
|
|
|
|
try:
|
|
# Currently, no Python 2 lib that supports reading and writing LAZ, so we will do it manually until ODM is migrated to Python 3
|
|
# When migration is done, we can move to pylas and avoid using PDAL for conversion
|
|
tempLasFile = os.path.join(os.path.dirname(lasFile), 'tmp.las')
|
|
|
|
# Convert LAZ to LAS
|
|
cmd = [
|
|
'pdal',
|
|
'translate',
|
|
'-i %s' % lasFile,
|
|
'-o %s' % tempLasFile
|
|
]
|
|
system.run(' '.join(cmd))
|
|
|
|
log.ODM_INFO("Rectifying {} using with [reclassify threshold: {}, min area: {}, min points: {}]".format(lasFile, reclassify_threshold, min_area, min_points))
|
|
run_rectification(
|
|
input=tempLasFile, output=tempLasFile, debug=debug, \
|
|
reclassify_plan='median', reclassify_threshold=reclassify_threshold, \
|
|
extend_plan='surrounding', extend_grid_distance=5, \
|
|
min_area=min_area, min_points=min_points)
|
|
|
|
# Convert LAS to LAZ
|
|
cmd = [
|
|
'pdal',
|
|
'translate',
|
|
'-i %s' % tempLasFile,
|
|
'-o %s' % lasFile
|
|
]
|
|
system.run(' '.join(cmd))
|
|
os.remove(tempLasFile)
|
|
|
|
except Exception as e:
|
|
raise Exception("Error rectifying ground in file %s: %s" % (lasFile, str(e)))
|
|
|
|
log.ODM_INFO('Created %s in %s' % (lasFile, datetime.now() - start))
|
|
return lasFile
|
|
|
|
error = None
|
|
|
|
def create_dem(input_point_cloud, dem_type, output_type='max', radiuses=['0.56'], gapfill=True,
|
|
outdir='', resolution=0.1, max_workers=1, max_tile_size=4096,
|
|
verbose=False, decimation=None, keep_unfilled_copy=False,
|
|
apply_smoothing=True):
|
|
""" Create DEM from multiple radii, and optionally gapfill """
|
|
|
|
global error
|
|
error = None
|
|
|
|
start = datetime.now()
|
|
|
|
if not os.path.exists(outdir):
|
|
log.ODM_INFO("Creating %s" % outdir)
|
|
os.mkdir(outdir)
|
|
|
|
extent = point_cloud.get_extent(input_point_cloud)
|
|
log.ODM_INFO("Point cloud bounds are [minx: %s, maxx: %s] [miny: %s, maxy: %s]" % (extent['minx'], extent['maxx'], extent['miny'], extent['maxy']))
|
|
ext_width = extent['maxx'] - extent['minx']
|
|
ext_height = extent['maxy'] - extent['miny']
|
|
|
|
w, h = (int(math.ceil(ext_width / float(resolution))),
|
|
int(math.ceil(ext_height / float(resolution))))
|
|
|
|
# Set a floor, no matter the resolution parameter
|
|
# (sometimes a wrongly estimated scale of the model can cause the resolution
|
|
# to be set unrealistically low, causing errors)
|
|
RES_FLOOR = 64
|
|
if w < RES_FLOOR and h < RES_FLOOR:
|
|
prev_w, prev_h = w, h
|
|
|
|
if w >= h:
|
|
w, h = (RES_FLOOR, int(math.ceil(ext_height / ext_width * RES_FLOOR)))
|
|
else:
|
|
w, h = (int(math.ceil(ext_width / ext_height * RES_FLOOR)), RES_FLOOR)
|
|
|
|
floor_ratio = prev_w / float(w)
|
|
resolution *= floor_ratio
|
|
radiuses = [str(float(r) * floor_ratio) for r in radiuses]
|
|
|
|
log.ODM_WARNING("Really low resolution DEM requested %s will set floor at %s pixels. Resolution changed to %s. The scale of this reconstruction might be off." % ((prev_w, prev_h), RES_FLOOR, resolution))
|
|
|
|
final_dem_pixels = w * h
|
|
|
|
num_splits = int(max(1, math.ceil(math.log(math.ceil(final_dem_pixels / float(max_tile_size * max_tile_size)))/math.log(2))))
|
|
num_tiles = num_splits * num_splits
|
|
log.ODM_INFO("DEM resolution is %s, max tile size is %s, will split DEM generation into %s tiles" % ((h, w), max_tile_size, num_tiles))
|
|
|
|
tile_bounds_width = ext_width / float(num_splits)
|
|
tile_bounds_height = ext_height / float(num_splits)
|
|
|
|
tiles = []
|
|
|
|
for r in radiuses:
|
|
minx = extent['minx']
|
|
|
|
for x in range(num_splits):
|
|
miny = extent['miny']
|
|
if x == num_splits - 1:
|
|
maxx = extent['maxx']
|
|
else:
|
|
maxx = minx + tile_bounds_width
|
|
|
|
for y in range(num_splits):
|
|
if y == num_splits - 1:
|
|
maxy = extent['maxy']
|
|
else:
|
|
maxy = miny + tile_bounds_height
|
|
|
|
filename = os.path.join(os.path.abspath(outdir), '%s_r%s_x%s_y%s.tif' % (dem_type, r, x, y))
|
|
|
|
tiles.append({
|
|
'radius': r,
|
|
'bounds': {
|
|
'minx': minx,
|
|
'maxx': maxx,
|
|
'miny': miny,
|
|
'maxy': maxy
|
|
},
|
|
'filename': filename
|
|
})
|
|
|
|
miny = maxy
|
|
minx = maxx
|
|
|
|
# Sort tiles by increasing radius
|
|
tiles.sort(key=lambda t: float(t['radius']), reverse=True)
|
|
|
|
def process_tile(q):
|
|
log.ODM_INFO("Generating %s (%s, radius: %s, resolution: %s)" % (q['filename'], output_type, q['radius'], resolution))
|
|
|
|
d = pdal.json_gdal_base(q['filename'], output_type, q['radius'], resolution, q['bounds'])
|
|
|
|
if dem_type == 'dtm':
|
|
d = pdal.json_add_classification_filter(d, 2)
|
|
|
|
if decimation is not None:
|
|
d = pdal.json_add_decimation_filter(d, decimation)
|
|
|
|
pdal.json_add_readers(d, [input_point_cloud])
|
|
pdal.run_pipeline(d, verbose=verbose)
|
|
|
|
parallel_map(process_tile, tiles, max_workers)
|
|
|
|
output_file = "%s.tif" % dem_type
|
|
output_path = os.path.abspath(os.path.join(outdir, output_file))
|
|
|
|
# Verify tile results
|
|
for t in tiles:
|
|
if not os.path.exists(t['filename']):
|
|
raise Exception("Error creating %s, %s failed to be created" % (output_file, t['filename']))
|
|
|
|
# Create virtual raster
|
|
tiles_vrt_path = os.path.abspath(os.path.join(outdir, "tiles.vrt"))
|
|
tiles_file_list = os.path.abspath(os.path.join(outdir, "tiles_list.txt"))
|
|
with open(tiles_file_list, 'w') as f:
|
|
for t in tiles:
|
|
f.write(t['filename'] + '\n')
|
|
|
|
run('gdalbuildvrt -input_file_list "%s" "%s" ' % (tiles_file_list, tiles_vrt_path))
|
|
|
|
merged_vrt_path = os.path.abspath(os.path.join(outdir, "merged.vrt"))
|
|
geotiff_tmp_path = os.path.abspath(os.path.join(outdir, 'tiles.tmp.tif'))
|
|
geotiff_small_path = os.path.abspath(os.path.join(outdir, 'tiles.small.tif'))
|
|
geotiff_small_filled_path = os.path.abspath(os.path.join(outdir, 'tiles.small_filled.tif'))
|
|
geotiff_path = os.path.abspath(os.path.join(outdir, 'tiles.tif'))
|
|
|
|
# Build GeoTIFF
|
|
kwargs = {
|
|
'max_memory': get_max_memory(),
|
|
'threads': max_workers if max_workers else 'ALL_CPUS',
|
|
'tiles_vrt': tiles_vrt_path,
|
|
'merged_vrt': merged_vrt_path,
|
|
'geotiff': geotiff_path,
|
|
'geotiff_tmp': geotiff_tmp_path,
|
|
'geotiff_small': geotiff_small_path,
|
|
'geotiff_small_filled': geotiff_small_filled_path
|
|
}
|
|
|
|
if gapfill:
|
|
# Sometimes, for some reason gdal_fillnodata.py
|
|
# behaves strangely when reading data directly from a .VRT
|
|
# so we need to convert to GeoTIFF first.
|
|
run('gdal_translate '
|
|
'-co NUM_THREADS={threads} '
|
|
'-co BIGTIFF=IF_SAFER '
|
|
'--config GDAL_CACHEMAX {max_memory}% '
|
|
'"{tiles_vrt}" "{geotiff_tmp}"'.format(**kwargs))
|
|
|
|
# Scale to 10% size
|
|
run('gdal_translate '
|
|
'-co NUM_THREADS={threads} '
|
|
'-co BIGTIFF=IF_SAFER '
|
|
'--config GDAL_CACHEMAX {max_memory}% '
|
|
'-outsize 10% 0 '
|
|
'"{geotiff_tmp}" "{geotiff_small}"'.format(**kwargs))
|
|
|
|
# Fill scaled
|
|
gdal_fillnodata(['.',
|
|
'-co', 'NUM_THREADS=%s' % kwargs['threads'],
|
|
'-co', 'BIGTIFF=IF_SAFER',
|
|
'--config', 'GDAL_CACHE_MAX', str(kwargs['max_memory']) + '%',
|
|
'-b', '1',
|
|
'-of', 'GTiff',
|
|
kwargs['geotiff_small'], kwargs['geotiff_small_filled']])
|
|
|
|
# Merge filled scaled DEM with unfilled DEM using bilinear interpolation
|
|
run('gdalbuildvrt -resolution highest -r bilinear "%s" "%s" "%s"' % (merged_vrt_path, geotiff_small_filled_path, geotiff_tmp_path))
|
|
run('gdal_translate '
|
|
'-co NUM_THREADS={threads} '
|
|
'-co TILED=YES '
|
|
'-co BIGTIFF=IF_SAFER '
|
|
'-co COMPRESS=DEFLATE '
|
|
'--config GDAL_CACHEMAX {max_memory}% '
|
|
'"{merged_vrt}" "{geotiff}"'.format(**kwargs))
|
|
else:
|
|
run('gdal_translate '
|
|
'-co NUM_THREADS={threads} '
|
|
'-co TILED=YES '
|
|
'-co BIGTIFF=IF_SAFER '
|
|
'-co COMPRESS=DEFLATE '
|
|
'--config GDAL_CACHEMAX {max_memory}% '
|
|
'"{tiles_vrt}" "{geotiff}"'.format(**kwargs))
|
|
|
|
if apply_smoothing:
|
|
median_smoothing(geotiff_path, output_path)
|
|
os.remove(geotiff_path)
|
|
else:
|
|
os.replace(geotiff_path, output_path)
|
|
|
|
if os.path.exists(geotiff_tmp_path):
|
|
if not keep_unfilled_copy:
|
|
os.remove(geotiff_tmp_path)
|
|
else:
|
|
os.replace(geotiff_tmp_path, io.related_file_path(output_path, postfix=".unfilled"))
|
|
|
|
for cleanup_file in [tiles_vrt_path, tiles_file_list, merged_vrt_path, geotiff_small_path, geotiff_small_filled_path]:
|
|
if os.path.exists(cleanup_file): os.remove(cleanup_file)
|
|
for t in tiles:
|
|
if os.path.exists(t['filename']): os.remove(t['filename'])
|
|
|
|
log.ODM_INFO('Completed %s in %s' % (output_file, datetime.now() - start))
|
|
|
|
|
|
def compute_euclidean_map(geotiff_path, output_path, overwrite=False):
|
|
if not os.path.exists(geotiff_path):
|
|
log.ODM_WARNING("Cannot compute euclidean map (file does not exist: %s)" % geotiff_path)
|
|
return
|
|
|
|
nodata = -9999
|
|
with rasterio.open(geotiff_path) as f:
|
|
nodata = f.nodatavals[0]
|
|
|
|
if not os.path.exists(output_path) or overwrite:
|
|
log.ODM_INFO("Computing euclidean distance: %s" % output_path)
|
|
|
|
if gdal_proximity is not None:
|
|
try:
|
|
gdal_proximity(['gdal_proximity.py', geotiff_path, output_path, '-values', str(nodata)])
|
|
except Exception as e:
|
|
log.ODM_WARNING("Cannot compute euclidean distance: %s" % str(e))
|
|
|
|
if os.path.exists(output_path):
|
|
return output_path
|
|
else:
|
|
log.ODM_WARNING("Cannot compute euclidean distance file: %s" % output_path)
|
|
else:
|
|
log.ODM_WARNING("Cannot compute euclidean map, gdal_proximity is missing")
|
|
|
|
else:
|
|
log.ODM_INFO("Found a euclidean distance map: %s" % output_path)
|
|
return output_path
|
|
|
|
|
|
def median_smoothing(geotiff_path, output_path, smoothing_iterations=1):
|
|
""" Apply median smoothing """
|
|
start = datetime.now()
|
|
|
|
if not os.path.exists(geotiff_path):
|
|
raise Exception('File %s does not exist!' % geotiff_path)
|
|
|
|
log.ODM_INFO('Starting smoothing...')
|
|
|
|
with rasterio.open(geotiff_path) as img:
|
|
nodata = img.nodatavals[0]
|
|
dtype = img.dtypes[0]
|
|
arr = img.read()[0]
|
|
|
|
nodata_locs = arr == nodata
|
|
|
|
# Median filter (careful, changing the value 5 might require tweaking)
|
|
# the lines below. There's another numpy function that takes care of
|
|
# these edge cases, but it's slower.
|
|
for i in range(smoothing_iterations):
|
|
log.ODM_INFO("Smoothing iteration %s" % str(i + 1))
|
|
arr = ndimage.median_filter(arr, size=9, output=dtype, mode='nearest')
|
|
|
|
# Median filter leaves a bunch of zeros in nodata areas
|
|
arr[nodata_locs] = nodata
|
|
|
|
# write output
|
|
with rasterio.open(output_path, 'w', BIGTIFF="IF_SAFER", **img.profile) as imgout:
|
|
imgout.write(arr, 1)
|
|
|
|
log.ODM_INFO('Completed smoothing to create %s in %s' % (output_path, datetime.now() - start))
|
|
|
|
return output_path |