Skip to main content
Version: 0.11.0

Image tiling processor

Introduced 0.11.0

The image_tiling processor splits large images into fixed-size tiles for multimodal vector search. It is designed for Cloud Optimized GeoTIFFs (COGs) but works with any image format. For GeoTIFFs, it computes geographic bounding boxes per tile using Apache SIS, enabling native geo_shape spatial queries on individual tiles.

The processor uses HTTP Range reads for COGs, fetching only the bytes needed for each tile rather than downloading the entire file. Peak memory is ~2-3 MB per tile regardless of source image size.

Syntax

{
"image_tiling": {
"field": "extracted.blocks",
"target_field": "chunks",
"profile": "geo_search",
"source_uri_field": "source_uri",
"reference_config": {
"region": "us-west-2"
}
}
}

How it works

s3://bucket/scene.tif  (Cloud Optimized GeoTIFF, 4096x4096 px)


┌─────────────────────────────────────────────┐
│ image_tiling processor │
│ │
│ 1. Open COG via HTTP Range reads │
│ 2. Extract CRS + geo-transform (SIS) │
│ 3. Compute tile grid │
│ 4. For each tile: │
│ - Read pixel window (Range request) │
│ - Encode as JPEG │
│ - Compute geographic bbox │
│ 5. Output chunk array │
└─────────────────────────────────────────────┘


┌───────────────────────────────────────────────────────────────┐
│ chunks: [ │
│ { │
│ tile_id: "tile_0", │
│ image_data: "<base64 JPEG>", │
│ bbox: { west: -120.5, east: -120.0, south: 35.0, ... }, │
│ crs: "EPSG:4326", │
│ pixel_window: { x: 0, y: 0, width: 512, height: 512 } │
│ }, │
│ { tile_id: "tile_1", ... }, │
│ ... │
│ ] │
└───────────────────────────────────────────────────────────────┘

▼ embed processor (Titan Multimodal)

▼ indexed with geo_shape envelope + kNN vector

Tile grid layout

Source image (4096 x 4096 px, profile: geo_search, tile_size: 512, overlap: 0):

0 512 1024 1536 2048 2560 3072 3584 4096
0 ┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐
│tile 0│tile 1│tile 2│tile 3│tile 4│tile 5│tile 6│tile 7│
512 ├──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│tile 8│tile 9│ 10 │ 11 │ 12 │ 13 │ 14 │ 15 │
1024 ├──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 16 │ 17 │ 18 │ 19 │ 20 │ 21 │ 22 │ 23 │
│ │ │ │ │ │ │ │ │
... ...
3584 ├──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 56 │ 57 │ 58 │ 59 │ 60 │ 61 │ 62 │ 63 │
4096 └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘

= 64 tiles, each 512x512 px, no overlap
= Each tile has a geographic bbox computed from the CRS affine transform

With overlap (profile: rag, overlap: 64):

0 64 512 576 1024
0 ┌─────────┐
│ tile 0 │
512 │ │┌─────────┐
└───┬─────┤│ tile 1 │ ◄── 64px overlap zone
64 │overlap │
└─────┤ │
576 └──────────┘

Auto-scaling for large images

When the computed tile grid exceeds max_tiles, the processor automatically scales up the tile size by 50% until the grid fits:

Image: 10000 x 10000 px, tile_size: 256, max_tiles: 100

Grid at 256px: 39 x 39 = 1521 tiles → exceeds max_tiles (100)
Grid at 384px: 26 x 26 = 676 tiles → exceeds max_tiles
Grid at 576px: 18 x 18 = 324 tiles → exceeds max_tiles
Grid at 864px: 12 x 12 = 144 tiles → exceeds max_tiles
Grid at 1296px: 8 x 8 = 64 tiles → fits! Use 1296px tiles

Profiles

Profiles provide preset configurations optimized for specific use cases.

ProfileTile sizeOverlapMax tilesUse case
rag512 px64 px100General multimodal image search (default)
detail256 px32 px400Fine-grained feature/object detection
overview1024 px128 px25Coarse scene-level classification
geo_search512 px0 px200Non-overlapping geospatial tiles for spatial queries
tip

Use the geo_search profile for geospatial imagery. Zero overlap ensures tile bounding boxes don't intersect, making geo_shape queries return clean, non-duplicated results.

You can override individual profile defaults:

{
"image_tiling": {
"profile": "geo_search",
"tile_size": 1024,
"max_tiles": 50
}
}

Configuration parameters

ParameterData typeRequired/OptionalDescription
fieldStringOptionalSource field containing image/geo_raster blocks. Default is extracted.blocks.
target_fieldStringOptionalField where tile chunks are written. Default is chunks.
source_uri_fieldStringOptionalDocument field containing image URI for direct tiling from S3/HTTPS.
region_fieldStringOptionalDocument field that overrides S3 region per document.
profileStringOptionalTiling profile: rag, detail, overview, or geo_search. Default is rag.
tile_sizeIntegerOptionalSquare tile dimension in pixels. Overrides profile default.
overlapIntegerOptionalPixel overlap between adjacent tiles. Overrides profile default.
max_tilesIntegerOptionalMaximum tile count. Auto-scales tile size if exceeded. Overrides profile default.
tile_formatStringOptionalOutput encoding: jpeg or png. Default is jpeg.
tile_qualityFloatOptionalJPEG compression quality [0.0, 1.0]. Default is 0.85.
block_typesArrayOptionalBlock types to tile. Default is ["image", "geo_raster"].
reference_configObjectOptionalS3/reference resolver configuration (region, anonymous, presign duration).
descriptionStringOptionalA brief description of the processor.
tagStringOptionalAn identifier tag for the processor.

Output structure

Each tile chunk contains:

{
"chunks": [
{
"tile_id": "tile_0",
"tile_index": 0,
"image_data": "<base64-encoded JPEG>",
"image_mime_type": "image/jpeg",
"pixel_window": {
"x": 0,
"y": 0,
"width": 512,
"height": 512
},
"bbox": {
"west": -120.5,
"east": -120.0,
"south": 35.0,
"north": 35.5
},
"crs": "EPSG:4326",
"parent_uri": "s3://bucket/scene.tif"
}
]
}
FieldDescription
tile_idUnique identifier for the tile within the document.
tile_indexSequential zero-based index (top-to-bottom, left-to-right).
image_dataBase64-encoded tile image (JPEG or PNG).
image_mime_typeMIME type of the encoded tile.
pixel_windowPixel coordinates in the source image.
bboxGeographic bounding box (present only for georeferenced images).
crsCoordinate Reference System identifier (e.g., EPSG:4326).
parent_uriSource URI when using source_uri_field.

GeoTIFF and COG support

Cloud Optimized GeoTIFF (COG)

The processor detects internally-tiled TIFFs and uses HTTP Range reads to fetch only the bytes needed for each tile. This avoids downloading multi-gigabyte files.

Standard GeoTIFF:              Cloud Optimized GeoTIFF:
┌──────────────────┐ ┌──────────────────┐
│ │ │ TIFF header + │ ◄── Range read 1 (small)
│ Full image must │ │ tile offsets │
│ be downloaded │ ├──────────────────┤
│ before tiling │ │ Tile 0 bytes │ ◄── Range read 2
│ │ ├──────────────────┤
│ (hundreds of MB)│ │ Tile 1 bytes │ ◄── Range read 3
│ │ ├──────────────────┤
└──────────────────┘ │ ... │
└──────────────────┘
Only needed tiles
are fetched!
warning

Non-COG GeoTIFFs larger than 100 MB will fail with a recommendation to convert to COG format:

gdal_translate -of COG input.tif output_cog.tif

CRS metadata extraction

Apache SIS extracts the Coordinate Reference System from GeoTIFF metadata:

  • CRS identifier (e.g., EPSG:4326, EPSG:32617)
  • Geo-transform (affine matrix mapping pixel coordinates to geographic coordinates)
  • Grid extent (image dimensions)

The geo-transform is used to compute each tile's geographic bounding box:

Pixel (x, y) → Geographic (lon, lat):

longitude = geoTransform[0] + x * geoTransform[1] + y * geoTransform[2]
latitude = geoTransform[3] + x * geoTransform[4] + y * geoTransform[5]

Indexing with geo_shape

Tile bounding boxes can be indexed as geo_shape envelopes for spatial queries:

PUT /geospatial-imagery
{
"mappings": {
"properties": {
"chunks": {
"type": "nested",
"properties": {
"bbox_shape": {
"type": "geo_shape"
},
"embedding": {
"type": "knn_vector",
"dimension": 1024,
"method": { "name": "hnsw", "space_type": "cosinesimil", "engine": "lucene" }
}
}
}
}
}
}

Then query with a bounding box:

GET /geospatial-imagery/_search
{
"query": {
"nested": {
"path": "chunks",
"query": {
"geo_shape": {
"chunks.bbox_shape": {
"shape": {
"type": "envelope",
"coordinates": [[-125.0, 50.0], [-65.0, 25.0]]
},
"relation": "intersects"
}
}
}
}
}
}

Using the processor

PUT _ingest/pipeline/geotiff-pipeline
{
"processors": [
{
"content_extract": {
"input_mode": "reference",
"source_uri_field": "source_uri",
"reference_config": {
"region": "us-west-2",
"anonymous": "true"
}
}
},
{
"image_tiling": {
"field": "extracted.blocks",
"target_field": "chunks",
"profile": "geo_search",
"reference_config": {
"region": "us-west-2",
"anonymous": "true"
}
}
},
{
"embed": {
"field": "chunks",
"model_id": "amazon.titan-embed-image-v1",
"provider": "bedrock",
"dimensions": 1024,
"content_type": "multimodal",
"provider_config": {
"region": "us-east-1"
}
}
}
]
}

Example 2: High-detail tiling for aerial imagery

PUT _ingest/pipeline/aerial-detail
{
"processors": [
{
"image_tiling": {
"source_uri_field": "source_uri",
"target_field": "chunks",
"profile": "detail",
"tile_format": "png",
"max_tiles": 500,
"reference_config": {
"region": "us-east-1"
}
}
}
]
}

Example 3: Overview tiles for scene classification

PUT _ingest/pipeline/scene-overview
{
"processors": [
{
"image_tiling": {
"source_uri_field": "source_uri",
"target_field": "chunks",
"profile": "overview",
"tile_quality": 0.9,
"reference_config": {
"region": "us-west-2"
}
}
}
]
}

Example 4: Tiling from a public S3 bucket

PUT _ingest/pipeline/public-imagery
{
"processors": [
{
"content_extract": {
"input_mode": "reference",
"source_uri_field": "source_uri",
"reference_config": {
"region": "us-west-2",
"anonymous": "true"
}
}
},
{
"image_tiling": {
"field": "extracted.blocks",
"target_field": "chunks",
"profile": "geo_search",
"reference_config": {
"region": "us-west-2",
"anonymous": "true"
}
}
}
]
}
PUT /imagery/_doc/1?pipeline=public-imagery
{
"source_uri": "s3://nasa-omi-no2/OMI-Aura_L2-OMNO2_2024m0115.tif",
"title": "OMI NO2 2024-01-15"
}

Memory and performance

Source image sizeTiles (geo_search)Peak memoryHTTP Range reads
512 x 512 px1~2 MB1
4096 x 4096 px64~3 MB64
10000 x 10000 px64 (auto-scaled to 1296px tiles)~6 MB64
30000 x 30000 px64 (auto-scaled to ~3900px tiles)~50 MB64
  • Tiles are processed sequentially -- one decoded at a time
  • Image bytes are discarded after encoding to base64
  • COG internal tiling aligns with HTTP Range reads for maximum efficiency