跳转到主要内容

基于large-image(和GDAL)构建的Django动态瓦片服务器

项目描述

🩻 🗺️ django-large-image

Made by Kitware PyPI conda-forge codecov Tests

django-large-imagelarge-image 的抽象,用于与 django-rest-framework 一起使用,提供端点视图集混入,以便在Django中处理大型图像(云优化GeoTiffs或医学图像格式)。这里提供的动态瓦片服务器防止了对大图像进行预处理以生成瓦片集以用于在滑块地图上交互式查看的需求。在底层,large-image应用操作(缩放、重投影、图像编码)以实时创建图像瓦片。

2022年云原生地理空间推广活动闪电演讲
outreach event video
在此查看幻灯片

目录


ℹ️ 概述

本包通过提供一组抽象的混合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动态瓦片服务器

🤝 支持

Kitware

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文档 瓦片端点
swagger-spec tiles-spec

⬇️ 安装

默认情况下,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 有两种样式模式

  1. 一个简单的界面,使用多个查询参数对单通道进行着色。这些是文档化的OpenAPI查询参数。

使用Matplotlib着色方案查看单个波段

var thumbnailUrl = `http://localhost:8000/api/image-file/${imageId}/data/thumbnail.png?band=3&palette=viridis&min=50&max=250`;
  1. 一个复杂的规范,用于在帧和波段之间进行样式化,以使用 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-imagedjango-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

项目详情


下载文件

下载适合您平台文件的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分布

django-large-image-0.10.0.tar.gz (949.9 kB 查看哈希值)

上传时间

构建分布

django_large_image-0.10.0-py3-none-any.whl (956.5 kB 查看哈希值)

上传时间 Python 3

支持者

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面