From 08b9baa0e096dcf4c5ced4391993e40bd4fcf31d Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 12 Aug 2026 20:49:03 +0200 Subject: [PATCH] Beam stop: a ring too small to judge is too small to judge others by The radial walk decides how far out the beam stop blocks a ring entirely by comparing each ring median against the largest background further out, and it refuses to judge a ring holding fewer than MIN_RING_PIXELS valid pixels - but it was building that outward maximum over every ring, including the ones it had just refused. At the corner of the detector a ring holds nine pixels and its median is one pixel's mean, so a single recorded reflection out there becomes the background that every ring inside it is compared against. Measured on the 38 rotation regression crystals, sampling 59 frames instead of 60: on one crystal the outward maximum moved from a 2544 pixel ring at r = 437 (median 12.53) to a 9 pixel ring at r = 1155 (median 32.37), the threshold went up 2.6x with it, and the walk marched from r = 32 to r = 391 - 33 223 masked pixels became 182 661, everything out to about 13 A declared to be inside the beam stop. The ring medians the walk actually reads changed by less than 1% between the two samples; only the reference did. Taking the maximum over the countable rings alone leaves the mask bit-identical on 38 of 38 at the default 60 frames and on 37 of 38 at 59 frames, the exception being the repair. Over the 114 samples of 38 crystals at 59, 60 and 61 frames, the outward maximum was set by an unjudgeable ring 8 times; 7 of those were within six pixels of the beam centre, where the suffix maximum does not reach the rings that matter, and the eighth is the failure above. --- image_analysis/beam_stop/ShadowFinder.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/image_analysis/beam_stop/ShadowFinder.cpp b/image_analysis/beam_stop/ShadowFinder.cpp index 59a65d9b..b289ab46 100644 --- a/image_analysis/beam_stop/ShadowFinder.cpp +++ b/image_analysis/beam_stop/ShadowFinder.cpp @@ -328,10 +328,14 @@ std::vector ShadowFinder::GetMask() const { // Counting statistics cannot decide this: on a bright dataset the shadow is still well counted. // The comparison is only ever used to answer "is this whole ring inside the stop", never to // judge an individual pixel, so taking the largest background over an outward window is safe - // here in a way it would not be per pixel. + // here in a way it would not be per pixel. It is taken only over the rings this same walk is + // willing to judge, though: at the corner of the detector a ring holds a handful of pixels and + // its median is one pixel's mean, so one recorded reflection out there would otherwise become + // the background every ring inside it is compared against. std::vector outward_max(max_radius + 2, 0.0f); for (int rad = max_radius; rad >= 0; rad--) - outward_max[rad] = std::max(baseline[rad], outward_max[rad + 1]); + outward_max[rad] = std::max(ring_pixels[rad] >= MIN_RING_PIXELS ? baseline[rad] : 0.0f, + outward_max[rad + 1]); int blocked_out_to = -1; for (int rad = 0; rad <= max_radius; rad++) {