added std to PedestalTrackingHistogram

This commit is contained in:
2026-07-27 10:48:23 +02:00
parent c1d9724eca
commit d5dfb6aa76
3 changed files with 56 additions and 0 deletions
@@ -107,6 +107,7 @@ class PedestalTrackingPixelHistogram {
void push_pedestal_no_update(const NDView<FrameType, 2> &frame);
void update_mean();
NDArray<AxisType, 2> pedestal_mean() const;
NDArray<AxisType, 2> pedestal_std() const;
void fill_async(NDArray<FrameType, 2> &&image);
@@ -119,6 +119,30 @@ void define_pedestal_tracking_pixel_histogram_bindings(py::module &m) {
containing the current cached pedestal mean.
)")
.def(
"pedestal_std",
[](const PedestalTrackingPixelHistogram &self) {
// pedestal_std() flushes + locks + memcpys; do all of
// that without the GIL, only reacquire to wrap into a
// numpy array.
NDArray<PedestalTrackingPixelHistogram::AxisType, 2> *ptr =
nullptr;
{
py::gil_scoped_release release;
ptr = new NDArray<PedestalTrackingPixelHistogram::AxisType,
2>(self.pedestal_std());
}
return return_image_data(ptr);
},
R"(
Snapshot the per-pixel pedestal std stitched together
from all shards.
Returns:
A 2D numpy array (rows x cols, dtype: float64)
containing the current cached pedestal std.
)")
.def(
"fill_async",
[](PedestalTrackingPixelHistogram &self,
@@ -386,6 +386,37 @@ PedestalTrackingPixelHistogram::pedestal_mean() const {
return data;
}
NDArray<PedestalTrackingPixelHistogram::AxisType, 2>
PedestalTrackingPixelHistogram::pedestal_std() const {
// Drain in-flight async fills and serialise with all other fan-outs
// (Fill / PushPedestal / UpdateMean). m_std is overwritten wholesale
// by Pedestal::update_mean, so without the lock we could read torn
// rows mid-update.
flush();
std::lock_guard<std::mutex> lock(fill_mutex_);
NDArray<AxisType, 2> data(
{static_cast<ssize_t>(rows_), static_cast<ssize_t>(cols_)});
// Each partial pedestal stores its slice of m_std in C-order
// [local_rows x cols], identical in layout to the corresponding
// [first_row .. first_row + local_rows)[col] slice of `data`, so
// we can copy each shard with a single memcpy.
const size_t row_stride = static_cast<size_t>(cols_);
for (int t = 0; t < n_threads_; ++t) {
const auto first_row = static_cast<size_t>(row_start(t));
const auto local_rows = static_cast<size_t>(row_count(t));
if (local_rows == 0)
continue;
const auto view = partial_std_[t].view();
std::memcpy(data.data() + first_row * row_stride, view.data(),
local_rows * row_stride * sizeof(AxisType));
}
return data;
}
void PedestalTrackingPixelHistogram::fill_with_threshold_batch_(
std::vector<NDArray<FrameType, 2>> &batch) {
// Called only by the coordinator thread on images already shape-checked