Both were opt-in adaptive-spot refinements that did not help. Soft per-spot weighting was index-rate neutral across the battery (re-ranking only bites when spots exceed the max-spot cap, which weak serial data does not reach). The local-SNR gate was neutral on index rate and degraded merged CC1/2 on flooded XFEL data. Drops the flags, ApplyWeights/FilterByLocalSNR, the per-spot weight field, and the by-weight FilterSpotsByCount branch (now strongest-first only). --adaptive-spots itself is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
45 lines
2.1 KiB
C++
45 lines
2.1 KiB
C++
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#pragma once
|
|
|
|
#include <vector>
|
|
|
|
#include "ImageSpotFinder.h"
|
|
#include "SpotFindingSettings.h"
|
|
#include "../../common/AzimuthalIntegrationMapping.h"
|
|
|
|
// Self-calibrating strong-pixel detector for the offline (rugnux/viewer) path.
|
|
//
|
|
// The classic finder (ImageSpotFinderCPU) marks a pixel strong when it clears a *fixed* photon
|
|
// count AND a local-box SNR. The fixed photon floor is what forces per-dataset tuning: it must sit
|
|
// above the background (wants high) yet not bury weak spots (wants low), and the background level
|
|
// differs per dataset, so the sweet spot is narrow (KR2 ~12 photons, weak OCP ~5).
|
|
//
|
|
// Here the floor is replaced by a per-resolution-ring threshold derived from a single portable
|
|
// number: E = the expected count of noise pixels tolerated per frame (default ~100). For a ring
|
|
// whose (peak-excluded) background mean is mu, the threshold is the smallest count whose Poisson
|
|
// upper tail is <= p = E / N_pixels, max'd with a Gaussian arm mu + z*sigma to absorb read/flat-field
|
|
// excess. Because it is set from the image's own noise, the SAME E lands ~12 photons on KR2 and ~5
|
|
// on OCP with no user input. Detection then is simply value > ring_threshold, fed to the same
|
|
// connected-component builder as the classic finder.
|
|
class AdaptiveSpotFinderCPU : public ImageSpotFinder {
|
|
const AzimuthalIntegrationMapping &mapping;
|
|
|
|
// per-ring scratch, sized to the mapping's bin count
|
|
std::vector<double> ring_sum;
|
|
std::vector<double> ring_sum2;
|
|
std::vector<int64_t> ring_cnt;
|
|
std::vector<float> ring_mean;
|
|
std::vector<float> ring_sigma;
|
|
std::vector<float> ring_thr;
|
|
|
|
void AccumulateRings(const ImagePreprocessorBuffer &image, float clip_k);
|
|
|
|
public:
|
|
explicit AdaptiveSpotFinderCPU(const AzimuthalIntegrationMapping &mapping);
|
|
std::vector<DiffractionSpot> Run(const ImagePreprocessorBuffer &image,
|
|
const SpotFindingSettings &settings,
|
|
const std::vector<bool> &res_mask) override;
|
|
};
|