Upscale Thermal Master P3 thermal-camera JPEGs by 4× using Upscayl.
The Thermal Master P3 has a 192×256 micro-bolometer sensor and the camera firmware bakes a ~5.83× upscaled 1120×1494 JPEG with edge-enhancement halos. This tool downscales the JPEG back to native sensor resolution (or extracts the raw uint16 thermal data from the JPEG's APP3 segment), optionally applies a Wiener-deconvolution sharpening preprocess, and runs Upscayl's NCNN super-resolution model for a clean 4× output (768×1024).
1:1 crops on the canonical discriminating regions — upper-cup-rim (camera-firmware halo around the rim) and belt-ornament (~1px hexagonal spokes at sensor resolution):
No install needed — uvx runs the tool in a one-shot environment from this repo:
uvx --from git+https://github.com/stared/thermal-upscale thermal-upscale photo.jpgOutput: photo_improved.png next to the input (768×1024).
For repeat use, install it once and call directly:
uv tool install git+https://github.com/stared/thermal-upscale
thermal-upscale photo.jpgTo upgrade later: uv tool upgrade thermal-upscale.
- Upscayl desktop app installed. The CLI shells out to the bundled
upscayl-binand reads the bundled NCNN models. macOS path is auto-detected (/Applications/Upscayl.app/...); on Linux/Windows placeupscayl-binon$PATHwith a siblingmodels/directory. - Python 3.13+ (handled automatically by
uv).
# default — JPEG-path, upscayl-standard model
thermal-upscale photo.jpg
# raw-path with PyTorch-optimized Wiener σ=0.81 + upscayl-lite (=RealESRGAN-General-v3)
thermal-upscale photo.jpg --from-raw
# explicit output path
thermal-upscale photo.jpg out.png
# different SR model
thermal-upscale photo.jpg --model 4xHFA2k
# disable sharpening preprocessing in raw mode
thermal-upscale photo.jpg --from-raw --sigma 0| flag | JPEG mode (default) | --from-raw |
|---|---|---|
| output | <input-stem>_improved.png |
same |
--model |
upscayl-standard-4x |
upscayl-lite-4x (= RealESRGAN-General-v3) |
--sigma |
0 (no preproc) |
0.81 (Wiener-deconvolved to match camera-JPEG sharpness) |
--cut-percentile |
n/a | 1.0 (clip 1st & 99th percentile) |
--colormap |
n/a | inferno |
--keep-intermediate saves the 192×256 stage next to the output for inspection.
- JPEG-path (default) is safer: the camera ISP already did bad-pixel correction, non-uniformity correction, and tone-mapping. The Lanczos downscale produces a clean 192×256 input for SR. Slight ISP halos remain.
--from-raw(experimental): bypasses ISP halos by extracting the raw uint16 sensor data from the JPEG's APP3 segments. Exposes the bolometer's fixed-pattern noise — Wiener σ=0.81 sharpens detail to roughly match the camera's gradient energy with about half the camera's halo level on the test set, but FPN can still be visible. Use--sigma 0if the noise gets amplified.
From a 14-model sweep on Thermal Master P3 photos (cups, campfire, person — see LAB_NOTEBOOK.md):
Top — default & primary alternatives
upscayl-standard-4x— reference. Faithful, no halo amplification. Bundled with Upscayl. Slowest (~1.9s).4xNomos8kSC(NCNN port) — clean & sharp without micro-contrast push. The only real alternative to Standard.RealESRGAN_General_x4_v3(NCNN port) — soft but faithful; preserves structure, doesn't hallucinate. Fast (~0.4s). Byte-identical to bundledupscayl-lite-4x.
Keep — fallbacks / aesthetic variants
upscayl-lite-4x— =RealESRGAN_General_x4_v3. Default for--from-raw.high-fidelity-4x— ≈ Standard, slightly softer.4xHFA2k(NCNN port) — painterly, smooths embers without fabricating.digital-art-4x— distinct smoother aesthetic.RealESRGAN_General_WDN_x4_v3— denoised variant; over-soft.
Drop — don't re-run
ultrasharp-4x, remacri-4x, ultramix-balanced-4x, 4x_NMKD-Siax_200k, 4x_NMKD-Superscale-SP_178000_G, 4xLSDIRplusC — either hallucinate textures (ultrasharp invents cup-ridge stripes, NMKD adds grain) or amplify the JPEG halo (remacri).
scripts/ contains the diagnostic and parameter-search programs that produced the chosen defaults (sharpness sweeps across 14 SR models, PyTorch optimization of σ against camera-JPEG gradient energy, FPN diagnostics, etc.). They depend on the [research] extras (torch, requests):
uv sync --extra research
uv run scripts/sharpen_optimize.pySee LAB_NOTEBOOK.md for the chronological log of findings and decisions.
MIT — see LICENSE.

