From 45a8db03d4a89165353fc576d079aa985b54f6d4 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sat, 26 Sep 2026 22:49:32 +0200 Subject: [PATCH] RotationScaleMerge: without a GPU, fold the partials' corr update into the rescale pass RunScalingLoop rescales after every iteration before anything reads corr, so the iteration's UpdateCorr and the rescale are one pass over the partials instead of two: the G and fitted frames as the iteration left them, then the ratio on top - the same two roundings in the same order. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01D1G8gJVAy6gp1K5Dz3NE5C --- image_analysis/scale_merge/RotationScaleMerge.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/image_analysis/scale_merge/RotationScaleMerge.cpp b/image_analysis/scale_merge/RotationScaleMerge.cpp index 3a53277c2..a644b54a9 100644 --- a/image_analysis/scale_merge/RotationScaleMerge.cpp +++ b/image_analysis/scale_merge/RotationScaleMerge.cpp @@ -5439,16 +5439,29 @@ RotationScaleMerge::Result RotationScaleMerge::Run(bool for_search, bool full_st } #endif if (!scaled_on_gpu) { + // RunScalingLoop rescales after every iteration before anything reads corr, so the iteration's + // UpdateCorr is folded into that pass over the partials: the G and the fitted frames as the + // iteration left them, then the rescale on top - the same two roundings, one pass instead of two. + std::vector g_fitted; + std::vector frame_fitted; partial_loop = RunScalingLoop("partials", g_partial, frame_count, smooth_window, /*release_restraint=*/false, [&] { ReducePartialGroupMeans(n_groups, partial_mean); FitPerFrameG(partials, frame_start, frame_count, partial_mean, /*unity=*/false, g_partial); - UpdateCorr(partials, g_partial, frame_scaled_scratch); + g_fitted = g_partial; + frame_fitted = frame_scaled_scratch; }, [&](const std::vector &apply, const std::vector &ratio) { ParallelChunks(static_cast(partials.size()), ThreadsForWork(partials.size(), nthreads), [&](int lo, int hi) { for (int i = lo; i < hi; ++i) { Obs &o = partials[i]; + if (frame_fitted[o.frame]) { // UpdateCorr + const double denom = static_cast(o.partiality) * g_fitted[o.frame]; + if (std::isfinite(o.prescaling_corr) && std::isfinite(denom) && denom > 0.0) + o.corr = static_cast(o.prescaling_corr / denom); + else + o.corr = NAN; + } if (apply[o.frame] && std::isfinite(o.corr)) o.corr = static_cast(o.corr * ratio[o.frame]); }