基于large-image(和GDAL)构建的Django动态瓦片服务器
项目描述
🩻 🗺️ django-large-image
django-large-image
是 large-image
的抽象,用于与 django-rest-framework
一起使用,提供端点视图集混入,以便在Django中处理大型图像(云优化GeoTiffs或医学图像格式)。这里提供的动态瓦片服务器防止了对大图像进行预处理以生成瓦片集以用于在滑块地图上交互式查看的需求。在底层,large-image应用操作(缩放、重投影、图像编码)以实时创建图像瓦片。
2022年云原生地理空间推广活动闪电演讲 |
---|
在此查看幻灯片 |
目录
ℹ️ 概述
本包通过提供一组抽象的混合API视图集类,将Kitware的large-image引入Django,这些类将处理瓦片服务、从图像中获取元数据和提取感兴趣区域。
django-large-image
是一个可安装的Django应用,包含一些可以混合到Django项目(或应用)的drf-based视图集中的类,以提供开箱即用的瓦片服务端点。值得注意的是,django-large-image
专门设计用于与FileField
接口一起工作,开发工作针对Kitware的S3FileField
进行了定制。GeoDjango的GDALRaster
也可以通过在get_path()
重写中返回GDALRaster.name
来使用。
此包包含用于使用CesiumJS渲染地理空间图像瓦片和GeoJS渲染非地理空间图像瓦片的预制作HTML模板。
基于large-image(和GDAL)构建的Django动态瓦片服务器
🤝 支持
django-large-image
和支持的large-image
库由Kitware, Inc.的数据与分析团队开发和维护。我们在地理空间和医疗领域都处理大量图像数据。如果您对这些技术有疑问,或者您想讨论自己的地理空间和医疗图像问题,了解我们如何帮助您,请通过kitware@kitware.com联系。我们期待与您的对话!
🌟 功能
丰富的RESTful端点,可从大型图像格式中提取信息
- 图像元数据(《/info/metadata》,《/info/metadata_internal》)
- 瓦片服务(《/tiles/{z}/{x}/{y}.png?projection=EPSG:3857》)
- 区域提取(《/data/region.tif?left=v&right=v&top=v&bottom=v》)
- 图像缩略图(《/data/thumbnail.png》)
- 单个像素(《/data/pixel?left=v&top=v》)
- 波段直方图(《/data/histogram》)
支持任何存储后端
- 支持Django的
FileField
- 支持
S3FileField
- 自定义处理数据访问的方法(重写
get_path
) - 支持GDAL的虚拟文件系统,适用于
s3://
、ftp://
等URL
杂项
- 用于查看图像瓦片的Admin界面小部件。
- 缓存
- 图像瓦片和缩略图被缓存,以防止在多个请求中重新创建这些数据
- 利用Django缓存框架。使用
LARGE_IMAGE_CACHE_NAME
设置指定要使用的命名缓存。
- 易于扩展的SSR模板,用于使用CesiumJS和GeoJS查看瓦片
- OpenAPI规范
OpenAPI文档 | 瓦片端点 |
---|---|
⬇️ 安装
默认情况下,django-large-image
仅依赖于核心large-image
模块,但您需要large-image-source-*
模块才能使其工作。我们的大多数用户可能希望处理地理空间图像,所以我们重点关注large-image-source-gdal
和``large-image-source-rasterio案例,但值得注意的是,`large-image`具有针对各种图像格式的源模块(例如,显微镜的医学图像格式)。
有关详细信息,请参阅large-image
的安装说明。
🎡 pip
Rasterio
pip install \
django-large-image \
'large-image[rasterio,pil]>=1.22'
GDAL
提示:安装GDAL非常困难,因此在我们Kitware,我们提供了预构建的Python wheel,其中包含GDAL二进制文件,以便在生产环境中轻松安装到Linux环境。要安装我们的GDAL wheel,请使用:pip install --find-links https://girder.github.io/large_image_wheels GDAL
pip install \
--find-links https://girder.github.io/large_image_wheels \
django-large-image \
'large-image[gdal,pil]>=1.16.2'
🐍 Conda
或者使用 conda
安装
conda install -c conda-forge django-large-image large-image-source-rasterio
conda install -c conda-forge django-large-image large-image-source-gdal
🚀 使用方法
只需安装应用程序并将其中一个混合类混入现有的 django-rest-framework
视图集。
# settings.py
INSTALLED_APPS = [
...,
'django_large_image',
]
以下是我们提供的混合类及其用例
LargeImageMixin
:用于标准、非详细ViewSet
。用户必须实现get_path()
LargeImageDetailMixin
:用于像GenericViewSet
这样的详细视图集。用户必须实现get_path()
LargeImageFileDetailMixin
:(最常用)用于像GenericViewSet
这样的详细视图集,其中关联的模型有一个存储图像数据的FileField
。LargeImageVSIFileDetailMixin
:(地理空间)用于像GenericViewSet
这样的详细视图集,其中关联的模型有一个存储图像数据的FileField
,这些数据旨在使用GDAL/rasterio读取。这将通过GDAL的虚拟文件系统接口(VSI路径)访问数据。
大多数用户将想要使用 LargeImageFileDetailMixin
,因此以下示例演示如何使用它
将 FILE_FIELD_NAME
指定为存储在关联模型中图像数据的 FileField
的字符串名称。
# viewsets.py
from rest_framework import viewsets
from django_large_image.rest import LargeImageFileDetailMixin
class MyModelViewSet(viewsets.GenericViewSet, LargeImageFileDetailMixin):
... # configuration for your model's viewset
FILE_FIELD_NAME = 'field_name'
# urls.py
from django.urls import include, path
from rest_framework.routers import SimpleRouter
from myapp.viewsets import MyModelViewSet
router = SimpleRouter(trailing_slash=False)
router.register(r'api/my-model', MyModelViewSet)
urlpatterns = [
# Additional, standalone URLs from django-large-image
path('', include('django_large_image.urls')),
] + router.urls
就是这样!
📝 示例代码
要使用此处提供的混合类,请将 django_large_image
添加到Django项目的 INSTALLED_APPS
,然后在Django项目中创建一个模型、序列化器和视图集,如下所示
# models.py
from django.db import models
from rest_framework import serializers
class ImageFile(models.Model):
name = models.TextField()
file = models.FileField()
class ImageFileSerializer(serializers.ModelSerializer):
class Meta:
model = ImageFile
fields = '__all__'
# admin.py
from django.contrib import admin
from example.core.models import ImageFile
@admin.register(ImageFile)
class ImageFileAdmin(admin.ModelAdmin):
list_display = ('pk', 'name')
然后创建视图集,混合使用 django-large-image
视图集类
# viewsets.py
from example.core import models
from rest_framework import mixins, viewsets
from django_large_image.rest import LargeImageFileDetailMixin
class ImageFileDetailViewSet(
mixins.ListModelMixin,
viewsets.GenericViewSet,
LargeImageFileDetailMixin,
):
queryset = models.ImageFile.objects.all()
serializer_class = models.ImageFileSerializer
# for `django-large-image`: the name of the image FileField on your model
FILE_FIELD_NAME = 'file'
然后注册URL
# urls.py
from django.urls import include, path
from example.core.viewsets import ImageFileDetailViewSet
from rest_framework.routers import SimpleRouter
router = SimpleRouter(trailing_slash=False)
router.register(r'api/image-file', ImageFileDetailViewSet)
urlpatterns = [
# Additional, standalone URLs from django-large-image
path('', include('django_large_image.urls')),
] + router.urls
(可选)您还可以为模型使用管理小部件
<!-- templates/admin/myapp/imagefile/change_form.html -->
{% extends "admin/change_form.html" %}
{% block after_field_sets %}
<script>
var baseEndpoint = 'api/image-file';
</script>
{% include 'admin/django_large_image/_include/geojs.html' %}
{% endblock %}
请注意,本存储库中的 project/
目录中的示例Django项目显示了如何在 girder-4
项目中使用 django-large-image
。
🛠️ 自定义
混合类是模块化设计的,并且可以根据您的项目需求进行子类化。虽然提供的 LargeImageFileDetailMixin
处理 FileField
-接口,但您可以轻松扩展其基类 LargeImageDetailMixin
,以处理详细视图集中任何数据存储机制。
在以下示例中,我们演示了如何从存储 s3://
或 https://
URL的模型中使用GDAL兼容的VSI路径。
# models.py
from django.db import models
from rest_framework import serializers
class URLImageFile(models.Model):
name = models.TextField()
url = models.TextField()
class URLImageFileSerializer(serializers.ModelSerializer):
class Meta:
model = URLImageFile
fields = '__all__'
# admin.py
from django.contrib import admin
from example.core.models import URLImageFile
@admin.register(URLImageFile)
class URLImageFileAdmin(admin.ModelAdmin):
list_display = ('pk', 'name')
# viewsets.py
from example.core import models
from rest_framework import mixins, viewsets
from django_large_image.rest import LargeImageDetailMixin
from django_large_image.utilities import make_vsi
class URLLargeImageMixin(LargeImageDetailMixin):
def get_path(self, request, pk=None):
object = self.get_object()
return make_vsi(object.url)
class URLImageFileDetailViewSet(
mixins.ListModelMixin,
viewsets.GenericViewSet,
URLLargeImageMixin,
):
queryset = models.URLImageFile.objects.all()
serializer_class = models.URLImageFileSerializer
这是一张好的测试图像:[链接](https://oin-hotosm.s3.amazonaws.com/59c66c5223c8440011d7b1e4/0/7ad397c0-bba2-4f98-a08a-931ec3a6e943.tif)
🥸 非详细视图集
LargeImageMixin
为非详细视图集提供混合接口(不需要关联的模型或主键)。如果您视图集有自定义逻辑来检索所需数据,这可能特别有用。
例如,您可能需要一个视图集,该视图集将数据路径作为请求查询参数中的URL获取。为此,您可以创建一个带有 LargeImageMixin
的标准 ViewSet,如下所示
# viewsets.py
from rest_framework import viewsets
from rest_framework.exceptions import ValidationError
from django_large_image.rest import LargeImageMixin
from django_large_image.utilities import make_vsi
class URLLargeImageViewSet(viewsets.ViewSet, LargeImageMixin):
def get_path(self, request, pk=None):
try:
url = request.query_params.get('url')
except KeyError:
raise ValidationError('url must be defined as a query parameter.')
return make_vsi(url)
🪄 样式
django-large-image
的动态瓦片服务支持波段样式,并从多个帧和/或波段创建复合图像。这意味着您可以从多光谱影像轻松创建假彩色图像。
django-large-image
有两种样式模式
- 一个简单的界面,使用多个查询参数对单通道进行着色。这些是文档化的OpenAPI查询参数。
使用Matplotlib着色方案查看单个波段
var thumbnailUrl = `http://localhost:8000/api/image-file/${imageId}/data/thumbnail.png?band=3&palette=viridis&min=50&max=250`;
- 一个复杂的规范,用于在帧和波段之间进行样式化,以使用 由
large-image
定义的JSON规范 创建复合图像。
从源图像的多个波段创建假彩色图像
// See https://girder.github.io/large_image/tilesource_options.html#style
var style = {
bands: [
{band: 5, palette: ['#000', '#f00']}, // red
{band: 3, palette: ['#000', '#0f0']}, // green
{band: 2, palette: ['#000', '#00f']} // blue
]
};
var styleEncoded = encodeURIComponent(JSON.stringify(style))
var thumbnailUrl = `http://localhost:8000/api/image-file/${imageId}/data/thumbnail.png?style=${styleEncoded}`;
☁️ 将图像转换为金字塔Tiff(COGs)
安装 large_image_converter
并运行以下命令
import large_image_converter
large_image_converter.convert(input_path, output_path)
就这么简单!该功能的默认参数会将地理空间栅格转换为云优化地理Tiff(COGs),将非地理空间图像转换为金字塔Tiff格式。
在应用程序中有一个将图像从模型转换为Celery任务的例子是很常见的。这是一个起点
import os
from example.core import models
from celery import shared_task
import large_image_converter # requires large-image-source-gdal
@shared_task
def task_convert_cog(my_model_pk):
image_file = models.ImageFile.objects.get(pk=my_model_pk)
input_path = image_file.file.name # TODO: get full path to file on disk
with tempfile.TemporaryDirectory() as tmpdir:
output_path = os.path.join(tmpdir, 'converted.tiff')
large_image_converter.convert(input_path, output_path)
# Do something with converted tiff file at `output_path`
...
如果使用基于 rasterio
的源模块,我们推荐使用 rio-cogeo
而不是 large_image_converter
。
与django-raster一起使用
django-raster
是在 Django 中存储地理空间栅格数据的热门选择。django-large-image
与 django-raster
兼容良好,提供了动态瓦片服务和其他附加端点。
请在此处查看演示项目:https://github.com/ResonantGeoData/django-raster-demo 并在有关 django-raster
的使用提出任何问题。
演示应用
在 demo/
目录中有一个纯Django项目,并且该应用程序作为一个独立的Docker镜像发布,任何人都可以尝试。
docker run -it -p 8000:8000 -v dli_demo_data:/opt/django-project/data ghcr.io/girder/django-large-image-demo:latest
项目详情
下载文件
下载适合您平台文件的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。