kopia lustrzana https://github.com/OpenDroneMap/WebODM
Hillshading working
rodzic
176672cf10
commit
dd3b413401
|
@ -20,7 +20,7 @@ from rio_tiler.io import COGReader
|
||||||
from rio_tiler.errors import InvalidColorMapName
|
from rio_tiler.errors import InvalidColorMapName
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from .custom_colormaps_helper import custom_colormaps
|
from .custom_colormaps_helper import custom_colormaps
|
||||||
from app.raster_utils import export_raster, extension_for_export_format
|
from app.raster_utils import export_raster, extension_for_export_format, ZOOM_EXTRA_LEVELS
|
||||||
from .hsvblend import hsv_blend
|
from .hsvblend import hsv_blend
|
||||||
from .hillshade import LightSource
|
from .hillshade import LightSource
|
||||||
from .formulas import lookup_formula, get_algorithm_list
|
from .formulas import lookup_formula, get_algorithm_list
|
||||||
|
@ -30,11 +30,11 @@ from rest_framework.response import Response
|
||||||
from worker.tasks import export_raster
|
from worker.tasks import export_raster
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
ZOOM_EXTRA_LEVELS = 3
|
|
||||||
|
|
||||||
for custom_colormap in custom_colormaps:
|
for custom_colormap in custom_colormaps:
|
||||||
colormap = colormap.register(custom_colormap)
|
colormap = colormap.register(custom_colormap)
|
||||||
|
|
||||||
|
|
||||||
def get_zoom_safe(src_dst):
|
def get_zoom_safe(src_dst):
|
||||||
minzoom, maxzoom = src_dst.spatial_info["minzoom"], src_dst.spatial_info["maxzoom"]
|
minzoom, maxzoom = src_dst.spatial_info["minzoom"], src_dst.spatial_info["maxzoom"]
|
||||||
if maxzoom < minzoom:
|
if maxzoom < minzoom:
|
||||||
|
@ -517,6 +517,14 @@ class Export(TaskNestedView):
|
||||||
rescale = list(map(float, rescale.split(",")))
|
rescale = list(map(float, rescale.split(",")))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise exception.ValidationError(_("Invalid rescale value: %(value)") % {'value': rescale})
|
raise exception.ValidationError(_("Invalid rescale value: %(value)") % {'value': rescale})
|
||||||
|
|
||||||
|
if hillshade is not None:
|
||||||
|
try:
|
||||||
|
hillshade = float(hillshade)
|
||||||
|
if hillshade < 0:
|
||||||
|
raise Exception("Hillshade must be > 0")
|
||||||
|
except:
|
||||||
|
raise exception.ValidationError(_("Invalid hillshade value: %(value)") % {'value': hillshade})
|
||||||
|
|
||||||
url = get_raster_path(task, asset_type)
|
url = get_raster_path(task, asset_type)
|
||||||
|
|
||||||
|
@ -535,5 +543,11 @@ class Export(TaskNestedView):
|
||||||
if export_format == 'gtiff' and (epsg == task.epsg or epsg is None) and expr is None:
|
if export_format == 'gtiff' and (epsg == task.epsg or epsg is None) and expr is None:
|
||||||
return Response({'url': '/api/projects/{}/tasks/{}/download/{}.tif'.format(task.project.id, task.id, asset_type), 'filename': filename})
|
return Response({'url': '/api/projects/{}/tasks/{}/download/{}.tif'.format(task.project.id, task.id, asset_type), 'filename': filename})
|
||||||
else:
|
else:
|
||||||
celery_task_id = export_raster.delay(url, epsg=epsg, expression=expr, format=export_format, rescale=rescale, color_map=color_map).task_id
|
celery_task_id = export_raster.delay(url, epsg=epsg,
|
||||||
|
expression=expr,
|
||||||
|
format=export_format,
|
||||||
|
rescale=rescale,
|
||||||
|
color_map=color_map,
|
||||||
|
hillshade=hillshade,
|
||||||
|
dem=asset_type in ['dsm', 'dtm']).task_id
|
||||||
return Response({'celery_task_id': celery_task_id, 'filename': filename})
|
return Response({'celery_task_id': celery_task_id, 'filename': filename})
|
||||||
|
|
|
@ -7,11 +7,15 @@ from rasterio.enums import ColorInterp
|
||||||
from rio_tiler.utils import has_alpha_band, linear_rescale
|
from rio_tiler.utils import has_alpha_band, linear_rescale
|
||||||
from rio_tiler.colormap import cmap as colormap, apply_cmap
|
from rio_tiler.colormap import cmap as colormap, apply_cmap
|
||||||
from rio_tiler.errors import InvalidColorMapName
|
from rio_tiler.errors import InvalidColorMapName
|
||||||
|
from app.api.hsvblend import hsv_blend
|
||||||
|
from app.api.hillshade import LightSource
|
||||||
from rasterio.warp import calculate_default_transform, reproject, Resampling
|
from rasterio.warp import calculate_default_transform, reproject, Resampling
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger('app.logger')
|
logger = logging.getLogger('app.logger')
|
||||||
|
|
||||||
|
ZOOM_EXTRA_LEVELS = 3
|
||||||
|
|
||||||
def extension_for_export_format(export_format):
|
def extension_for_export_format(export_format):
|
||||||
extensions = {
|
extensions = {
|
||||||
'gtiff': 'tif',
|
'gtiff': 'tif',
|
||||||
|
@ -27,6 +31,8 @@ def export_raster(input, output, **opts):
|
||||||
export_format = opts.get('format')
|
export_format = opts.get('format')
|
||||||
rescale = opts.get('rescale')
|
rescale = opts.get('rescale')
|
||||||
color_map = opts.get('color_map')
|
color_map = opts.get('color_map')
|
||||||
|
hillshade = opts.get('hillshade')
|
||||||
|
dem = opts.get('dem')
|
||||||
|
|
||||||
with rasterio.open(input) as src:
|
with rasterio.open(input) as src:
|
||||||
profile = src.meta.copy()
|
profile = src.meta.copy()
|
||||||
|
@ -41,18 +47,19 @@ def export_raster(input, output, **opts):
|
||||||
if export_format == "jpg":
|
if export_format == "jpg":
|
||||||
driver = "JPEG"
|
driver = "JPEG"
|
||||||
profile.update(quality=70)
|
profile.update(quality=70)
|
||||||
max_bands = 3
|
band_count = 3
|
||||||
with_alpha = False
|
with_alpha = False
|
||||||
rgb = True
|
rgb = True
|
||||||
elif export_format == "png":
|
elif export_format == "png":
|
||||||
driver = "PNG"
|
driver = "PNG"
|
||||||
max_bands = 3
|
band_count = 4
|
||||||
rgb = True
|
rgb = True
|
||||||
elif export_format == "gtiff-rgb":
|
elif export_format == "gtiff-rgb":
|
||||||
max_bands = 3
|
band_count = 4
|
||||||
rgb = True
|
rgb = True
|
||||||
|
else:
|
||||||
band_count = min(src.count, max_bands + (1 if with_alpha else 0))
|
band_count = src.count
|
||||||
|
|
||||||
if rgb and rescale is None:
|
if rgb and rescale is None:
|
||||||
rescale = [0,255]
|
rescale = [0,255]
|
||||||
|
|
||||||
|
@ -82,7 +89,7 @@ def export_raster(input, output, **opts):
|
||||||
cmap = colormap.get(color_map)
|
cmap = colormap.get(color_map)
|
||||||
except InvalidColorMapName:
|
except InvalidColorMapName:
|
||||||
logger.warning("Invalid colormap {}".format(color_map))
|
logger.warning("Invalid colormap {}".format(color_map))
|
||||||
|
|
||||||
|
|
||||||
def process(arr, skip_rescale=False, skip_alpha=False, skip_type=False):
|
def process(arr, skip_rescale=False, skip_alpha=False, skip_type=False):
|
||||||
if not skip_rescale and rescale is not None:
|
if not skip_rescale and rescale is not None:
|
||||||
|
@ -98,6 +105,9 @@ def export_raster(input, output, **opts):
|
||||||
if rgb:
|
if rgb:
|
||||||
profile.update(dtype=rasterio.uint8)
|
profile.update(dtype=rasterio.uint8)
|
||||||
|
|
||||||
|
if dem and rgb and profile.get('nodata') is not None:
|
||||||
|
profile.update(nodata=None)
|
||||||
|
|
||||||
# Define write band function
|
# Define write band function
|
||||||
# Reprojection needed?
|
# Reprojection needed?
|
||||||
if src.crs is not None and epsg is not None and src.crs.to_epsg() != epsg:
|
if src.crs is not None and epsg is not None and src.crs.to_epsg() != epsg:
|
||||||
|
@ -168,6 +178,37 @@ def export_raster(input, output, **opts):
|
||||||
if rgb and cmap is not None:
|
if rgb and cmap is not None:
|
||||||
rgb_data, _ = apply_cmap(process(arr, skip_alpha=True), cmap)
|
rgb_data, _ = apply_cmap(process(arr, skip_alpha=True), cmap)
|
||||||
|
|
||||||
|
band_num = 1
|
||||||
|
for b in rgb_data:
|
||||||
|
write_band(process(b, skip_rescale=True), dst, band_num)
|
||||||
|
band_num += 1
|
||||||
|
|
||||||
|
if with_alpha:
|
||||||
|
write_band(mask, dst, band_num)
|
||||||
|
else:
|
||||||
|
# Raw
|
||||||
|
write_band(process(arr)[0], dst, 1)
|
||||||
|
elif dem:
|
||||||
|
# Apply hillshading, colormaps to elevation
|
||||||
|
with rasterio.open(output, 'w', **profile) as dst:
|
||||||
|
arr = src.read()
|
||||||
|
|
||||||
|
intensity = None
|
||||||
|
if hillshade is not None and hillshade > 0:
|
||||||
|
delta_scale = (ZOOM_EXTRA_LEVELS + 1) * 4
|
||||||
|
dx = src.meta["transform"][0] * delta_scale
|
||||||
|
dy = -src.meta["transform"][4] * delta_scale
|
||||||
|
ls = LightSource(azdeg=315, altdeg=45)
|
||||||
|
intensity = ls.hillshade(arr[0], dx=dx, dy=dy, vert_exag=hillshade)
|
||||||
|
intensity = intensity * 255.0
|
||||||
|
|
||||||
|
# Apply colormap?
|
||||||
|
if rgb and cmap is not None:
|
||||||
|
rgb_data, _ = apply_cmap(process(arr, skip_alpha=True), cmap)
|
||||||
|
|
||||||
|
if intensity is not None:
|
||||||
|
rgb_data = hsv_blend(rgb_data, intensity)
|
||||||
|
|
||||||
band_num = 1
|
band_num = 1
|
||||||
for b in rgb_data:
|
for b in rgb_data:
|
||||||
write_band(process(b, skip_rescale=True), dst, band_num)
|
write_band(process(b, skip_rescale=True), dst, band_num)
|
||||||
|
|
Ładowanie…
Reference in New Issue