Adds a background worker that aligns every scan angle onto one shared,
zero-padded canvas using a rigid transform only (no scaling): rotation
is taken analytically from the known scan angle, and only the residual
translation is found via FFT phase correlation of each angle's
binarized CH4 dc-mask. An "Aligned View" toggle then redisplays the
currently selected angle/channel resampled onto that shared canvas,
with ROI, CSV export, and waveform-click inspection all kept working.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Previously the FFT was always run unmasked (dc_threshold_mv=-1e9) so the
result could be cached independent of the threshold, with masking applied
afterward as a display-time step. That meant every pixel's CH1 waveform
was read and FFT'd even when most of the scan is background — wasted work
now that the DC map (and its threshold mask) is already known ahead of
time via the DC precompute cache.
compute_rf_image now takes the real threshold and an optional precomputed
dc4_mv array (reused from the DC cache, avoiding a redundant CH4 read),
and skips the FFT for masked-out pixels entirely, same as before this
threshold-caching detour was introduced. The masked-out CH1 samples are
also never read from disk: the boolean valid-pixel mask is applied to the
raw memmap slice before any dtype conversion, so numpy only pages in the
bytes for pixels that pass the threshold.
Threshold is therefore back to being part of the FFT cache key (changing
it now decides which pixels get computed at all, so it can't be satisfied
from a cache built for a different threshold) — but the recompute it
triggers reuses the cached DC4 image and skips both the FFT and the I/O
for masked pixels, so it's much cheaper than the original full-image
compute. Grating and colormap remain pure post-processing with no
recompute.
Verified bit-identical output against the un-optimized reference path on
synthetic data (including scattered, non-row-aligned masking), and timed
on the real 532 GB / 17-angle file: angle 0's FFT (75.2% of pixels above
the default 50 mV threshold) went from ~121s (fully unmasked) to 114s
(FFT skipped, I/O not skipped) to 90.2s with this change (both skipped).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Colormap, DC threshold, velocity grating, and FFT pad-factor changes were
all routing through a full recompute, which is unworkable on large v6
scans where a single angle's FFT can take minutes. These are now applied
as cheap post-processing on cached data instead:
- ComputeWorker computes CH1/Velocity as an unmasked raw FFT plus its DC4
mask image, cached per (angle, bg_sub, n_fft). Threshold masking and
grating scaling are applied to the cached array on redraw, so neither
needs a recompute; colormap changes only touch matplotlib.
- New DcPrecomputeWorker fills a per-angle DC (CH3/CH4) cache in the
background right after load, since DC images are cheap (mean, no FFT)
and make switching angles instant once cached. Progress is shown in the
Scan Info panel.
- New _refresh_display()/_show_image_now() route every settings-changed
handler through the cache first, falling back to the existing threaded
_start_compute() (with a progress popup, now FFT- vs DC-specific) only
on a genuine cache miss.
- File load now defaults to a DC channel instead of CH1/FFT, so opening a
large file shows something in seconds instead of minutes.
Verified against a real 532 GB / 17-angle file: DC compute for one angle
takes ~100s+ (I/O-bound over USB) the first time, but switching to an
already-cached angle takes 0.4s with no compute thread spun up at all.
Audited every widget signal connection for this pass; the spinboxes
already correctly used editingFinished rather than valueChanged — the
recompute-on-every-change bug was in the handlers, not the event type.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 20:36:44 -05:00
1 changed files with 814 additions and 77 deletions
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.