Skip to content

GEOINT/grdk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GRDK — GEOINT Rapid Development Kit

GUI toolkit for CUDA-optimized image processing workflow orchestration. Built as Orange Data Mining add-on plugins on top of the GRDL library.

What It Does

GRDK turns GRDL's image processing algorithms into a visual drag-and-drop workflow builder. Load multi-band satellite/aerial imagery, co-register image stacks, chip regions of interest, label training data, build processing pipelines with real-time GPU preview, and publish reproducible workflows — all without writing code.

Two Modes

Mode Purpose Widgets
GEODEV Interactive GEOINT development Image Loader, Stack Viewer, Co-Register, Processor, Orchestrator, Preview, Chipper, Labeler, Project, Publisher
Admin Catalog management Catalog Browser, Artifact Editor, Workflow Manager, Update Monitor

Quick Start

# Install in editable mode
pip install -e .

# With dev tools (pytest, black, mypy)
pip install -e ".[dev]"

Launching the Canvas

GRDK provides the grdk-canvas command, which launches the Orange Canvas with the PyQt6 backend pre-configured and GRDK widgets registered:

grdk-canvas

This is the primary way to use GRDK interactively. The canvas loads two widget categories:

  • GEODEV — Image Loader, Stack Viewer, Co-Register, Processor, Orchestrator, Preview, Chipper, Labeler, Project, Publisher
  • GRDK Admin — Catalog Browser, Artifact Editor, Workflow Manager, Update Monitor

Drag widgets onto the canvas, connect them with signal wires, and build image processing workflows visually.

Note: grdk-canvas sets QT_API=pyqt6 and configures the AnyQt backend before importing Orange. Always use grdk-canvas instead of orange-canvas to ensure the correct Qt backend.

Headless Execution

Run workflows without a GUI:

python -m grdk workflow.yaml --input image.tif --output result.tif
python -m grdk workflow.yaml --input image.tif --output result.tif --no-gpu

Architecture

grdl              (processing primitives — no framework awareness)
  ↓
grdl-runtime      (execution framework — no GUI)
  ├── grdl_rt.execution/  — workflow engine, GPU backend, discovery, DSL
  └── grdl_rt.catalog/    — artifact storage, search, updates
  ↓
grdk              (Qt/Orange GUI)
  ├── viewers/    — embeddable Qt widgets (ImageCanvas, napari viewer, chip gallery)
  ├── widgets/
  │   ├── _signals.py          — custom Orange signal types
  │   ├── _param_controls.py   — dynamic parameter UI builder
  │   ├── _display_controls.py — image display settings UI builder
  │   ├── geodev/              — 10 GEODEV workflow widgets (ow_*.py)
  │   └── admin/               — 4 Admin catalog widgets (ow_*.py)
  ├── _launcher.py             — grdk-canvas entry point
  └── _pyqt6_bootstrap.py     — PyQt6/AnyQt backend setup
tests/            — pytest suite
docs/             — architecture and API documentation

Layer Rules

  • Execution and catalog logic lives in grdl-runtime (grdl_rt package) — GRDK widgets import from grdl_rt.execution and grdl_rt.catalog, not from local directories
  • viewers/ are standalone Qt widgets, embeddable in any Qt parent — no Orange dependency
  • widgets/ are Orange OWBaseWidget subclasses that compose viewers/ and grdl_rt

Key Dependencies

Dependency Purpose
grdl-runtime Execution framework (workflow engine, GPU backend, catalog, discovery)
grdl Image I/O, processing algorithms, coregistration
numpy, scipy Array operations
PyQt6 Qt6 widget toolkit
orange3, orange-widget-base Orange Canvas widget framework
napari Stack viewer with polygon drawing

Standalone Viewer (grdk-viewer)

GRDK includes a standalone geospatial image viewer for SAR, EO/IR, and multispectral imagery. Launch it from the command line:

grdk-viewer                          # empty window
grdk-viewer /path/to/image.tif       # open a file on startup
grdk-viewer /path/to/product_dir     # open a product directory (SAFE, BIOMASS, etc.)

Supported Formats

The viewer opens any format supported by GRDL's reader library:

Format Reader Notes
GeoTIFF GeoTIFFReader Single- and multi-band
NITF / SICD SICDReader SAR complex data with full SICD metadata
SIDD SIDDReader SAR detected images
CPHD CPHDReader Compensated phase history
CRSD CRSDReader Compensated received signal
BIOMASS L1 BIOMASSL1Reader ESA BIOMASS P-band SAR (HH, HV, VH, VV)
Sentinel-1 IW SLC Sentinel1SLCReader Per-swath (IW1/IW2/IW3), per-polarization (VV/VH/HH/HV)
Sentinel-2 L1C/L2A Sentinel2Reader Per-band spectral data and TCI
TerraSAR-X / TanDEM-X TerraSARReader StripMap, SpotLight, ScanSAR
NISAR RSLC / GSLC NISARReader L-band and S-band, per-frequency/polarization
JPEG2000 JP2Reader Wavelet-compressed imagery

Display Features

  • Tiled rendering — streams image tiles on demand; handles imagery of any size without loading the full image into memory
  • Dual-pane view — side-by-side comparison with synchronized pan/zoom; automatic split when opening multi-band or multi-polarization data
  • SAR complex remap — automatic log-magnitude display for complex-valued SAR data
  • Contrast / brightness / gamma — real-time adjustment via per-pane controls
  • Dynamic range windowing — percentile-based or manual min/max clipping
  • Colormaps — grayscale, viridis, inferno, plasma, hot
  • Band / polarization selector — combo box shows named bands (e.g. HH, HV, B04) with automatic reader swap for multi-polarization SAR
  • Coordinate bar — live latitude/longitude readout under the cursor (requires geolocation metadata)
  • Color bar — data-range reference strip alongside each pane
  • GeoJSON vector overlay — load and display vector features on top of imagery

Sentinel-1 IW SLC

When opening a Sentinel-1 SAFE product the viewer prompts for swath selection (IW1 / IW2 / IW3) and automatically enables burst boundary masking to zero out invalid border samples. Multi-polarization products (e.g. VV + VH) are offered as a dual-pane split.

Geolocation

The viewer creates geolocation models automatically from reader metadata:

Sensor Geolocation Method
SICD SICD projection model
BIOMASS Ground control point interpolation
Sentinel-1 SLC Annotation grid interpolation
TerraSAR-X Annotation grid interpolation
NISAR RSLC 3-D geolocation grid interpolation (middle height layer)
NISAR GSLC Affine transform (already geocoded)
Sentinel-2 Affine transform from CRS metadata
GeoTIFF Affine transform from CRS metadata

Processing Tools

Available from the Tools menu:

Tool Description
Orthorectify Projects imagery onto a geographic grid. In dual mode, both panes are orthorectified to a shared output grid for geo-synced comparison. Supports SICD, BIOMASS, Sentinel-1, TerraSAR-X, NISAR, and GeoTIFF sources.
Combine to RGB Builds a false-color RGB composite from any combination of available bands/polarizations (e.g. HH→R, HV→G, VV→B). Includes derived channels like HH+VV and HH−VV.

Export

Action Shortcut Output
Export pane as image Ctrl+E Saves the current pane view as PNG, JPEG, or BMP (screen capture)
Export data Ctrl+Shift+E Saves processing results: ortho → GeoTIFF, RGB composite → TIFF / PNG / JPEG (full resolution)

Programmatic API

The viewer can be embedded in any PyQt6 application:

from grdk.viewers.main_window import ViewerMainWindow

window = ViewerMainWindow()
window.open_file("/path/to/image.tif")           # file or directory
window.open_reader(reader, geolocation=geo)       # grdl reader + geolocation
window.set_array(arr, geolocation=geo, title="…") # numpy array
window.show()

Image Canvas (ImageCanvas)

The underlying display component used by the viewer and all GRDK widgets. A QGraphicsView-based interactive image display with:

  • Pan (mouse drag), Zoom (scroll wheel, double-click to fit)
  • Contrast/Brightness adjustment (does not modify source data)
  • Dynamic range windowing (manual min/max or percentile-based)
  • Gamma correction
  • Colormaps (grayscale, viridis, inferno, plasma, hot)
  • Band selection for multi-band imagery
  • Pixel inspector (hover to read raw values)

Two variants:

  • TiledImageCanvas — tiled, streaming display for large imagery (used by the standalone viewer)
  • ImageCanvas — full interactive viewer for in-memory arrays
  • ImageCanvasThumbnail — non-interactive fixed-size variant for grids and galleries

See docs/image-canvas.md for the API reference.

GRDL Integration

GRDK automatically discovers and wraps GRDL processors:

  • Processor discovery: Scans grdl.image_processing and grdl.coregistration for concrete classes
  • Tag filtering: Processors with __processor_tags__ can be filtered by modality (SAR, PAN, MSI, ...) and category (spatial_filter, contrast_enhancement, ...)
  • GPU dispatch: Respects __gpu_compatible__ flags — skips futile GPU attempts for scipy-dependent processors
  • Progress callbacks: Forwards progress_callback through the pipeline with per-step rescaling
  • Exception handling: Distinguishes GrdlError subtypes from general Python errors in logging
  • Normalization: Optional GRDL data_prep.Normalizer integration in the Chipper widget

Testing

# Full suite
pytest tests/ -v

# Specific module
pytest tests/test_image_canvas.py -v

# With coverage
pytest tests/ --cov=grdk --cov-report=term-missing

174+ tests across 15 test modules. Widget and Qt tests auto-skip when no display is available.

Project Structure (All Files)

Click to expand full file listing

Execution & Catalog (from grdl-runtime)

These modules are imported by GRDK widgets from the grdl_rt package:

Package Key Types Used by Widgets
grdl_rt.execution.discovery discover_processors(), get_processor_tags()
grdl_rt.execution.gpu GpuBackend
grdl_rt.execution.workflow WorkflowDefinition, ProcessingStep, WorkflowState
grdl_rt.execution.dsl DslCompiler
grdl_rt.execution.chip Chip, ChipSet, ChipLabel, PolygonRegion
grdl_rt.execution.tags WorkflowTags, ProjectTags
grdl_rt.execution.project GrdkProject
grdl_rt.execution.executor WorkflowExecutor
grdl_rt.catalog.database ArtifactCatalog
grdl_rt.catalog.models Artifact, UpdateResult
grdl_rt.catalog.resolver resolve_catalog_path()
grdl_rt.catalog.updater ArtifactUpdateWorker
grdl_rt.catalog.pool ThreadExecutorPool

Viewers (grdk/viewers/)

File Purpose
main_window.py ViewerMainWindow — standalone viewer with menus, toolbar, ortho, RGB, export
dual_viewer.py DualGeoViewer — synchronized dual-pane viewer with crop-to-overlap
geo_viewer.py GeoViewer — single-pane viewer with geolocation, file opening, band info
tiled_canvas.py TiledImageCanvas — streaming tiled display for large imagery
tile_cache.py TileCache — async tile loading with LRU eviction
image_canvas.py ImageCanvas, ImageCanvasThumbnail, DisplaySettings, normalize_array
band_info.py BandInfo, get_band_info — named band metadata extraction per reader type
coordinate_bar.py CoordinateBar — live lat/lon readout widget
vector_overlay.py GeoJSON vector overlay on image canvases
stack_viewer.py NapariStackViewer — multi-layer image viewer with polygon drawing
chip_gallery.py ChipGalleryWidget — scrollable thumbnail grid with click-to-label
polygon_tools.py chip_stack_at_polygons — polygon-based chip extraction

Widgets — GEODEV (grdk/widgets/geodev/)

Widget Name Purpose
ow_image_loader.py Image Loader Load TIFF/NITF/HDF5 into image stack
ow_stack_viewer.py Stack Viewer Napari viewer with polygon drawing
ow_coregister.py Co-Register ORB/SIFT feature-match registration (affine/homography)
ow_processor.py Processor Single GRDL processor with tunable params
ow_orchestrator.py Orchestrator Multi-step pipeline builder
ow_preview.py Preview Real-time before/after GPU preview
ow_chipper.py Chipper Extract chips from polygon definitions
ow_labeler.py Labeler Click-to-label chip classification
ow_project.py Project Save/load GRDK project directories
ow_publisher.py Publisher Publish workflows to catalog

Widgets — Admin (grdk/widgets/admin/)

Widget Name Purpose
ow_catalog_browser.py Catalog Browser Search/discover artifacts
ow_artifact_editor.py Artifact Editor Edit catalog artifact metadata
ow_workflow_manager.py Workflow Manager Import/export workflow files
ow_update_monitor.py Update Monitor Check for package updates

Shared Widget Infrastructure (grdk/widgets/)

File Purpose
_signals.py ImageStack, ChipSetSignal, ProcessingPipelineSignal, WorkflowArtifactSignal, GrdkProjectSignal
_param_controls.py build_param_controls() — auto-generates Qt controls from TunableParameterSpec
_display_controls.py build_display_controls() — contrast/brightness/gamma/colormap/window UI

Remote GUI Visualization

GRDK's GUI can be displayed on a remote machine (via SSH X11 forwarding) or from inside a Docker/Podman container. PyQt6 (Qt6) requires the X11/XCB platform plugin and associated libraries on the remote/container side, and a running X server on the host side.

Prerequisites (Remote / Container Side)

Install the X11/XCB runtime libraries required by Qt6:

# Debian / Ubuntu
apt-get update && apt-get install -y \
    libxcb1 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 \
    libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxcb-xfixes0 \
    libxcb-xinerama0 libxcb-xkb1 libxkbcommon-x11-0 libxkbcommon0 \
    libegl1 libgl1-mesa-glx libglib2.0-0 libfontconfig1 libdbus-1-3 \
    x11-utils

# RHEL / Fedora / Rocky
dnf install -y \
    libxcb xcb-util-cursor xcb-util-image xcb-util-keysyms \
    xcb-util-renderutil xcb-util-wm libxkbcommon-x11 libxkbcommon \
    mesa-libEGL mesa-libGL glib2 fontconfig dbus-libs xorg-x11-utils

Environment Variables

Set these before launching GRDK:

# Force the XCB platform plugin (required for X11 forwarding)
export QT_QPA_PLATFORM=xcb

# Disable OpenGL for pure software rendering over X11 (avoids GLX errors)
export QT_QUICK_BACKEND=software
export LIBGL_ALWAYS_SOFTWARE=1

# If you see "Could not connect to display", verify DISPLAY is set:
echo $DISPLAY   # Should show e.g. :0 or localhost:10.0

Option A: Native Linux — SSH X11 Forwarding

From your local machine (the one with the display):

# Connect with X11 forwarding enabled
ssh -X user@remote-host

# Or for trusted forwarding (faster, less restrictive):
ssh -Y user@remote-host

On the remote host:

# Verify DISPLAY is set (ssh -X sets it automatically)
echo $DISPLAY

# Set Qt platform and launch
export QT_QPA_PLATFORM=xcb
export QT_QUICK_BACKEND=software

# Install and run
pip install -e .
python -c "from PyQt6.QtWidgets import QApplication; print('PyQt6 OK')"  # Quick test
grdk-canvas  # Launch GRDK GUI

Option B: Docker Container with X11 Forwarding

Host setup (run once per session on your local machine):

# Allow local Docker containers to access the X server
xhost +local:docker

Run the container with X11 socket and DISPLAY forwarded:

docker run -it \
    -e DISPLAY=$DISPLAY \
    -e QT_QPA_PLATFORM=xcb \
    -e QT_QUICK_BACKEND=software \
    -e LIBGL_ALWAYS_SOFTWARE=1 \
    -v /tmp/.X11-unix:/tmp/.X11-unix:rw \
    --network=host \
    your-grdk-image:latest \
    bash

Example Dockerfile:

FROM python:3.12-slim

# Install X11/XCB runtime dependencies for Qt6
RUN apt-get update && apt-get install -y --no-install-recommends \
    libxcb1 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 \
    libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxcb-xfixes0 \
    libxcb-xinerama0 libxcb-xkb1 libxkbcommon-x11-0 libxkbcommon0 \
    libegl1 libgl1-mesa-glx libglib2.0-0 libfontconfig1 libdbus-1-3 \
    && rm -rf /var/lib/apt/lists/*

# Set Qt environment for X11 forwarding
ENV QT_QPA_PLATFORM=xcb
ENV QT_QUICK_BACKEND=software
ENV LIBGL_ALWAYS_SOFTWARE=1

WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -e .

CMD ["grdk-canvas"]

Build and run:

docker build -t grdk-gui .
xhost +local:docker
docker run -it \
    -e DISPLAY=$DISPLAY \
    -v /tmp/.X11-unix:/tmp/.X11-unix:rw \
    --network=host \
    grdk-gui

Option C: Podman Container

Podman works similarly but uses --userns=keep-id for rootless operation:

xhost +local:
podman run -it \
    -e DISPLAY=$DISPLAY \
    -e QT_QPA_PLATFORM=xcb \
    -e QT_QUICK_BACKEND=software \
    -e LIBGL_ALWAYS_SOFTWARE=1 \
    -v /tmp/.X11-unix:/tmp/.X11-unix:rw \
    --userns=keep-id \
    --network=host \
    grdk-gui

Troubleshooting

Symptom Cause Fix
Could not connect to display DISPLAY not set or X server not reachable Verify echo $DISPLAY, use ssh -X, mount X11 socket
qt.qpa.xcb: could not connect Missing xcb libraries or no X server Install libxcb* packages (see Prerequisites)
Could not load the Qt platform plugin "xcb" Missing Qt XCB platform dependencies Install all libxcb* and libxkbcommon* packages
GLX/OpenGL errors Hardware GL not available over X11 Set QT_QUICK_BACKEND=software and LIBGL_ALWAYS_SOFTWARE=1
Authorization required xhost not configured Run xhost +local:docker on host
No protocol specified Container user mismatch Use xhost +local: or pass --userns=keep-id (Podman)
Blank/frozen window Compositor issue over forwarding Try export QT_X11_NO_MITSHM=1
Slow rendering Network-bound X11 pixel transfer Use SSH compression (ssh -XC) or consider VNC

Security Note

xhost +local:docker permits any local process running under the docker user to access your X server. For production or multi-user environments, prefer X11 cookie-based authentication:

# More secure alternative: share the X authority cookie
docker run -it \
    -e DISPLAY=$DISPLAY \
    -e XAUTHORITY=/tmp/.Xauthority \
    -v $XAUTHORITY:/tmp/.Xauthority:ro \
    -v /tmp/.X11-unix:/tmp/.X11-unix:rw \
    --network=host \
    grdk-gui

Publishing to PyPI

Dependency Management

All dependencies are defined in pyproject.toml. Keep these files synchronized:

  • pyproject.toml — source of truth for versions and dependencies
  • requirements.txt — regenerate with pip freeze > requirements.txt after updating pyproject.toml
  • .github/workflows/publish.yml — automated PyPI publication (do not edit manually)

Releasing a New Version

  1. Update the version field in pyproject.toml (semantic versioning: major.minor.patch)
  2. Update requirements.txt if dependencies changed: pip install -e ".[all,dev]" && pip freeze > requirements.txt
  3. Commit both files
  4. Create a git tag: git tag v0.2.0 (matches version in pyproject.toml)
  5. Push to GitHub: git push && git push --tags
  6. Create a GitHub Release from the tag — this triggers the publish workflow automatically

The workflow:

  • Builds wheels and source distribution using python -m build
  • Publishes to PyPI with OIDC authentication (secure, no API keys)
  • Artifacts are available at pypi.org/p/grdk

See CLAUDE.md for detailed dependency management guidelines.

License

MIT License. Copyright (c) 2026 geoint.org. See LICENSE.

About

GEOINT Rapid Development Kit

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors 4

  •  
  •  
  •  
  •  

Languages