Viewer: drop the in-view ROI accumulation, the worker already does it

The statistics shown for a drawn ROI do not come from the view at all. Drawing
one promotes it to a named ROI, roiGeometryEdited goes to the reading worker, and
the worker's per-image results arrive in ImageData().roi, which is what the
Inspector's ROI section displays. So accumulateROI/CalcROI/roiCalculated were a
second implementation of the same thing whose output nothing read -- and the
worker's version is the better one: it handles the mask and it persists per
image.

Remove them. The view now owns only the ROI's geometry and gestures, which is
all the worker needs from it.

This corrects the previous commit's claim that nothing surfaces ROI statistics:
the Inspector does, via the worker. Verified by drawing a box over the beam
centre: Sum 65453, Max 1634, Mean 0.468, centre of mass (786.3, 843.4) against a
beam centre of (764, 850). Note the numbers appear from the next analysed frame
onward, since the worker attaches them at analysis time and the displayed frame
was analysed before the ROI existed -- that behaviour is unchanged here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-26 21:42:30 +02:00
co-authored by Claude Opus 5
parent 85c4908afc
commit ac932676ec
4 changed files with 1 additions and 95 deletions
@@ -877,7 +877,6 @@ void JFJochDiffractionImage::loadImage(std::shared_ptr<const JFJochReaderImage>
LoadImageInternal();
RenderImage();
Redraw();
CalcROI();
} else {
image.reset();
W = 0; H = 0;
@@ -887,8 +886,6 @@ void JFJochDiffractionImage::loadImage(std::shared_ptr<const JFJochReaderImage>
resetScenePointers();
hover_resolution = NAN;
DrawResolutionText();
CalcROI();
}
}
@@ -982,88 +979,7 @@ QString JFJochDiffractionImage::HoverResolutionLabel() const {
return QString("d = %1 \u00C5").arg(QString::number(hover_resolution, 'f', 2));
}
ROIMessage JFJochDiffractionImage::AccumulateROI(
int64_t xmin, int64_t xmax, int64_t ymin, int64_t ymax,
const std::function<bool(int64_t, int64_t)> &inside) const {
int64_t roi_val = 0;
uint64_t roi_val_2 = 0;
int64_t roi_max = INT64_MIN;
uint64_t roi_npixel = 0;
uint64_t roi_npixel_masked = 0;
float x_weighted = 0.0f;
float y_weighted = 0.0f;
// Clamp bounds defensively to the image
xmin = std::max<int64_t>(0, xmin);
ymin = std::max<int64_t>(0, ymin);
xmax = std::min<int64_t>(W, xmax);
ymax = std::min<int64_t>(H, ymax);
const auto &pixels = image->Image();
for (int64_t y = ymin; y < ymax; ++y) {
for (int64_t x = xmin; x < xmax; ++x) {
if (!inside(x, y)) continue;
const int32_t val = pixels[x + W * y];
if (val == SATURATED_PXL_VALUE || val == ERROR_PXL_VALUE) {
roi_npixel_masked++;
} else if (val != GAP_PXL_VALUE) {
x_weighted += static_cast<float>(val) * x;
y_weighted += static_cast<float>(val) * y;
roi_val += val;
roi_val_2 += static_cast<uint64_t>(val) * val;
if (val > roi_max) roi_max = val;
roi_npixel++;
}
}
}
return ROIMessage{
.sum = roi_val,
.sum_square = roi_val_2,
.max_count = roi_max,
.pixels = roi_npixel,
.pixels_masked = roi_npixel_masked,
.x_weighted = std::lroundf(x_weighted),
.y_weighted = std::lroundf(y_weighted),
};
}
void JFJochDiffractionImage::CalcROI() {
if (!image || W * H == 0) {
auto msg = ROIMessage{.pixels = 0, .pixels_masked = 0};
emit roiCalculated(msg);
return;
}
auto box_norm = roiBox.normalized();
// Using the rectangle as-is; you can adjust inclusivity if needed
const int64_t xmin = box_norm.left();
const int64_t xmax = box_norm.right();
const int64_t ymin = box_norm.top();
const int64_t ymax = box_norm.bottom();
ROIMessage msg{};
if (roi_type == RoiType::RoiBox)
msg = AccumulateROI(xmin, xmax, ymin, ymax,
[](int64_t, int64_t) { return true; }); // everything in the rectangle
else {
const QPointF delta = roiStartPos - roiEndPos;
const float cx = static_cast<float>(roiStartPos.x());
const float cy = static_cast<float>(roiStartPos.y());
const float r2 = static_cast<float>(delta.x() * delta.x() + delta.y() * delta.y());
msg = AccumulateROI(xmin, xmax, ymin, ymax,
[cx, cy, r2](int64_t x, int64_t y) {
const float dx = static_cast<float>(x) - cx;
const float dy = static_cast<float>(y) - cy;
return dx * dx + dy * dy <= r2;
});
}
emit roiCalculated(msg);
}
QString JFJochDiffractionImage::PixelLabel(int x, int y) const {
if (!image)
+1 -6
View File
@@ -3,8 +3,6 @@
#pragma once
#include <functional>
#include <QPainterPath>
#include "JFJochImage.h"
@@ -34,9 +32,7 @@ Q_OBJECT
// This is the view that has detector counts, so it is the one that offers an ROI
[[nodiscard]] bool AllowROI() const override { return true; }
void CalcROI() override;
[[nodiscard]] ROIMessage AccumulateROI(int64_t xmin, int64_t xmax, int64_t ymin, int64_t ymax,
const std::function<bool(int64_t, int64_t)> &inside) const;
void drawForeground(QPainter *painter, const QRectF &rect) override;
public:
enum class RingMode {Auto, Estimation, Manual, None, IceRings};
@@ -119,7 +115,6 @@ private:
void mouseHover(const QPointF &scenePos, Qt::KeyboardModifiers modifiers) override;
signals:
void roiCalculated(ROIMessage &output);
void roiGeometryEdited(ROIDefinition rois);
void roiSelected(QString name); // user picked an ROI by clicking it on the image
public slots:
-2
View File
@@ -514,7 +514,6 @@ void JFJochImage::saveImageToFile(bool with_overlay) {
void JFJochImage::clearROIInternal() {
roiBox = QRectF(); // clear any ROI
// Keep current roi_type; ROI simply becomes empty
CalcROI(); // will emit a zeroed ROI message
updateOverlay();
emit writeStatusBar(tr("ROI cleared"), 1500);
}
@@ -602,7 +601,6 @@ void JFJochImage::updateROI() {
}
emit roiCircleUpdated(roiStartPos.x(), roiStartPos.y(), radius);
}
CalcROI();
updateOverlay();
}
-3
View File
@@ -185,9 +185,6 @@ protected:
ResizeHandle hitTestROIHandle(const QPointF& scenePos, qreal tol = 3.0) const;
// Statistics over roiBox, for the view that has pixel values to accumulate
virtual void CalcROI() {}
void updateOverlay();
void RenderImage();
PixelColorMap MakeColorMap() const;