Dev neb synth - #3
Merged
Merged
Conversation
…checkbox Before/after slider margins now synced via QTimer.singleShot(0) so the deferred call runs after draw_idle() and constrained_layout have settled, preventing the slider from spanning the full window width on mode switch. Adds a Subtract image median checkbox alongside Normalize to peak. When checked, each image's global median is subtracted from its cross-section profile before any normalization, removing the STF background pedestal and shifting profiles to a near-zero baseline. Y-axis label updates to reflect the active combination of both options. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
STF stretch parameters are computed per-image from each image's own sky median and MAD, so cross-sections of the display image can reflect the nonlinear transform rather than real optical differences between filters. Adds _inspector_linear() to report_builder.py that stores the pre-stretch science data as float32 [0, 1] alongside the existing display images. Integer data (uint16 ADUs) is divided by the dtype max; PixInsight float32 data is already in [0, 1]. The 2048 px max-dimension cap from _inspector_display is reused to control NPZ size growth (~2-4x per image vs uint8). Two new entries appear in the inspector section combo — "Original (linear)" and "Starless (linear)" — giving unbiased PSF and filter transmission cross-sections on a common linear scale. Y-axis label updates to reflect the data type and active checkbox state. Old NPZ files without linear_* keys open cleanly with no change in behaviour. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add bottleneck as a dependency and route NaN-aware and median operations on full-image or near-full-image arrays through bn.* instead of np.*, with a transparent ImportError fallback so environments without bottleneck are unaffected. Hot paths benefiting from this change: - core/stretch.py: two bn.median calls in stf_stretch() and stf_stretch_matched() run on the full flattened image array on every display refresh. - analysis/snr_analyzer.py: bn.median on the 2D background model array. - analysis/halo_analyzer.py: bn.median on stacked radial profiles; bn.nanmean / bn.nanstd on the NaN-padded per-star RDF matrix. analysis/image_filters.py has the same one-line bn.median change in _estimate_noise() but is left out of this commit because it also carries unrelated in-progress work. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ion 8e Michelson contrast (C = ΔL/(I_max+I_min)) proved less useful in practice. Weber fraction contrast (c = ΔL/L where L = kernel median) better represents how much brighter-than-background a feature appears, matching Weber's Law. The median denominator is robust to bright filaments and residual star halos that would inflate the mean. Scalar metric uses the 99th percentile of the Weber map (not max) to avoid dark-sky pixels with near-zero median driving the comparison value to extremes. Maps use PowerNorm for display since the output is unbounded. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Change the central load-time conversion in core/astro_image.py from float64 to float32. All FITS/XISF/TIFF input data is at most 16-bit integer before stacking; float32 (24-bit mantissa) represents every possible value exactly while halving memory footprint and yielding 1.5-2x faster element-wise operations through better cache utilisation and wider SIMD lanes. Byte-order normalisation (big-endian FITS >f4 from astropy) remains a free side-effect of the astype() call. Cascading cleanup removes or narrows nine redundant float64 casts in snr_analyzer.py, edge_analyzer.py, and report_builder.py that were no-ops when self.data was already float64. The astroalign registration call in gui/analysis_thread.py retains its explicit float64 cast — astroalign requires it and the cast now does real conversion work. All 205 fast tests pass after the change. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The log-Y radial power overlay hides small, consistent A-vs-B differences in the noise floor. Add a 10*log10(P_A/P_B) ratio curve in a separate panel (not twinx -- see CLAUDE.md) for both the primary/starless and with-stars pairs, readable directly against a 0 dB reference line. Also documents the new pattern and a pre-existing, unrelated bug found during verification (_section_snr crashes when SNR is unchecked) in CLAUDE.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
_plot_snr_pair built a panels list filtered to non-None entries but never checked whether it ended up empty before calling plt.subplots(1, len(panels)), which raised ValueError: Number of columns must be a positive integer, not 0. Reachable any time SNR is unchecked while another metric (e.g. Power Spectrum) is run. Return None instead, matching the guard pattern already used by _plot_radial_overlay/_plot_radial_ratio_db -- both call sites already pipe the result through _img_tag, which turns None into "". Verified end-to-end via the real ReportBuilder.generate() pipeline: the original crash scenario now succeeds, and a real SNR-populated run still renders both SNR map panels correctly (no regression). Updates the CLAUDE.md pitfall entry documented in the prior commit to reflect the fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a shared-nebula-ROI, per-scale A/B ratio metric across std, LoG, wavelet, and Weber contrast (score = median(|detail|) over the region both images agree is nebula, divided by each image's own background noise floor at that scale), plus a new Gradient Magnitude / Edge Sharpness method and noise-normalised display maps so filter A vs B comparisons aren't confounded by differing absolute noise levels. Also fixes the Report Inspector's panel catalog, which used a hardcoded map that had gone stale against STD_KERNEL_SIZES and never included Weber maps at all — it's now derived dynamically from the computed panels so nothing can silently disappear from the Inspector again. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds the exact mean-normalised, ROI-cropped array every std/LoG/wavelet/ Weber/gradient map is computed from as its own "Original Image (ROI)" panel, so the Report Inspector can show the source image content alongside a map, pixel-aligned to the same crop. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…lity gate _extract_esf() rotated the entire ROI and averaged across all rows to build the edge spread function. scipy.ndimage.rotate(reshape=False) clips the box's corners for any oblique angle (worst at 45deg, ~30% of the area), and that zero-padding was getting mixed into the column averages, fabricating a second, spurious transition in the ESF for otherwise-clean edges. Averaging is now restricted to the disc inscribed in the ROI square, the largest region mathematically guaranteed to contain only genuine data at any rotation angle. A new ESF monotonicity check (_esf_quality) catches edges that are still contaminated (e.g. a scan line that genuinely crosses two physical edges, like a thin filament) — in auto-detect mode these are skipped in favour of the next-strongest gradient peak, and if every candidate fails, the least-bad one is shown but clearly flagged "low confidence" in the report rather than silently reporting a meaningless width. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.