Adapting our large-image toolkit to Django for solving geospatial and medical image challenges on the web
At Kitware, we have been building a suite of geospatial data cataloging, visualization, and analysis tools in Django under the Resonant GeoData brand for the past two years. We are excited to introduce a new tool from this effort for dynamic tile serving of geospatial and medical images: django-large-image.
We debuted django-large-image to the world during the 2022 Cloud-Native Geospatial Outreach Event with a video recording and slides. django-large-image is a Django app with an extensible interface for building web applications focused on dynamic tile serving of large image formats. It is built on django-rest-framework’s viewset class interface and Kitware’s large-image package. It provides Django projects with a dynamic tile server preventing the need for preprocessing large images into tile sets or deploying an external tiling service for viewing images interactively on a slippy-map interface.
Read on for the story and motivation behind django-large-image.
Visualizing Geospatial Images in Your Web-Browser
A core part of Kitware’s Resonant GeoData platform is working to ingest cloud-hosted geospatial and georeferenced datasets – namely satellite imagery. Resonant GeoData not only indexes these data into a searchable catalog but also dynamically serves the data to our customers for processing and visualization. While Resonant GeoData is a broader platform of geospatial data services in Django, in this post, we will focus on the path we took to create a standalone library to dynamically serve tiles with Django from large, remotely-hosted images for visualization in web browsers.
We wanted to enable users of Resonant GeoData to interactively visualize satellite imagery in a dynamic manner (rescaling, color mapping, etc.).This allows them to gain insights into the data for quality control analysis and to find the right dataset to download for processing. We also wanted users to be able to perform this analysis within the web application as they are sorting through the search results from Resonant GeoData’s catalog API.
To improve how users interact with search results, we sought a way to dynamically fetch the cloud-hosted imagery and visualize the large images in a web client. Due to the vast amount of data in the catalog, pre-processing the imagery into tilesets or converting the data to Cloud Optimized GeoTiffs were not viable solutions. To avoid duplicating large volumes of data and provide a way for our customers to be able to rapidly visualize cloud-hosted imagery, we needed to provide a dynamic tile server.
In traditional static tile serving, raster images are rescaled, reprojected, and split into tiles (often 256 by 256 pixels in size) at various zoom levels. Then, a map tile viewer requests those pre-existing image tiles and streams them to the browser efficiently. On the other hand, dynamic tile serving is a way of performing each of those tasks on the fly, avoiding the need for pre-processing large images into tilesets. Dynamic tile serving further enables a user to adjust visualization parameters on demand (e.g., color mapping to create false-color images of user-defined bands), which would not be efficient with statically pre-processed tilesets.
Since Resonant GeoData uses Django with PostGIS for its backing database, we were thrilled to find the GeoDjango contrib module and django-raster Django app. They had a clean interface to GDAL (Geospatial Data Abstraction Library, the de facto standard library for handling geospatial data formats) for storing raster imagery and performing tile serving. The GeoDjango extension provides Django model fields for OGC geometries and raster data which are utilized in django-raster to provide a high-level interface for storing raster data. Unfortunately, these technologies come with a few limitations that ultimately led us toward another solution:
- The raster data must be stored/referenced in PostGIS. We need flexibility in how and where the data are stored and we want to make sure that our Django projections have the flexibility to use any database backend.
- The data must be stored and served in a fixed projection. We need to support vast catalogs of data with arbitrary projections.
- Django-raster pre-generates static tiles for each raster dataset. We have vast collections of data and it would be too expensive to pre-generate tiles for every raster.
Our customers often require flexibility in data storage, want to avoid vendor lock-in with PostGIS, and are looking to minimize the data storage footprint while handling a variety of image formats (single or multi-band) in any projection. Considering the limitations, we decided to veer away from GeoDjango. Instead, we expanded from our existing work building large-image, a library for working with large geospatial and medical images that provides the backbone for several of our image analysis platforms, including HistomicsUI and the Digital Slide Archive. One of large-image’s core offerings is dynamic tile serving for a vast range of image formats, including geospatial imagery (backed by GDAL and Mapnik). What we needed was a way to bring the power of large-image into Resonant GeoData.
We realized we could meet our own needs while also having an impact on the geospatial tool ecosystem by exporting large-image’s functionality (especially its dynamic tile serving capability) through a general, reusable Django app: django-large-image. The goal was to empower Django projects with a RESTful dynamic tile server capable of handling a wide variety of image types and sizes across any data storage backend. The API exposes many of the other offerings of large-image as well, such as metadata extraction, region of interest clipping, thumbnail generation, and more.
The django-large-image REST API offers the following core features:
- Dynamic tile serving for on-the-fly operations (rescaling, color mapping, & reprojection)
- Region of interest clipping
- Advanced metadata extraction
- Thumbnail generation for various encodings at specified sizes
- Individual pixel access (in geospatial or pixel coordinates)
- Band histogram generation
Applying The Benefits Of This Technology To Other Large Image Projects
Initially, this work was tightly coupled to the core Resonant GeoData platform, but we soon realized the value django-large-image would provide across our projects and to the broader Django ecosystem. This led us to pull out the large-image wrappings from Resonant GeoData to create a lightweight, standalone, and open source package. Django-large-image is built with modularity and customizability in mind and is ready for use in any Django projects where working with large image formats is a requirement, especially for tile serving.
To enable django-large-image to provide immediate value to some of our other image analysis Django projects, we included a few different web map viewers for previewing imagery. These include Django templates for visualizing image tiles with CesiumJS or GeoJS and an admin interface widget.
Django-large-image is installable as a typical Django app. You add it to your project’s INSTALLED_APPS list, then mix in the provided classes to your ViewSets to bring the power of large-image to your web application. The django-large-image README has an overview of how to install and use the application. For an additional, high-level overview of the software, we invite you to watch the brief overview of the software from the 2022 Cloud-Native Geospatial Outreach Event in the link below.
Partnering With Kitware for Your Large Image Projects
django-large-image and the supporting large-image library are developed and maintained by Kitware. We have extensive experience working with large-image data for geospatial and medical industries. We can work with you to build custom web applications for working with large image formats. For more information, please contact our team. We look forward to hearing from you!