Skip to main content

RasterMoves

A modular Python CLI and library for local image upscaling with OpenModelDB models. Each model is an independent plugin, normally a small JSON manifest. Shared PyTorch/Spandrel and ONNX Runtime backends handle architecture loading and inference. Weights are fetched from the model's recorded sources only when needed, verified, and cached for later use.

Version: 0.3.0. Distribution name: rastermoves. See release setup for PyPI, TestPyPI, GitHub Releases and container publishing. It is an independent implementation, not an official OpenModelDB product.

Part of DanceFlow

RasterMoves is the image-upscaling and enhancement component of the DanceFlow family, alongside KeywordMoves, StemLab, DanceMoves, and DanceRudiments. It runs as a standalone Python library or command-line tool; it does not require those other components to be installed. The package, Python import, and executable all use rastermoves.

Version 0.1.1 renamed the original UpscaleLab package. See the migration guide for import, command, plugin, environment-variable, and existing-cache changes, and the changelog for release details.

Install

Python 3.10 or newer is required; Python 3.11 or 3.12 is a practical choice for broad runtime wheel availability. Extract the source archive and run these commands inside its rastermoves directory:

python -m venv .venv
# Linux / macOS:
source .venv/bin/activate
# Windows PowerShell, instead:
# .venv\Scripts\Activate.ps1

python -m pip install --upgrade pip
python -m pip install -e ".[torch,onnx,gdrive]"
rastermoves --version
rastermoves doctor

This installs the two inference backends and optional Google Drive downloader. For a smaller installation, choose only the required extras:

python -m pip install -e ".[torch]"        # PyTorch / Spandrel
python -m pip install -e ".[onnx]"         # ONNX Runtime CPU, without PyTorch
python -m pip install -e .                # Catalogue and downloads only

For NVIDIA acceleration, first install matching PyTorch and torchvision builds using the official PyTorch installer, then install this project's torch extra. The ONNX CUDA alternative is .[onnx-gpu]; do not install onnxruntime and onnxruntime-gpu together. CUDA/cuDNN compatibility is governed by the chosen runtime. PyTorch also supports Apple MPS when that device is available. doctor reports the runtimes and devices it can actually discover.

For a complete NVIDIA development environment after installing the matching CUDA PyTorch build, install every compatible optional feature explicitly. This uses the GPU ONNX runtime instead of the conflicting CPU package:

python -m pip install -e ".[torch,onnx-gpu,refine,trace,gdrive,extra-arches,dev]"
python -m pip check
rastermoves doctor
python -m pytest -q

This path was verified on 3 October 2026 with Python 3.13.14, PyTorch 2.14.1+cu126, torchvision 0.29.1+cu126, ONNX Runtime GPU 1.30.0, Diffusers 0.35.2 and an NVIDIA RTX 4060 Ti. doctor found CUDA through PyTorch and TensorRT/CUDA/CPU ONNX providers; the local suite passed 347 tests with five explicitly opt-in pretrained/download tests skipped. These versions describe that verified environment, not a universal lockfile. Model weights are still downloaded on demand and retain their own licences and storage requirements.

Dependencies have compatibility floors, not a lockfile. Keep inference dependencies updated, especially PyTorch. The core local tests were run on Python 3.13.5; that does not imply all optional third-party runtimes were installed or tested on that version.

Compare every model

# All registered models: bundled, previously synced, and your custom plugins.
rastermoves upscale input.png --all-models -o comparison

# Refresh the full OpenModelDB catalogue first, then attempt every entry.
rastermoves upscale input.png --all-models --sync-models -o full-comparison

# Inspect the planned models, licences and filenames without downloading weights.
rastermoves upscale input.png --all-models --sync-models --dry-run -o full-comparison

# Retry failures/interrupted models; reuse only checksum-verified matching results.
rastermoves upscale input.png --all-models --resume -o full-comparison

Each model runs sequentially and is released before the next one. Successful models produce model-MODEL_ID.png and a provenance sidecar. summary.json records every selected model's success, failure or interruption and is updated as the run proceeds. Failures do not stop later models; the command exits 1 if any model fails, 130 on Ctrl+C, or 0 when all models succeed or are reused.

--all-models by itself does not refresh metadata or secretly download the entire remote catalogue. Add --sync-models (or run rastermoves sync) for that. A fresh installation knows eight model plugins. Full-catalogue comparisons can download many large checkpoints. Catalogue membership is not a guarantee of runtime compatibility: unsupported architectures, unavailable hosts and missing runtimes are recorded as failures, not presented as successful results. Each model's licence still applies.

Use a new output folder, --resume, or --overwrite explicitly. Standard tile, precision, device, final-size, format, alpha, offline and checksum options also apply. One device and precision apply to the whole sweep. If only particular models reject that combination, keep the original summary.json and rerun those model IDs into a separate folder with compatible settings and the same final-size option; changing device or precision is not a valid --resume of the original comparison. See all-model comparisons for details and resume boundaries.

Optional generative detail refinement

RasterMoves can now upscale, then refine at the same dimensions, or refine an already enlarged image. The independent sd15-tile and sdxl-tile workflows use ControlNet Tile with image-to-image diffusion. This synthesises plausible detail; it is not verified recovery of information. Refinement is always opt-in on upscale. Ordinary upscaling, model IDs and existing defaults are unchanged.

# Add the separate diffusion extra. Install the appropriate PyTorch build for your hardware.
python -m pip install -e ".[refine,trace]"

rastermoves refiners
rastermoves upscale input.png -o enhanced.png --refiner sd15-tile --seed 123 --trace
rastermoves refine already-upscaled.png -o enhanced.png --refiner sdxl-tile --seed 123

# White mask pixels protect lettering/faces; mask dimensions must match the working image.
rastermoves refine already-upscaled.png -o enhanced.png --protect-mask protected.png

# Preview without weight downloads, or resume a verified result / interrupted workflow.
rastermoves refine already-upscaled.png -o enhanced.png --dry-run
rastermoves refine already-upscaled.png -o enhanced.png --resume

Every workflow saves enhanced.baseline.png and its report before attempting refinement, plus enhanced.png.json with component revisions, checksums, seeds, parameters and actual denoising-step counts. Failed refinement preserves the baseline; --resume verifies hashes and can reuse it. Outputs must be lossless PNG/WebP/TIFF. Transparency is retained and fully protected pixels are restored from the baseline.

Weights are multi-gigabyte, first-use downloads, pinned to specific Hugging Face commits. No repository Python code is downloaded/executed. The SD1.5 Tile checkpoint uses restricted tensor-only loading; other components require safetensors. Full-precision files are downloaded and cast for inference; low GPU precision does not reduce download size. Component licences apply separately. --offline requires all pinned files cached.

--refine-tile and --refine-overlap control diffusion independently of existing upscaler tiles. On CUDA, --refine-offload model trades speed for reduced resident GPU memory. Existing --trace records refinement stages, with CUDA allocator peaks included in refinement reports when applicable. CPU/MPS routes exist but hardware performance is not promised. Tiling bounds inference work, not total output-buffer RAM.

The heavy refine extra is intentionally not part of all, default dependencies, or the default CPU container. Use .[all,refine] explicitly for both toolsets. upscale --all-models --refiner sd15-tile applies just that refiner to every selected upscaler; there is no implicit refiner/seed cross product. See the complete refinement guide for presets, masks, caching, resume, plugins, test limitations, and the Python API.

Timing and resource traces

python -m pip install -e ".[trace]"  # Also included in .[all] and .[dev]

# A single image: output.png.trace.json (a new numbered file if it already exists).
rastermoves upscale input.png -o output.png --trace

# One timeline for an entire model comparison, with per-model metrics in summary.json.
rastermoves upscale input.png --all-models -o comparison --trace

# Named trace; --trace-file enables recording even without --trace.
rastermoves upscale input.png -o output.png --trace-file timings/run-01.json --trace-interval 0.1

Traces contain wall time, process CPU time/utilization, resident/virtual memory and thread counts, plus system available-memory context. Timed stages distinguish model loading, downloads/cache verification, inference, postprocessing and output writing. Open the Chrome JSON trace in Perfetto to inspect the stage timeline alongside resource counters, or read the JSON directly. A concise run summary is printed to stderr. Batch/all-model defaults are OUTPUT_DIR/trace.json.

This is process-level sampling, not GPU profiling or exact allocation tracking: 100% CPU means one logical CPU, multi-core use can exceed 100%, and memory peaks are sampled estimates that include runtime/allocator memory. Tracing is off by default; no sampler, trace files or psutil import are used until enabled. See the tracing guide for fields, limitations, failure handling, resume and Python API usage.

First upscale

rastermoves upscale input.png -o output.png

The default plugin is 4x-realesr-general-x4v3. The first run fetches its weights; subsequent runs use the verified cache. Images are processed locally and are not uploaded to the model host. By default, inference is FP32 and automatically selects CUDA, then MPS, then CPU for PyTorch; ONNX selects CUDA when available, otherwise CPU.

# Explicit model and CUDA device; save a provenance sidecar
rastermoves upscale input.png -o output.png -m 4x-realesrgan-x4plus --device cuda --report

# A Hugging Face-hosted model (review its non-commercial licence)
rastermoves upscale input.png -o sharp.png -m 4x-UltraSharpV2

# An ONNX-only starter model
rastermoves upscale input.png -o span.png -m 4x-SPANkendata --backend onnx --device cpu

# Resize to a particular width AFTER the native neural upscale
rastermoves upscale cover.png -o cover-3000.png --width 3000

# Batch processing, including subdirectories; retain transparency in PNG output
rastermoves upscale ./originals -o ./upscaled --recursive --report

--scale, --width, --height, and --long-edge specify the final size while preserving aspect ratio. Only one may be selected. The neural model still runs at its native integer scale; a final Lanczos resize produces the requested size. Targets larger than native scale emit a warning: the extra enlargement is not another neural pass.

Model plugins and the OpenModelDB catalogue

Eight independently addressable manifests are bundled. No weights are included. The licence and source details below were transcribed from OpenModelDB; consult the linked record and original author before using or redistributing a model.

Plugin ID Native scale Architecture / format Recorded model licence
4x-realesr-general-x4v3 4x Compact / PTH BSD-3-Clause
4x-realesr-animevideo-v3 4x Compact / PTH BSD-3-Clause
4x-realesrgan-x4plus 4x ESRGAN / PTH BSD-3-Clause
4x-UltraSharpV2 4x DAT / safetensors, ONNX CC-BY-NC-SA-4.0
4x-Remacri 4x ESRGAN / PTH CC-BY-NC-SA-4.0
4x-SPANkendata 4x SPAN / ONNX CC-BY-SA-4.0
4x-LexicaHAT 4x HAT / PTH CC-BY-4.0
2x-NomosUni-span-multijpg 2x SPAN / PTH, Google Drive CC-BY-4.0
rastermoves models
rastermoves models --tag photo
rastermoves models --architecture span --scale 2
rastermoves info 4x-UltraSharpV2

# Import the current catalogue metadata, not every model's weights
rastermoves sync
rastermoves models --json > catalogue.json

sync consumes OpenModelDB's exported JSON catalogue, with its official repository archive as a fallback. Every valid model entry becomes a separate data-driven plugin. The importer retains its architecture, channels, native scale, tags, source URLs, formats, byte sizes, and checksums. Unsupported formats remain visible rather than being mislabeled as runnable. The catalogue endpoint and remote downloads were not exercised in this release validation; local schema and fallback fixtures were tested.

For an unbundled model, pass the exact OpenModelDB ID or model-page URL. It is fetched individually on first use, without requiring a full sync:

rastermoves info https://openmodeldb.info/models/4x-LexicaHAT
rastermoves upscale input.png -o output.png -m https://openmodeldb.info/models/4x-LexicaHAT

# Import from a local OpenModelDB checkout, useful offline or with a pinned revision
rastermoves sync --source /path/to/open-model-database/data/models --offline

Catalogue coverage is not universal inference compatibility. A model must have a supported resource, a working source, and an architecture understood by the installed backend. New architectures, unsupported hosts, face-alignment workflows, multi-input models, video models, and archive-only packages can require an additional plugin. No remote repository Python code is loaded or installed automatically.

Downloads, verification and offline use

Hugging Face sources use huggingface_hub.hf_hub_download. Other supported sources include GitHub releases/raw files and ordinary HTTPS file links. Individual Google Drive file links use the optional gdrive extra. Listed mirrors are tried in order of provider preference: Hugging Face, direct HTTPS, then Google Drive. It does not search for similarly named models and silently substitute third-party weights.

rastermoves download 4x-realesr-general-x4v3 --strict-checksums
rastermoves upscale input.png -o output.png --offline

# Global flags go BEFORE the subcommand
rastermoves --cache-dir ./model-cache download 4x-UltraSharpV2 --backend spandrel
rastermoves --cache-dir ./model-cache upscale input.png -o output.png -m 4x-UltraSharpV2 --offline

Defaults use platform-specific user cache/config directories. RASTERMOVES_CACHE overrides the cache; RASTERMOVES_OFFLINE=1 disables network use through the tool. The cache contains weights, huggingface, catalog.json, and imported-models as needed. Hugging Face's own cache and the verified weight copy can consume duplicate disk space. Once the verified copy exists, inference needs only that copy.

A publisher SHA-256, when supplied, is checked on every cache use. Files without a publisher checksum get a local integrity receipt, which detects later corruption but does not authenticate their origin. --strict-checksums rejects those files. Partial or failed downloads are not published as complete cached weights; file locks protect concurrent writes. The tool rejects HTML error pages and Git LFS pointers. A checksum mismatch is an error, not permission to use the changed file.

Use HF_TOKEN for a Hugging Face account when necessary. The token is handled by the Hub library, never attached to arbitrary HTTP model sources. Public models usually do not require an account. Gated models may require accepting their terms first.

Mega links, pCloud share pages, Drive folders, and compressed archive resources are not automatically resolved. Download those manually through their normal provider, then use a local file:

rastermoves upscale input.png -o output.png --model-file /path/to/model.safetensors
rastermoves upscale input.png -o output.png --model-file /path/to/model.onnx --native-scale 4

Adding -m MODEL_ID to a local-file run verifies matching manifest checksums and metadata when available. Standalone local ONNX defaults to RGB NCHW; nonstandard layout/channel contracts need a manifest. TorchScript is deliberately unsupported.

Memory, tiling and image handling

# Smaller tiles to reduce inference VRAM requirements
rastermoves upscale input.png -o output.png --tile 128 --overlap 24 --tile-pad 16

# Whole-image inference, when memory permits
rastermoves upscale input.png -o output.png --tile 0

# CUDA half precision only for PyTorch models that explicitly support it
rastermoves upscale input.png -o output.png --device cuda --precision fp16

Tiles overlap and are feather-blended, with an additional context halo to reduce boundary artifacts. Sizes are in input-image pixels. Overlap must be smaller than the tile size. Spandrel's descriptor handles model-specific input padding and cropping; ONNX constraints can be supplied in a manifest. GPU out-of-memory failures during supported tiled inference trigger smaller-tile retries. Model loading failures and host RAM exhaustion do not receive that recovery.

Global-context models can behave differently on tiles. The tool respects a Spandrel model's discouraged/internal tiling guidance and runs a whole-image pass unless --force-tiling is supplied. That override may trade image consistency for lower VRAM. There is no promise that feathering eliminates every neural-model boundary artifact.

Tiling limits inference VRAM, not total output RAM. Native-scale results are accumulated in host memory before final resizing. The default native AND final output limit is 64 megapixels; increase --max-output-mp only with sufficient memory. A 3000x3000 input at 4x produces a 144-megapixel intermediate even when the final target is 3000 pixels wide, so it exceeds the default limit. The float RGB accumulation buffer plus weights alone uses about 16 bytes per native output pixel, before other arrays, inference workspaces and encoded output.

Input PNG, JPEG, WebP, BMP and TIFF are supported via Pillow. Output supports PNG, lossless WebP, JPEG quality 95 and TIFF. The pipeline applies EXIF orientation and converts embedded profiles to sRGB. Alpha is handled separately using Lanczos by default; --alpha model sends the alpha channel through the model too. Transparent JPEG output is rejected rather than silently flattened. Input files are never replaced in place; overwriting an existing destination requires --overwrite.

This version is an 8-bit still-image tool. HDR/high-bit-depth input, animated images and multi-page inputs are rejected. EXIF metadata is intentionally not copied: orientation has been applied and stale dimensions/GPS fields are omitted. Neural upscaling can invent or alter detail; it is not forensic reconstruction.

Python API

from rastermoves import Upscaler

with Upscaler("4x-realesr-general-x4v3", device="auto") as upscaler:
    upscaler.upscale_file(
        "input.png", "output.png",
        tile=256, overlap=32, tile_pad=16,
        report=True,
    )
    print(upscaler.last_report)

The same session can process many images without reloading the model. upscale_image accepts and returns a Pillow image. Sessions are not thread-safe; use separate sessions or external serialization. See examples/batch_api.py and the plugin guide.

Agent skill: use and improve RasterMoves

The repository includes the discoverable $use-and-improve-rastermoves skill for image-upscaling work. It wraps the existing CLI and API guidance in a continuous improvement loop: verify the image and provenance, capture friction from the real run, make the smallest reusable improvement, test it, document it here, then commit and verify the focused patch on GitHub.

Six-step RasterMoves loop from intentional image run through verification, workflow improvement, documentation and verified GitHub commit

The loop keeps image results and reusable tool changes connected without committing private inputs, model weights or unsupported claims.

Example requests:

Use $use-and-improve-rastermoves to upscale this cover to 3000 pixels wide, preserve
transparency, verify the output, and improve any reusable part of the workflow you find.

Use $use-and-improve-rastermoves to compare suitable photo models on this image, explain
the visible trade-offs, and turn the clearest workflow gap into a tested patch.

Each resulting improvement adds a concise reproducible command or API example to this README. Add a labelled before/after screenshot or equal-coordinate 100% crops under docs/assets/ only when they materially demonstrate a visual change, comparison, or diagnostic; text-only changes and private source images do not need screenshots. The skill's evaluation checklist defines the evidence, visual checks, and screenshot standard.

The skill does not make generative detail factual, waive model licences, permit private inputs to be committed, or turn a local commit into proof that GitHub received it.

Validation and development

python -m pip install -e ".[dev]"
python -m pytest -q

# Download and run two actual small models: requires both runtimes and network access
python -m pip install -e ".[torch,onnx,dev]"
# Linux / macOS:
RASTERMOVES_LIVE=1 python -m pytest -q tests/test_live.py
# Windows PowerShell, instead:
# $env:RASTERMOVES_LIVE = "1"
# python -m pytest -q tests/test_live.py

The supplied local verification covers cache integrity, catalogue parsing, safe checkpoint loading, image processing, tiled inference, backend contracts and CLI behavior. Real pretrained-model smoke tests were not run in the build environment, where the Spandrel and ONNX runtimes are not installed. This rename validation did not download weights or attempt live pretrained inference. See TESTING.md for the exact results and distinctions between real PyTorch operations, stubbed adapters, and unrun live integrations.

python -m build

A GitHub Actions workflow is included for offline tests and an opt-in manual live smoke-test job. No repository was created and no release was published automatically.

Licence and references

Project source: GPL-3.0-only. Model weights retain their own licences and are not included or relicensed. In particular, UltraSharpV2 and Remacri are recorded as non-commercial models. A model being downloadable does not grant commercial rights. Review the creator's terms separately. See LICENSE, THIRD_PARTY_NOTICES.md, SECURITY.md, and SOURCES.md.

Automated releases and containers

The Release workflow tests the tagged source, builds and validates its wheel/source distribution, then publishes to PyPI, GitHub Releases, and GHCR. TestPyPI and a Docker Hub mirror are optional. Configure Trusted Publishing once, then push a tag matching both version declarations:

git tag -a v0.2.0 -m "RasterMoves 0.2.0"
git push origin v0.2.0

Production uploads do not run on ordinary branch pushes or pull requests. The repository must contain the workflow at the tagged commit. See RELEASING.md for exact setup fields, first-release instructions, TestPyPI rehearsals, failure recovery, and Docker commands. Neither the wheel nor the container includes pretrained weights; they download on demand. The supplied linux/amd64 container includes CPU PyTorch/Spandrel and ONNX Runtime; GPU use remains available through the native Python installation.

After a successful production publication:

python -m pip install "rastermoves[all]"
docker run --rm ghcr.io/kieransimkin/rastermoves:0.2.0 --version

Metadata

Release files for rastermoves 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for rastermoves 0.3.1
File Size Uploaded
rastermoves-0.3.1.tar.gz 164.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rastermoves 0.3.1
File Interpreter ABI Platform
rastermoves-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 255.8 kB

Release files / rastermoves-0.3.1.tar.gz

Download URL rastermoves-0.3.1.tar.gz
Size 164.5 kB
Tags Source
SHA-256 checksum
How to use checksums
4908e009402256632128bc21dd9445d9f668b82dededfd6855a90bb71b114825
BLAKE2b-256 checksum
How to use checksums
ca75cba8f09d4b5327a9ab9c77591cd213a7e6abc110317ec42e85fa21e5d9d6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / rastermoves-0.3.1-py3-none-any.whl

Download URL rastermoves-0.3.1-py3-none-any.whl
Size 91.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
011cc31dba1f916869b31afc296edf0f51da6352e511c856eec4fc24a51ddf29
BLAKE2b-256 checksum
How to use checksums
eefbdd2b66f3bf9a681f786bc4bea8eb04320b58b52199193379a41007c49928
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page