Skip to content

Repository files navigation

Repo Hero Image

About

LunarSight is a modular pipeline for lunar feature detection using YOLO and/or Detectron2. It processes LROC NAC images with SPICE geolocation, converts annotations to COCO format, trains object detection models, and runs inference.

Quickstart

# Install the package (includes all dependencies)
pip install .

# Run the full pipeline (uses ./data directory by default)
lunarsight run 1-5

Note: No configuration file required. The pipeline uses sensible defaults with ./data as the base directory.

Getting Started

Complete setup checklist for team members:

# 1. Clone and install
git clone https://github.com/ansidian/LunarSight.git
cd LunarSight
pip install .

# 2. Install system dependencies (GDAL) - see Prerequisites section below

# 3. Verify installation
lunarsight --help

# 4. Run tests to confirm everything works (~60 seconds)
python tests/test_data/download.py   # Download test data
pytest                               # Should show: 395 passed, 2 skipped

For full pipeline demo, you'll also need:

  • LROC NAC imagery (.IMG + .xml files) — use lunarsight acquire to download, or place manually in data/source_images/
  • SPICE kernels in data/kernels/
  • Annotation tool: LabelImg for local annotation, or Roboflow for cloud-based annotation (see Roboflow Workflow)
  • ML frameworks: pip install ultralytics (YOLO) or pip install torch detectron2 (Detectron2)

Installation

Prerequisites

  • Python 3.11+
  • GDAL - For GeoTIFF processing
    # macOS
    brew install gdal
    
    # Ubuntu/Debian
    sudo apt-get install gdal-bin libgdal-dev
    
    # Windows: use OSGeo4W installer (recommended)
    # Download from https://trac.osgeo.org/osgeo4w/
    # Or with conda:
    conda install -c conda-forge gdal
  • SPICE kernels - For lunar geolocation (placed in data/kernels/)

Install Package

git clone https://github.com/ansidian/LunarSight.git
cd LunarSight
pip install .

The installed CLI command is lunarsight; the Python API uses lunar_pipeline package name.

For development (editable install):

pip install -e .

All core dependencies (including imaging libraries like rasterio and Pillow, SPICE support, and test tools) are automatically installed from pyproject.toml.

Optional: ML Dependencies

Training requires framework-specific packages:

# For YOLO training (Phase 3)
pip install ultralytics

# For Detectron2 training (Phase 4)
pip install torch torchvision
pip install 'git+https://github.com/facebookresearch/detectron2.git'

Usage

Running the Full Pipeline

Execute all 5 phases in sequence:

lunarsight run 1-5

Running Individual Phases

Run specific phases using the run command:

# Phase 1: Image processing
lunarsight run imaging

# Phase 2: Annotation conversion
lunarsight run annotation

# Phase 3: YOLO training
lunarsight run yolo

# Phase 4: Detectron2 training
lunarsight run d2

# Phase 5: Inference
lunarsight run inference

Training Only YOLO or Only Detectron2

You can run a subset of training phases:

# YOLO-only workflow (phases 1-3, skip Detectron2)
lunarsight run 1-3

# Detectron2-only workflow (phases 1,2,4, skip YOLO)
lunarsight run 1,2,4

# Run inference with whichever model(s) were trained
lunarsight run 5

This is useful when:

  • You only need one model type for your use case
  • You want faster iteration during development
  • Your hardware doesn't support one of the frameworks

Flexible Phase Selection

The run command supports multiple selection patterns:

# Run a single phase by number
lunarsight run 3

# Run by name or alias
lunarsight run yolo
lunarsight run train-yolo

# Run a range of phases
lunarsight run 1-3

# Run specific phases (comma-separated)
lunarsight run 2,4,5
lunarsight run ann,yolo,inf

# Interactive menu
lunarsight run

Phase aliases:

  • Phase 0: acquire, download
  • Phase 1: imaging, img
  • Phase 2: annotation, ann
  • Phase 3: train-yolo, yolo
  • Phase 4: train-detectron2, d2
  • Phase 5: inference, inf

Logging Options

Control log verbosity with CLI flags:

# Verbose mode (DEBUG level)
lunarsight --verbose run 1-5

# Quiet mode (WARNING level only)
lunarsight --quiet run 1-5

# Default: INFO level
lunarsight run 1-5

GPU vs CPU Mode

The pipeline automatically detects GPU availability:

  • GPU available: Training uses CUDA for acceleration
  • No GPU: Training falls back to CPU automatically

No configuration needed. Both YOLO and Detectron2 will use the best available device.

Note: CPU training is significantly slower but works on any machine. For large datasets, GPU is recommended.

Configuration

The pipeline uses sensible defaults with ./data as the base directory:

Setting Default Description
Base directory ./data All data paths relative to this
Source images ./data/source_images/ LROC NAC .IMG files
SPICE kernels ./data/kernels/ Planetary ephemeris data
Annotations ./data/annotated_images/ XML annotations from LabelImg
Output tiles ./data/raw_tiles/ Generated PNG tiles
Training runs ./data/runs/ Model weights and metrics
Tile metadata ./data/tile_metadata/ Geolocation JSON files

Model defaults: 3 classes (crater, pit, rock), 1024px tiles, 80/20 train/test split, 30 YOLO epochs, 300 Detectron2 iterations.

Just place your data in ./data and run — no config file needed.

Environment Variables (.env)

For Roboflow integration, create a .env file:

# Copy the example file
cp .env.example .env

# Edit with your credentials
ROBOFLOW_API_KEY=your_roboflow_api_key
ROBOFLOW_PROJECT=lunarsight

Note: The .env file is gitignored and never committed. Only needed if using the push/pull commands.

Pipeline Phases

Phase Name Description Input Output
0 acquire Download LROC NAC images from PDS Volume selection .IMG + .xml files in structured dirs
1 imaging Process LROC NAC images, create tiles .IMG files, SPICE kernels PNG tiles, geolocation JSON
2 annotation Convert XML to COCO, train/test split XML annotations, tiles COCO JSON (train/test), split datasets
3 train-yolo Train YOLOv11 model COCO dataset best.pt weights, metrics.json
4 train-detectron2 Train Faster R-CNN (Detectron2) COCO dataset model_final.pth, metrics.json
5 inference Run detection on new images Trained weights, images Predictions, visualizations

Phase Details

Phase 0 - Data Acquisition:

  • Interactive CLI to browse and download LROC NAC images from the PDS archive
  • Supports volume selection (LROLRC_0020 and higher)
  • Downloads .IMG files with matching PDS4 .xml labels
  • Outputs to structured directories: source_images/{volume_id}/{esm}/NAC/
  • Tracks existing downloads to avoid duplicates
# Interactive volume selection
lunarsight acquire

# List available volumes
lunarsight acquire --list-volumes

Phase 1 - Imaging:

  • Reads LROC NAC .IMG files using SPICE for geolocation
  • Generates tiles at configured size (default: 1024×1024)
  • Outputs PNG tiles and geolocation metadata (lat/lon/altitude per tile)

Phase 2 - Annotation:

  • Converts PASCAL VOC XML annotations (from LabelImg) to COCO format
  • Also converts COCO to YOLO format for Phase 3 training
  • Performs train/test split (default: 80/20)
  • Validates COCO schema and file references
  • Reports class distribution per split

Note: After Phase 1 generates tiles, annotate craters, pits, and rocks using either:

Phase 3 - Train YOLO:

  • Trains YOLOv11 on COCO dataset
  • Saves best model weights to runs/yolo/train/weights/best.pt
  • Generates training metrics: mAP@50, mAP@50:95, precision, recall
  • Saves metrics to metrics.json alongside weights

Phase 4 - Train Detectron2:

  • Trains Faster R-CNN with ResNet-50 backbone
  • Saves final model to runs/detectron2/model_final.pth
  • Generates evaluation metrics on test set
  • Saves metrics to metrics.json

Phase 5 - Inference:

  • Auto-discovers trained weights from runs directory
  • Runs both YOLO and Detectron2 models (if available)
  • Batch processing for large datasets (configurable batch_size, default 16)
  • Generates predictions in COCO format
  • Creates visualization images with bounding boxes

Roboflow Workflow

The pipeline integrates with Roboflow for cloud-based annotation. This is an alternative to local annotation with LabelImg — use whichever fits your workflow.

Setup: Install the optional dependency and configure credentials:

pip install '.[roboflow]'
cp .env.example .env   # then add your ROBOFLOW_API_KEY and ROBOFLOW_PROJECT

Pushing Tiles for Annotation

After Phase 1 generates tiles, push them to Roboflow:

# Interactive batch picker
lunarsight push

# Push all batches without prompting
lunarsight push --all

# Use more upload threads (default: 10)
lunarsight push -w 20

The push command:

  • Discovers batch directories in raw_tiles/ with tiles
  • Uploads concurrently with retry logic and rate-limit handling
  • Cleans up local tile directories after successful upload

Pulling Annotations for Training

After annotating in Roboflow, pull the dataset back:

# Pull latest version
lunarsight pull

# Pull a specific version
lunarsight pull --version 3

The pull command:

  • Downloads the annotated dataset from Roboflow
  • Transforms Roboflow's COCO export into the pipeline's unified format
  • Splits data 3-way: 70% train / 20% val / 10% test
  • Converts to YOLO format automatically
  • Backs up any existing annotations before overwriting

After pulling, you can proceed directly to Phase 3 (YOLO) or Phase 4 (Detectron2) training.

Python API

For programmatic usage:

from lunar_pipeline import (
    run_imaging,
    run_annotation,
    run_train_yolo,
    run_train_detectron2,
    run_inference,
    run_all
)
from lunar_pipeline.config import PipelineConfig

# Load configuration (uses ./data defaults)
config = PipelineConfig.from_yaml()

# Run individual phases
run_imaging(config)
run_annotation(config)
weights_yolo = run_train_yolo(config)
weights_d2 = run_train_detectron2(config)
run_inference(config, yolo_weights=weights_yolo, d2_weights=weights_d2, batch_size=16)

# Or run all phases
run_all(config)

# YOLO-only workflow
config = PipelineConfig.from_yaml()
run_imaging(config)
run_annotation(config)
weights = run_train_yolo(config)
run_inference(config, yolo_weights=weights)  # D2 weights optional

Config API

from lunar_pipeline.config import PipelineConfig

# Load default configuration
config = PipelineConfig.from_yaml()

# Access configuration
print(config.paths.base_dir)      # ./data
print(config.model.classes)       # ['crater', 'pit', 'rock']
print(config.model.yolo_epochs)   # 30

Project Structure

LunarSight/
├── src/
│   └── lunar_pipeline/              # Main package
│       ├── phases/                  # Phase modules (5 phases)
│       │   ├── imaging.py           # Phase 1: Tiling & geolocation
│       │   ├── annotation.py        # Phase 2: XML to COCO conversion
│       │   ├── train_yolo.py        # Phase 3: YOLOv11 training
│       │   ├── train_detectron2.py  # Phase 4: Detectron2 training
│       │   └── inference.py         # Phase 5: Detection inference
│       ├── acquisition/             # Phase 0: LROC image download
│       │   ├── runner.py            # Acquisition orchestrator
│       │   ├── downloader.py        # PDS archive download
│       │   ├── volumes.py           # Volume/product indexing
│       │   └── lookup.py            # Image ID → volume lookup
│       ├── roboflow/                # Roboflow integration
│       │   ├── client.py            # API client with lazy validation
│       │   ├── uploader.py          # Batch upload with retry logic
│       │   └── puller.py            # Pull annotations & COCO transform
│       ├── cli.py                   # CLI entry point
│       ├── config.py                # Configuration management
│       ├── validation.py            # Data validation utilities
│       └── __init__.py              # Public API exports
├── utils/                           # Shared utilities
│   ├── exceptions.py                # Exception hierarchy
│   ├── rollback.py                  # Cleanup on failure (RollbackContext)
│   ├── spice.py                     # SPICE kernel manager
│   ├── coco.py                      # COCO format helpers
│   └── paths.py                     # Path validation
├── tests/                           # Test suite
├── data/                            # Default data directory (auto-created)
│   ├── source_images/               # Input: LROC NAC images (.IMG files)
│   │   ├── *.IMG                    # Flat structure (manual placement)
│   │   └── {volume_id}/             # Nested structure (Phase 0 acquisition)
│   │       └── {esm}/NAC/*.IMG
│   ├── kernels/                     # Input: SPICE kernels
│   ├── annotated_images/            # Input: XML annotations
│   ├── raw_tiles/                   # Output: Generated tiles
│   ├── runs/                        # Output: Training results
│   └── tile_metadata/               # Output: Geolocation data
├── .env                             # Secrets (optional, gitignored)
└── pyproject.toml                   # Package metadata

Training Metrics

Both training phases automatically evaluate on the test set and save metrics:

YOLO metrics (data/runs/detect/train_*/weights/metrics.json):

{
  "mAP50": 0.847,
  "mAP50-95": 0.623,
  "precision": 0.891,
  "recall": 0.834
}

Detectron2 metrics (data/runs/detectron2_train/metrics.json):

{
  "bbox/AP": 0.615,
  "bbox/AP50": 0.842,
  "bbox/AP75": 0.687
}

Metrics are displayed as formatted tables during training and saved for later reference.

Development

Running Tests

Test dependencies (pytest, pytest-mock) are included in the package, so no additional installation is needed.

# Run all tests (~60 seconds)
pytest

# Run with coverage
pytest --cov=lunar_pipeline

# Run specific test file
pytest tests/test_phase1_imaging.py

# Run with verbose output
pytest -v

# Show skip reasons for skipped tests
pytest -rs

Expected Results: 395 passed, 2 skipped (with test data)

Test Suite Overview

The test suite provides comprehensive coverage of all pipeline phases. Tests complete in approximately 60 seconds and verify the entire data flow without requiring actual trained model weights.

What the Tests Verify

Test File Tests Purpose
test_phase1_imaging.py 8 Tile generation, geolocation accuracy, output structure, PNG/GeoTIFF creation
test_phase2_annotation.py 13 XML parsing, COCO conversion, train/test splitting, YOLO format conversion
test_phase3_yolo.py 5 YOLO config validation (model name, epochs, batch size, image size)
test_phase4_detectron2.py 2 Detectron2 config validation, dataset registration paths
test_phase5_inference.py ~20 SPICE kernel discovery, CPU/CUDA device detection, batch processing, inference output structure
test_rollback.py 12 RollbackContext cleanup on failure, directory cleanup, edge cases
test_annotation_yolo.py 13 COCO → YOLO format conversion, bbox normalization, data.yaml generation
integration/test_inference_integration.py 9 Batch boundary cases, empty/invalid input handling, mocked ML models
integration/test_annotation_integration.py 14 Malformed XML handling, missing image validation, end-to-end conversion
roboflow/test_client.py 17 API client validation, project creation, credential handling
roboflow/test_uploader.py 30 Batch upload, retry logic, concurrent upload, batch discovery
roboflow/test_puller.py 18 Pull workflow, COCO transform, 3-way split, YOLO conversion

Why Two Tests Are Skipped

Two integration test classes are intentionally skipped:

  1. TestPhase3Integration (test_phase3_yolo.py) — "Requires ultralytics and test data"

    • Full YOLO training integration requires ultralytics library and real training data
    • Unit tests validate config and setup without actual model training
  2. TestPhase4Integration (test_phase4_detectron2.py) — "Requires detectron2 and test data"

    • Full Detectron2 training integration requires detectron2 library and real training data
    • Unit tests validate config and setup without actual model training

These skips are intentional to keep the test suite fast and runnable without ML framework dependencies. The skipped tests are for end-to-end training validation, which requires GPU resources and significant time.

Use pytest -rs to see skip reasons in test output.

Why Tests Tile Only a Few Images

Phase 1 tests use a 4096-pixel tile size (the maximum allowed) instead of the default 1024 pixels. This generates approximately 13 tiles instead of 153 tiles, dramatically reducing test execution time while still validating the tiling logic, geolocation accuracy, and output structure.

Test Data

Tests require sample LROC NAC imagery, SPICE kernels, and annotated tiles located in tests/test_data/.

Test data structure:

tests/test_data/
├── source_images/     # LROC NAC .IMG files with PDS4 .xml labels
├── kernels/           # SPICE kernels (.bsp, .tsc, .tf, etc.)
├── annotated_images/  # Annotated tiles (.png) with VOC XML annotations
├── raw_tiles/         # Generated output (created by tests)
├── runs/              # Generated output (created by tests)
└── download.py        # Automated test data setup script

Setup test data:

# Automatic download (recommended)
python tests/test_data/download.py

# Check if test data is present
python tests/test_data/download.py --check-only

The test fixture automatically downloads test data from GitHub releases if missing. See tests/test_data/README.md for manual setup options.

Without test data: Tests that require real imagery will be skipped with the message "Test data not available. Run tests/test_data/download.py for setup instructions."

Package Installation

# Standard install
pip install .

# Editable install (for development)
pip install -e .

# Verify installation
lunarsight --help
python -c "from lunar_pipeline import run_all; print('OK')"

Troubleshooting

"SPICE kernel not found"

  • Ensure SPICE kernels are placed in data/kernels/
  • Required kernels: planetary constants, lunar frame, and appropriate time kernels

"GDAL not found"

  • Install GDAL system package (see Prerequisites section)
  • Verify with: gdalinfo --version

"No module named 'ultralytics'"

  • Training requires ML framework: pip install ultralytics (for YOLO)
  • Or: pip install torch detectron2 (for Detectron2)

"Training is very slow"

  • No GPU detected — training is running on CPU
  • Install CUDA-compatible PyTorch: pip install torch --index-url https://download.pytorch.org/whl/cu118
  • Verify GPU is available: python -c "import torch; print(torch.cuda.is_available())"

"Invalid COCO format"

  • Check annotation files match expected schema
  • Validation errors show specific issues with annotation ID, filename, and dimensions
  • Bbox bounds validation catches coordinates extending beyond image dimensions
  • Review logs with --verbose flag for detailed error messages

About

Lunar feature detection pipeline using YOLO and Detectron2

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages