Allow upsampling and downsampling past computed zoom levels, nearest resampling for orthophoto

pull/768/head
Piero Toffanin 2019-12-10 14:47:17 -05:00
rodzic 02c24d744b
commit 60364dbc0b
2 zmienionych plików z 25 dodań i 15 usunięć

Wyświetl plik

@ -17,10 +17,13 @@ from .tasks import TaskNestedView
from rest_framework import exceptions
from rest_framework.response import Response
ZOOM_EXTRA_LEVELS = 2
def get_zoom_safe(src_dst):
minzoom, maxzoom = get_zooms(src_dst)
if maxzoom < minzoom:
maxzoom = minzoom
return minzoom, maxzoom
def get_tile_url(task, tile_type, query_params):
@ -113,8 +116,8 @@ class TileJson(TaskNestedView):
'version': '1.0.0',
'scheme': 'xyz',
'tiles': [get_tile_url(task, tile_type, self.request.query_params)],
'minzoom': minzoom,
'maxzoom': maxzoom,
'minzoom': minzoom - ZOOM_EXTRA_LEVELS,
'maxzoom': maxzoom + ZOOM_EXTRA_LEVELS,
'bounds': get_extent(task, tile_type).extent
})
@ -206,32 +209,34 @@ class Metadata(TaskNestedView):
if info['maxzoom'] < info['minzoom']:
info['maxzoom'] = info['minzoom']
info['maxzoom'] += ZOOM_EXTRA_LEVELS
info['minzoom'] -= ZOOM_EXTRA_LEVELS
return Response(info)
def get_elevation_tiles(elevation, url, x, y, z, tilesize, nodata):
def get_elevation_tiles(elevation, url, x, y, z, tilesize, nodata, resampling_method):
tile = np.full((tilesize * 3, tilesize * 3), nodata, dtype=elevation.dtype)
try:
left, _ = main.tile(url, x - 1, y, z, indexes=1, tilesize=tilesize, nodata=nodata)
left, _ = main.tile(url, x - 1, y, z, indexes=1, tilesize=tilesize, nodata=nodata, resampling_method=resampling_method)
tile[tilesize:tilesize*2,0:tilesize] = left
except TileOutsideBounds:
pass
try:
right, _ = main.tile(url, x + 1, y, z, indexes=1, tilesize=tilesize, nodata=nodata)
right, _ = main.tile(url, x + 1, y, z, indexes=1, tilesize=tilesize, nodata=nodata, resampling_method=resampling_method)
tile[tilesize:tilesize*2,tilesize*2:tilesize*3] = right
except TileOutsideBounds:
pass
try:
bottom, _ = main.tile(url, x, y + 1, z, indexes=1, tilesize=tilesize, nodata=nodata)
bottom, _ = main.tile(url, x, y + 1, z, indexes=1, tilesize=tilesize, nodata=nodata, resampling_method=resampling_method)
tile[tilesize*2:tilesize*3,tilesize:tilesize*2] = bottom
except TileOutsideBounds:
pass
try:
top, _ = main.tile(url, x, y - 1, z, indexes=1, tilesize=tilesize, nodata=nodata)
top, _ = main.tile(url, x, y - 1, z, indexes=1, tilesize=tilesize, nodata=nodata, resampling_method=resampling_method)
tile[0:tilesize,tilesize:tilesize*2] = top
except TileOutsideBounds:
pass
@ -276,6 +281,10 @@ class Tiles(TaskNestedView):
except ValueError as e:
raise exceptions.ValidationError(str(e))
resampling = "nearest"
if tile_type in ['dsm', 'dtm']:
resampling = "bilinear"
if tile_type in ['dsm', 'dtm'] and rescale is None:
rescale = "0,1000"
@ -299,17 +308,17 @@ class Tiles(TaskNestedView):
with rasterio.open(url) as src:
minzoom, maxzoom = get_zoom_safe(src)
if z < minzoom or z > maxzoom:
if z < minzoom - ZOOM_EXTRA_LEVELS or z > maxzoom + ZOOM_EXTRA_LEVELS:
raise exceptions.NotFound()
try:
if expr is not None:
tile, mask = expression(
url, x, y, z, expr=expr, tilesize=tilesize, nodata=nodata
url, x, y, z, expr=expr, tilesize=tilesize, nodata=nodata, resampling_method=resampling
)
else:
tile, mask = main.tile(
url, x, y, z, indexes=indexes, tilesize=tilesize, nodata=nodata
url, x, y, z, indexes=indexes, tilesize=tilesize, nodata=nodata, resampling_method=resampling
)
except TileOutsideBounds:
raise exceptions.NotFound("Outside of bounds")
@ -346,7 +355,7 @@ class Tiles(TaskNestedView):
# Hillshading is not a local tile operation and
# requires neighbor tiles to be rendered seamlessly
elevation = get_elevation_tiles(tile[0], url, x, y, z, tilesize, nodata)
elevation = get_elevation_tiles(tile[0], url, x, y, z, tilesize, nodata, resampling)
intensity = ls.hillshade(elevation, dx=dx, dy=dy, vert_exag=hillshade)
intensity = intensity[tilesize:tilesize*2,tilesize:tilesize*2]

Wyświetl plik

@ -18,6 +18,7 @@ from django.utils import timezone
from app import pending_actions
from app.api.formulas import algos, get_camera_filters_for
from app.api.tiler import ZOOM_EXTRA_LEVELS
from app.cogeo import valid_cogeo
from app.models import Project, Task, ImageUpload
from app.models.task import task_directory_path, full_task_directory_path, TaskInterruptedException
@ -388,8 +389,8 @@ class TestApiTask(BootTransactionTestCase):
for f in fields:
self.assertTrue(f in metadata)
self.assertEqual(metadata['minzoom'], 17)
self.assertEqual(metadata['maxzoom'], 17)
self.assertEqual(metadata['minzoom'], 17 - ZOOM_EXTRA_LEVELS)
self.assertEqual(metadata['maxzoom'], 17 + ZOOM_EXTRA_LEVELS)
# Colormaps and algorithms should be empty lists
self.assertEqual(metadata['algorithms'], [])
@ -505,9 +506,9 @@ class TestApiTask(BootTransactionTestCase):
self.assertEqual(res.status_code, status.HTTP_404_NOT_FOUND)
# Cannot access zoom levels outside of the allowed zoom levels
res = client.get("/api/projects/{}/tasks/{}/orthophoto/tiles/16/32042/46185.png".format(project.id, task.id))
res = client.get("/api/projects/{}/tasks/{}/orthophoto/tiles/14/32042/46185.png".format(project.id, task.id))
self.assertEqual(res.status_code, status.HTTP_404_NOT_FOUND)
res = client.get("/api/projects/{}/tasks/{}/orthophoto/tiles/18/32042/46185.png".format(project.id, task.id))
res = client.get("/api/projects/{}/tasks/{}/orthophoto/tiles/20/32042/46185.png".format(project.id, task.id))
self.assertEqual(res.status_code, status.HTTP_404_NOT_FOUND)
# Can access hillshade, formulas, bands, rescale, color_map