Skip to content

Slices Module

The georeader.slices module provides utilities for dividing large raster datasets into smaller tiles (chips/windows) for batch processing, machine learning inference, and memory-efficient workflows.

Overview

When working with large satellite images that don't fit in memory, or when running ML models that require fixed-size inputs, you need to tile the data into smaller chunks. This module handles the complexity of:

  • Generating tile coordinates without loading data
  • Overlap handling for seamless predictions
  • Edge cases at image boundaries
  • Multi-dimensional support (time, bands, spatial)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        TILING WORKFLOW OVERVIEW                              β”‚
β”‚                                                                              β”‚
β”‚    Large Raster (10000 Γ— 10000)                                             β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”             β”‚
β”‚   β”‚                                                           β”‚             β”‚
β”‚   β”‚   β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”        β”‚             β”‚
β”‚   β”‚   β”‚  1  β”‚  2  β”‚  3  β”‚  4  β”‚  5  β”‚  6  β”‚  7  β”‚ 8 β”‚        β”‚             β”‚
β”‚   β”‚   β”œβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€        β”‚             β”‚
β”‚   β”‚   β”‚  9  β”‚ 10  β”‚ 11  β”‚ 12  β”‚ 13  β”‚ 14  β”‚ 15  β”‚16 β”‚        β”‚             β”‚
β”‚   β”‚   β”œβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€        β”‚             β”‚
β”‚   β”‚   β”‚ 17  β”‚ 18  β”‚ ... β”‚     β”‚     β”‚     β”‚     β”‚   β”‚        β”‚             β”‚
β”‚   β”‚   β”œβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€        β”‚             β”‚
β”‚   β”‚   β”‚     β”‚     β”‚     β”‚     β”‚     β”‚     β”‚     β”‚   β”‚        β”‚  tiles =    β”‚
β”‚   β”‚   β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”˜        β”‚  create_    β”‚
β”‚   β”‚                                                           β”‚  windows()  β”‚
β”‚   β”‚   Each tile: 256 Γ— 256 pixels                            β”‚             β”‚
β”‚   β”‚   Edge tiles may be smaller (trim_incomplete=True)       β”‚             β”‚
β”‚   β”‚                                                           β”‚             β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚
β”‚                                                                              β”‚
β”‚   Process each tile independently β†’ combine results                         β”‚
β”‚                                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Functions

create_windows

Generates a list of rasterio.windows.Window objects for tiling a raster:

from georeader.slices import create_windows

# Create 256Γ—256 tiles with 32px overlap
windows = create_windows(
    geodata_shape=(4000, 5600),  # (height, width)
    window_size=(256, 256),      # (height, width)
    overlap=(32, 32),            # (row_overlap, col_overlap)
    include_incomplete=True,     # Include edge tiles
    trim_incomplete=True         # Edge tiles have actual size, not padded
)

print(f"Created {len(windows)} tiles")
# Each window has: window.row_off, window.col_off, window.height, window.width

create_slices

Lower-level function using dictionaries for named dimensions:

from georeader.slices import create_slices

# For multi-dimensional data (e.g., time series)
named_shape = {"time": 12, "y": 4000, "x": 5600}
dims = {"y": 256, "x": 256}
overlap = {"y": 32, "x": 32}

slices = create_slices(named_shape, dims, overlap=overlap)
# Returns: [{"y": slice(0, 256), "x": slice(0, 256)}, ...]

Overlap Strategies

Overlap is crucial for ML inference to avoid edge artifacts:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                           OVERLAP HANDLING                                   β”‚
β”‚                                                                              β”‚
β”‚   Without Overlap (artifacts at tile edges)                                 β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”                                              β”‚
β”‚   β”‚        β”‚        β”‚        β”‚   Each tile processed independently          β”‚
β”‚   β”‚  Tile  β”‚  Tile  β”‚  Tile  β”‚   β†’ visible seams in output                  β”‚
β”‚   β”‚   1    β”‚   2    β”‚   3    β”‚                                              β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                              β”‚
β”‚            ↓        ↓                                                       β”‚
β”‚          seams   seams                                                      β”‚
β”‚                                                                              β”‚
β”‚   With Overlap (seamless predictions)                                       β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                              β”‚
β”‚   β”‚        ╔══════╗          β”‚   Tiles overlap by N pixels                  β”‚
β”‚   β”‚  Tile  β•‘Overlapβ•‘  Tile   β”‚   β†’ blend or crop overlap region             β”‚
β”‚   β”‚   1    β•‘Region β•‘   2     β”‚   β†’ seamless output                          β”‚
β”‚   β”‚        β•šβ•β•β•β•β•β•β•          β”‚                                              β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                              β”‚
β”‚            ←─ overlap ─→                                                    β”‚
β”‚                                                                              β”‚
β”‚   Overlap = kernel_size / 2 is a good rule of thumb for CNNs               β”‚
β”‚                                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Typical Overlap Values

Model Type Recommended Overlap Reason
Simple CNN 16-32 px Receptive field edge effects
U-Net 32-64 px Multi-scale features
Vision Transformer patch_size / 2 Patch boundary artifacts
Segmentation class_boundary_width Smooth boundaries

Examples

For complete examples of using tiling for ML inference workflows, including handling edge cases and stitching predictions, see the Tiling and Stitching tutorial.

Handling Edge Cases

Incomplete Tiles at Edges

# Option 1: Include smaller edge tiles (default)
windows = create_windows(shape, tile_size, 
                        include_incomplete=True,
                        trim_incomplete=True)
# Edge tiles have actual size: 256Γ—200 for a 200px remainder

# Option 2: Pad edge tiles to full size
windows = create_windows(shape, tile_size,
                        include_incomplete=True, 
                        trim_incomplete=False)
# Edge tiles request 256Γ—256 even if image is smaller β†’ needs padding

# Option 3: Exclude edge tiles entirely
windows = create_windows(shape, tile_size,
                        include_incomplete=False)
# Only tiles that fit completely are included

Negative Offsets for Symmetric Padding

# For predictions where you want overlap on ALL edges (including first/last tile)
windows = create_windows(shape, tile_size,
                        overlap=(64, 64),
                        start_negative_if_padding=True)
# First window starts at row=-32, col=-32
# Requires handling out-of-bounds reads with padding

Performance Considerations

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        PERFORMANCE TRADEOFFS                                 β”‚
β”‚                                                                              β”‚
β”‚   Tile Size vs Overhead                                                      β”‚
β”‚                                                                              β”‚
β”‚   Small tiles (64Γ—64)         Large tiles (512Γ—512)                         β”‚
β”‚   ───────────────────         ─────────────────────                         β”‚
β”‚   βœ“ Low memory per tile       βœ“ Less overhead per tile                      β”‚
β”‚   βœ— Many tiles = overhead     βœ“ Better GPU utilization                      β”‚
β”‚   βœ— More edge artifacts       βœ— Higher memory requirement                   β”‚
β”‚                                                                              β”‚
β”‚   Overlap Impact                                                             β”‚
β”‚   ──────────────                                                             β”‚
β”‚   Small overlap (16px)        Large overlap (128px)                         β”‚
β”‚   ───────────────────         ─────────────────────                         β”‚
β”‚   βœ“ Fewer total tiles         βœ“ Cleaner predictions                         β”‚
β”‚   βœ— Possible edge artifacts   βœ— Significant overhead                        β”‚
β”‚                                                                              β”‚
β”‚   Rule of thumb:                                                             β”‚
β”‚   - tile_size = 256-512 for most GPU workflows                              β”‚
β”‚   - overlap = 10-20% of tile_size                                           β”‚
β”‚                                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

API Reference

georeader.slices

Slices Module: Generate windows for tiled/chunked raster processing.

This module provides utilities to divide large rasters into overlapping or non-overlapping tiles (slices) for memory-efficient processing. Essential for processing datasets that don't fit in memory.

Tiling Strategies

Choosing the right tiling approach for your use case::

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    TILING STRATEGIES                                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                          β”‚
β”‚  Non-overlapping (overlap=0)          Overlapping (overlap>0)           β”‚
β”‚  ─────────────────────────            ──────────────────────            β”‚
β”‚                                                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”              β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”               β”‚
β”‚  β”‚ 1  β”‚ 2  β”‚ 3  β”‚ 4  β”‚              β”‚ 1 ─┼─ 2 ┼─ 3 ┼─ 4 β”‚               β”‚
β”‚  β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€              β”œβ”€β”€β”€β”¬β”Όβ”€β”€β”€β”¬β”Όβ”€β”€β”€β”¬β”Όβ”€β”€β”€β”¬β”€               β”‚
β”‚  β”‚ 5  β”‚ 6  β”‚ 7  β”‚ 8  β”‚              β”‚ 5 β”‚β”œ 6 β”‚β”œ 7 β”‚β”œ 8 β”‚β”‚               β”‚
β”‚  β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€              β”œβ”€β”€β”€β”Όβ”Όβ”€β”€β”€β”Όβ”Όβ”€β”€β”€β”Όβ”Όβ”€β”€β”€β”Όβ”€               β”‚
β”‚  β”‚ 9  β”‚ 10 β”‚ 11 β”‚ 12 β”‚              β”‚ 9 β”‚β”‚10 β”‚β”‚11 β”‚β”‚12 β”‚β”‚               β”‚
β”‚  β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”˜              β””β”€β”€β”€β”΄β”΄β”€β”€β”€β”΄β”΄β”€β”€β”€β”΄β”΄β”€β”€β”€β”΄β”˜               β”‚
β”‚                                          └─ overlap region              β”‚
β”‚  Best for:                          Best for:                           β”‚
β”‚  β€’ Independent tiles                β€’ Edge-sensitive algorithms         β”‚
β”‚  β€’ Aggregation tasks                β€’ Convolutions/filters              β”‚
β”‚  β€’ Simple mosaicking                β€’ Seamline blending                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Slice Coordinates vs Windows

Understanding the relationship between slices and windows::

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              SLICES (Python) vs WINDOWS (Rasterio)                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                          β”‚
β”‚  slice(start, stop)              Window(col_off, row_off, width, height)β”‚
β”‚  ──────────────────              ──────────────────────────────────────│
β”‚                                                                          β”‚
β”‚  β€’ Python array indexing         β€’ Rasterio file reading                β”‚
β”‚  β€’ 2D: (row_slice, col_slice)    β€’ 2D: explicit offsets + sizes         β”‚
β”‚  β€’ End-exclusive                 β€’ Width/height inclusive               β”‚
β”‚                                                                          β”‚
β”‚  Conversion:                                                             β”‚
β”‚    slices_to_windows((row_slice, col_slice)) β†’ Window                   β”‚
β”‚    window_to_slices(window) β†’ (row_slice, col_slice)                    β”‚
β”‚                                                                          β”‚
β”‚  Example:                                                                β”‚
β”‚    slice(100, 356), slice(200, 456)  β†’  Window(200, 100, 256, 256)      β”‚
β”‚    (rows 100-355, cols 200-455)          (col=200, row=100, 256x256)    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Edge Handling Options

What happens when tiles don't fit evenly::

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    EDGE HANDLING OPTIONS                                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                          β”‚
β”‚  Raster: 500px, Tile: 128px, Overlap: 0                                 β”‚
β”‚  ──────────────────────────────────────                                 β”‚
β”‚                                                                          β”‚
β”‚  include_incomplete=True (default):                                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”                             β”‚
β”‚  β”‚  128   β”‚  128   β”‚  128   β”‚  128   β”‚ 12 β”‚  ← 5 tiles, last is 12px   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”˜                             β”‚
β”‚                                                                          β”‚
β”‚  include_incomplete=False:                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”                                           β”‚
β”‚  β”‚  128   β”‚  128   β”‚  128   β”‚  ← 3 tiles, drops edge                    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                           β”‚
β”‚                                                                          β”‚
β”‚  trim_incomplete=True:                                                   β”‚
β”‚  Same as include_incomplete=True but last slice is trimmed              β”‚
β”‚  slice(384, 500) instead of slice(384, 512)                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Module Functions Overview

Slice Generation
  • :func:_slices: Generate 1D slices for a single dimension
  • :func:_slices_nd: Generate N-dimensional slice tuples
  • :func:_slices_2d: Generate 2D (row, col) slice tuples
Window Conversion
  • :func:slices_to_windows: Convert (row_slice, col_slice) β†’ Window
  • :func:window_to_slices: Convert Window β†’ (row_slice, col_slice)
  • :func:windows_from_shape: Generate Windows covering a shape

Quick Start

Generate tiles for processing a large raster::

from georeader import slices
import rasterio

# Generate 256x256 tiles with 32px overlap
with rasterio.open("large_raster.tif") as src:
    tiles = slices._slices_2d(
        shape=(src.height, src.width),
        size=(256, 256),
        overlap=(32, 32)
    )

    for row_slice, col_slice in tiles:
        # Read this tile
        data = src.read(window=slices.slices_to_windows((row_slice, col_slice)))
        # Process...

Convert between slices and windows::

from georeader import slices

# Slices to Window
row_s, col_s = slice(100, 356), slice(200, 456)
window = slices.slices_to_windows((row_s, col_s))
# Window(col_off=200, row_off=100, width=256, height=256)

# Window to slices
row_s, col_s = slices.window_to_slices(window)
# slice(100, 356), slice(200, 456)

See Also

georeader.mosaic : Mosaic processing using tiles georeader.read : Reading functions that accept Windows rasterio.windows : Window class documentation

create_windows(geodata_shape, window_size, overlap=None, include_incomplete=True, start_negative_if_padding=False, trim_incomplete=True)

Generate rasterio Window objects covering a raster in tiles.

This is the primary function for tiled raster processing with rasterio/georeader. It creates a list of Windows that can be passed directly to read functions.

Parameters:

Name Type Description Default
geodata_shape Tuple[int, int]

Spatial shape of the raster as (height, width) or equivalently (n_rows, n_cols). Note: height first, matching numpy convention.

required
window_size Tuple[int, int]

Size of each tile as (height, width). Example: (256, 256) for 256Γ—256 pixel tiles.

required
overlap Optional[Tuple[int, int]]

Overlap in pixels as (row_overlap, col_overlap). Example: (32, 32) for 32-pixel overlap in both dimensions. Default None (no overlap, stride = window_size).

None
include_incomplete bool

Include edge tiles that are smaller than window_size. Default True.

True
start_negative_if_padding bool

Start tiling at -overlap//2 for symmetric edge padding. Requires boundless=True when reading. Default False.

False
trim_incomplete bool

Trim edge tiles to raster bounds rather than extending beyond. Default True.

True

Returns:

Type Description
List[Window]

List[rasterio.windows.Window]: Windows covering the raster. Each window has integer col_off, row_off, width, height attributes.

Examples:

Generate tiles for a raster:

>>> from georeader import slices
>>> import rasterio
>>>
>>> # 1000Γ—1200 raster into 256Γ—256 tiles
>>> windows = slices.create_windows(
...     geodata_shape=(1000, 1200),
...     window_size=(256, 256)
... )
>>> len(windows)
20  # 4 rows Γ— 5 cols
>>> windows[0]
Window(col_off=0, row_off=0, width=256, height=256)

Process raster in tiles:

>>> with rasterio.open("large_image.tif") as src:
...     windows = slices.create_windows(
...         geodata_shape=(src.height, src.width),
...         window_size=(512, 512),
...         overlap=(64, 64)
...     )
...     for window in windows:
...         data = src.read(window=window)
...         # Process tile...

With GeoTensor:

>>> from georeader import read
>>> windows = slices.create_windows(
...     geodata_shape=geotensor.shape[-2:],  # (H, W)
...     window_size=(256, 256)
... )
>>> for window in windows:
...     tile = read.read_from_window(geotensor, window)
See Also

create_slices: Returns dict of slices for xarray-style indexing. georeader.read.read_from_window: Read data using a Window.

Source code in georeader/slices.py
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
def create_windows(geodata_shape: Tuple[int, int],
                   window_size: Tuple[int, int], overlap: Optional[Tuple[str, int]] = None,
                   include_incomplete: bool = True, start_negative_if_padding: bool = False,
                   trim_incomplete: bool = True) -> List[rasterio.windows.Window]:
    """
    Generate rasterio Window objects covering a raster in tiles.

    This is the primary function for tiled raster processing with rasterio/georeader.
    It creates a list of Windows that can be passed directly to read functions.

    Args:
        geodata_shape (Tuple[int, int]): Spatial shape of the raster as (height, width)
            or equivalently (n_rows, n_cols). Note: height first, matching numpy convention.
        window_size (Tuple[int, int]): Size of each tile as (height, width).
            Example: (256, 256) for 256Γ—256 pixel tiles.
        overlap (Optional[Tuple[int, int]]): Overlap in pixels as (row_overlap, col_overlap).
            Example: (32, 32) for 32-pixel overlap in both dimensions.
            Default None (no overlap, stride = window_size).
        include_incomplete (bool): Include edge tiles that are smaller than window_size.
            Default True.
        start_negative_if_padding (bool): Start tiling at -overlap//2 for symmetric
            edge padding. Requires boundless=True when reading. Default False.
        trim_incomplete (bool): Trim edge tiles to raster bounds rather than extending
            beyond. Default True.

    Returns:
        List[rasterio.windows.Window]: Windows covering the raster. Each window has
            integer col_off, row_off, width, height attributes.

    Examples:
        Generate tiles for a raster:

        >>> from georeader import slices
        >>> import rasterio
        >>>
        >>> # 1000Γ—1200 raster into 256Γ—256 tiles
        >>> windows = slices.create_windows(
        ...     geodata_shape=(1000, 1200),
        ...     window_size=(256, 256)
        ... )
        >>> len(windows)
        20  # 4 rows Γ— 5 cols
        >>> windows[0]
        Window(col_off=0, row_off=0, width=256, height=256)

        Process raster in tiles:

        >>> with rasterio.open("large_image.tif") as src:
        ...     windows = slices.create_windows(
        ...         geodata_shape=(src.height, src.width),
        ...         window_size=(512, 512),
        ...         overlap=(64, 64)
        ...     )
        ...     for window in windows:
        ...         data = src.read(window=window)
        ...         # Process tile...

        With GeoTensor:

        >>> from georeader import read
        >>> windows = slices.create_windows(
        ...     geodata_shape=geotensor.shape[-2:],  # (H, W)
        ...     window_size=(256, 256)
        ... )
        >>> for window in windows:
        ...     tile = read.read_from_window(geotensor, window)

    See Also:
        create_slices: Returns dict of slices for xarray-style indexing.
        georeader.read.read_from_window: Read data using a Window.
    """
    named_shape = {"x":geodata_shape[-1], "y":geodata_shape[-2]}

    if overlap is not None:
        overlap = {"x": overlap[1], "y": overlap[0]}

    list_of_dict_slices = create_slices(named_shape,
                                        {"x": window_size[1], "y":window_size[0]},
                                        overlap=overlap, include_incomplete=include_incomplete,
                                        start_negative_if_padding=start_negative_if_padding,
                                        trim_incomplete=trim_incomplete)

    return [rasterio.windows.Window.from_slices(dict_slices["y"], dict_slices["x"], boundless=True) for dict_slices in list_of_dict_slices]

create_slices(named_shape, dims, overlap=None, include_incomplete=True, start_negative_if_padding=False, trim_incomplete=True)

Generate N-dimensional slice combinations for tiled array processing.

This function extends 1D slicing (:func:_slices) to multiple named dimensions, returning all combinations of slices as a Cartesian product. Designed for xarray-style named dimensions but works with any string keys.

The function is useful for processing large multidimensional datasets in chunks, such as temporal-spatial data cubes or multi-resolution pyramids.

Parameters:

Name Type Description Default
named_shape Dict[str, int]

Shape of the array with named dimensions. Example: {"x": 5600, "y": 4000} for a 5600Γ—4000 raster.

required
dims Dict[str, int]

Size of tiles for each dimension to slice. Only dimensions in this dict will be sliced; others are left whole. Example: {"x": 128, "y": 128} for 128Γ—128 tiles.

required
overlap Optional[Dict[str, int]]

Overlap pixels per dimension. Example: {"x": 16, "y": 16} for 16-pixel overlap. Defaults to 0 for any dimension not specified.

None
include_incomplete bool

Include edge tiles smaller than dims. Default True.

True
start_negative_if_padding bool

Start at -overlap//2 for symmetric edge handling. Default False.

False
trim_incomplete bool

Trim edge tiles to actual array bounds rather than extending beyond. Default True.

True

Returns:

Type Description
List[Dict[str, slice]]

List[Dict[str, slice]]: List of slice dictionaries, one per tile. Each dict maps dimension names to slice objects. Total count = product of tile counts per dimension.

Examples:

Simple 2D tiling:

>>> named_shape = {"x": 500, "y": 400}
>>> dims = {"x": 256, "y": 256}
>>> tiles = create_slices(named_shape, dims)
>>> len(tiles)  # 2 in x Γ— 2 in y = 4 tiles
4
>>> tiles[0]
{'x': slice(0, 256), 'y': slice(0, 256)}

With overlap for ML inference:

>>> tiles = create_slices(
...     named_shape={"x": 1000, "y": 1000},
...     dims={"x": 512, "y": 512},
...     overlap={"x": 64, "y": 64}
... )
>>> # stride = 512 - 64 = 448
>>> len(tiles)  # 3 in x Γ— 3 in y = 9 tiles
9

Use with xarray:

>>> import xarray as xr
>>> data = xr.DataArray(np.random.rand(400, 500), dims=['y', 'x'])
>>> tiles = create_slices(
...     named_shape={"x": data.sizes["x"], "y": data.sizes["y"]},
...     dims={"x": 128, "y": 128}
... )
>>> for tile_slices in tiles:
...     chunk = data.isel(tile_slices)  # Extract tile
...     # Process chunk...
See Also

create_windows: Returns rasterio.windows.Window objects instead of dicts. _slices: Underlying 1D slicing function.

Source code in georeader/slices.py
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
def create_slices(named_shape: Dict[str, int],
                  dims: Dict[str, int], overlap: Optional[Dict[str, int]] = None,
                  include_incomplete: bool = True, start_negative_if_padding: bool = False,
                  trim_incomplete: bool = True) -> List[Dict[str, slice]]:
    """
    Generate N-dimensional slice combinations for tiled array processing.

    This function extends 1D slicing (:func:`_slices`) to multiple named dimensions,
    returning all combinations of slices as a Cartesian product. Designed for
    xarray-style named dimensions but works with any string keys.

    The function is useful for processing large multidimensional datasets in
    chunks, such as temporal-spatial data cubes or multi-resolution pyramids.

    Args:
        named_shape (Dict[str, int]): Shape of the array with named dimensions.
            Example: ``{"x": 5600, "y": 4000}`` for a 5600Γ—4000 raster.
        dims (Dict[str, int]): Size of tiles for each dimension to slice.
            Only dimensions in this dict will be sliced; others are left whole.
            Example: ``{"x": 128, "y": 128}`` for 128Γ—128 tiles.
        overlap (Optional[Dict[str, int]]): Overlap pixels per dimension.
            Example: ``{"x": 16, "y": 16}`` for 16-pixel overlap.
            Defaults to 0 for any dimension not specified.
        include_incomplete (bool): Include edge tiles smaller than `dims`.
            Default True.
        start_negative_if_padding (bool): Start at -overlap//2 for symmetric
            edge handling. Default False.
        trim_incomplete (bool): Trim edge tiles to actual array bounds rather
            than extending beyond. Default True.

    Returns:
        List[Dict[str, slice]]: List of slice dictionaries, one per tile.
            Each dict maps dimension names to slice objects.
            Total count = product of tile counts per dimension.

    Examples:
        Simple 2D tiling:

        >>> named_shape = {"x": 500, "y": 400}
        >>> dims = {"x": 256, "y": 256}
        >>> tiles = create_slices(named_shape, dims)
        >>> len(tiles)  # 2 in x Γ— 2 in y = 4 tiles
        4
        >>> tiles[0]
        {'x': slice(0, 256), 'y': slice(0, 256)}

        With overlap for ML inference:

        >>> tiles = create_slices(
        ...     named_shape={"x": 1000, "y": 1000},
        ...     dims={"x": 512, "y": 512},
        ...     overlap={"x": 64, "y": 64}
        ... )
        >>> # stride = 512 - 64 = 448
        >>> len(tiles)  # 3 in x Γ— 3 in y = 9 tiles
        9

        Use with xarray:

        >>> import xarray as xr
        >>> data = xr.DataArray(np.random.rand(400, 500), dims=['y', 'x'])
        >>> tiles = create_slices(
        ...     named_shape={"x": data.sizes["x"], "y": data.sizes["y"]},
        ...     dims={"x": 128, "y": 128}
        ... )
        >>> for tile_slices in tiles:
        ...     chunk = data.isel(tile_slices)  # Extract tile
        ...     # Process chunk...

    See Also:
        create_windows: Returns rasterio.windows.Window objects instead of dicts.
        _slices: Underlying 1D slicing function.
    """
    if overlap is None:
        overlap = {}

    dim_slices = []
    for dim in dims:
        dimsize = named_shape[dim]
        size = dims[dim]
        olap = overlap.get(dim, 0)
        dim_slices.append(_slices(dimsize, size, olap, include_incomplete=include_incomplete,
                                  start_negative_if_padding=start_negative_if_padding,
                                  trim_incomplete=trim_incomplete))

    return [{key: slic for key, slic in zip(dims, tuple_slices)} for tuple_slices in itertools.product(*dim_slices)]

See Also

  • Read Module - Image reading and reprojection
  • Mosaic Module - Combining multiple rasters
  • georeader.read.read_from_window - Reading tiles from GeoData