The adaptive finder keeps (local test & ring threshold), so the local test's second pass is only wanted at the ring pixels. Its window there is the first pass's window with the first pass's strong pixels taken out, and those are few: the first pass now records its window sums at the ring pixels, and the second pass subtracts the strong pixels in each window instead of sweeping the whole image again. Integer sums and the same acceptance test (factored into StrongInWindow), so the bits are exactly the dense pass's. CPU-only rotation run of a 16M set: md5-identical output, 262 -> 242 s. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D1G8gJVAy6gp1K5Dz3NE5C
56 lines
2.4 KiB
C++
56 lines
2.4 KiB
C++
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#pragma once
|
|
|
|
|
|
#include <cstddef>
|
|
#include <vector>
|
|
|
|
#include "ImageSpotFinder.h"
|
|
#include "SpotFindingSettings.h"
|
|
#include "../../common/AzimuthalIntegrationMapping.h"
|
|
#include "../../common/DiffractionSpot.h"
|
|
|
|
// This is "slow" spot finder for image-based analysis
|
|
// To complement "fast" PSI detector module based spot finder
|
|
// This one is expected to be used in cases, where images are already assembled
|
|
// and it aims for 100 ms execution
|
|
|
|
class ImageSpotFinderCPU : public ImageSpotFinder {
|
|
// Output of the first pass, and the exclusion mask for the second.
|
|
std::vector<uint32_t> first_pass_buffer;
|
|
|
|
// One detection pass. prev_strong is the previous pass's bitmap, or nullptr for the first pass;
|
|
// a pixel set in it is treated as INT32_MAX, i.e. kept out of every local background it would
|
|
// fall into, and reported strong.
|
|
//
|
|
// With candidates set (SNR test only), the window sums of every candidate pixel are also recorded
|
|
// in candidate_windows, in pixel order.
|
|
void DetectPass(const ImagePreprocessorBuffer &image, const SpotFindingSettings &settings,
|
|
const uint32_t *prev_strong, std::vector<uint32_t> &out,
|
|
const uint32_t *candidates = nullptr);
|
|
|
|
// Local-box sums (centre pixel included) of one candidate pixel, as the first pass saw them.
|
|
struct CandidateWindow {
|
|
int32_t pxl;
|
|
int64_t sum, sum2, valid;
|
|
};
|
|
std::vector<CandidateWindow> candidate_windows;
|
|
|
|
protected:
|
|
// Detect, but with the result wanted only at the candidate pixels (packed like output_buffer):
|
|
// output_buffer ends up holding (Detect's result & candidates). The second pass is not run over
|
|
// the image: a candidate's second-pass window is its first-pass window with the pixels the first
|
|
// pass found strong taken out, and those are few, so they are subtracted from the sums the first
|
|
// pass recorded. Integer sums and the same test, so the bits are exactly Detect's.
|
|
void DetectAt(const ImagePreprocessorBuffer &image, const SpotFindingSettings &settings,
|
|
const std::vector<uint32_t> &candidates);
|
|
|
|
public:
|
|
ImageSpotFinderCPU(int32_t width, int32_t height);
|
|
void Detect(const ImagePreprocessorBuffer &image, const SpotFindingSettings &settings) override;
|
|
};
|
|
|
|
|