Files
Jungfraujoch/viewer/image_viewer/JFJochSimpleImage.cpp
T
leonarski_fandClaude Opus 5 57f9e42382 Viewer: the region of interest belongs to the diffraction view alone
Drawing an ROI only means something where there are detector counts to
accumulate. Gate the gesture on a virtual AllowROI(), true only for
JFJochDiffractionImage: shift-drag, the resize handles, the hover cursor and the
"Clear ROI" context entry now do nothing in the azimuthal, grid-scan and
calibration views, which cannot report anything about a box anyway.

The statistics move out of the base class into the diffraction view and read the
int32 image directly, so no float copy of the detector image is built for them
either. With the labels already converted, image_fp is now untouched by the
diffraction view, and the lazy EnsurePixelValues machinery it needed is gone.
image_fp stays as the base's representation for the views whose data really is
float: the azimuthal profile, the grid-scan 1/sigma^2 map, and the calibration
viewer's eight source types.

Removed with it: the ROI readouts in the calibration and 2D azimuthal windows,
which were the only two consumers of roiCalculated -- the diffraction view
emitted it and nothing listened. Nothing surfaces ROI statistics now; the
pixel-mask case wants rectangles counting excluded pixels and deserves its own
design. JFJochViewerROIResult is still used by the side-panel ROI list, so the
widget stays.

Verified in the GUI: shift-drag in the diffraction view still draws the box,
turns it into a named ROI and runs the statistics; fit-view panel remains
pixel-identical to the pre-series baseline.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 21:32:47 +02:00

116 lines
3.7 KiB
C++

// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "JFJochSimpleImage.h"
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <QMouseEvent>
#include <QtMath>
#include <cstring>
#include <algorithm>
#include "../../common/JFJochException.h"
JFJochSimpleImage::JFJochSimpleImage(QWidget *parent)
: JFJochImage(parent) {
auto *scn = new QGraphicsScene(this);
setScene(scn);
// Repaint only what changed. FullViewportUpdate redraws the entire viewport on any change,
// which is wasted work locally and, on a remote session, uploads far more than was touched.
setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
// The predicted/float image is unreadable with 3-decimal per-pixel labels.
label_decimals_ = 1;
}
void JFJochSimpleImage::setImage(std::shared_ptr<const SimpleImage> img) {
if (img) {
image_ = std::move(img);
loadImageInternal();
RenderImage();
Redraw();
} else {
image_.reset();
W = 0; H = 0;
if (scene())
scene()->clear();
resetScenePointers();
}
}
void JFJochSimpleImage::mouseHover(const QPointF &scenePos, Qt::KeyboardModifiers) {
if (image_) {
// Hover feedback / status bar display
if ((scenePos.x() >= 0)
&& (scenePos.x() < image_->image.GetWidth())
&& (scenePos.y() >= 0)
&& (scenePos.y() < image_->image.GetHeight())) {
const auto ix = int(scenePos.x());
const auto iy = int(scenePos.y());
const auto idx = iy * int(image_->image.GetWidth()) + ix;
if (idx >= 0 && idx < int(image_fp.size()))
emit writeStatusBar(QString("x=%1 y=%2 I=%3")
.arg(scenePos.x(), 0, 'f', 1)
.arg(scenePos.y(), 0, 'f', 1)
.arg(image_fp[size_t(idx)]), 3000);
} else {
emit writeStatusBar("", 1000);
}
}
}
template<class T>
void JFJochSimpleImage::loadImageInternal(const uint8_t *input) {
const size_t W = image_->image.GetWidth();
const size_t H = image_->image.GetHeight();
auto ptr = reinterpret_cast<const T *>(input);
for (int i = 0; i < W * H; i++)
image_fp[i] = static_cast<float>(ptr[i]);
}
void JFJochSimpleImage::loadImageInternal() {
W = image_->image.GetWidth();
H = image_->image.GetHeight();
if (W == 0 || H == 0) return;
image_fp.resize(W * H);
std::vector<uint8_t> image_buffer;
// Access uncompressed data
const uint8_t *src = image_->image.GetUncompressedPtr(image_buffer);
const auto mode = image_->image.GetMode();
switch (mode) {
case CompressedImageMode::Uint8:
loadImageInternal<uint8_t>(src);
break;
case CompressedImageMode::Int8:
loadImageInternal<int8_t>(src);
break;
case CompressedImageMode::Uint16:
loadImageInternal<uint16_t>(src);
break;
case CompressedImageMode::Int16:
loadImageInternal<int16_t>(src);
break;
case CompressedImageMode::Uint32:
loadImageInternal<uint32_t>(src);
break;
case CompressedImageMode::Int32:
loadImageInternal<int32_t>(src);
break;
case CompressedImageMode::Float32:
loadImageInternal<float>(src);
break;
case CompressedImageMode::Float64:
loadImageInternal<double>(src);
break;
default:
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Image format not supported");
}
}