diff --git a/viewer/CMakeLists.txt b/viewer/CMakeLists.txt index e0d046ca..251ce2c6 100644 --- a/viewer/CMakeLists.txt +++ b/viewer/CMakeLists.txt @@ -58,6 +58,10 @@ ADD_EXECUTABLE(jfjoch_viewer jfjoch_viewer.cpp JFJochViewerWindow.cpp JFJochView widgets/JFJochOneOverResSqChartView.h JFJochViewerImageROIStatistics.cpp JFJochViewerImageROIStatistics.h + JFJochViewerImageROIStatistics_Box.cpp + JFJochViewerImageROIStatistics_Box.h + JFJochViewerImageROIStatistics_Circle.cpp + JFJochViewerImageROIStatistics_Circle.h ) TARGET_LINK_LIBRARIES(jfjoch_viewer Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Charts Qt6::DBus diff --git a/viewer/JFJochViewerImage.cpp b/viewer/JFJochViewerImage.cpp index 5b4f255f..cf60a2d3 100644 --- a/viewer/JFJochViewerImage.cpp +++ b/viewer/JFJochViewerImage.cpp @@ -728,3 +728,19 @@ void JFJochViewerImage::ShowImageMenu(QMouseEvent *event) { } } } + +void JFJochViewerImage::SetROIBox(QRect box) { + roi_type = RoiType::RoiBox; + roi_box = box; + roiStartPos = roi_box.topLeft(); + roiEndPos = roi_box.bottomRight(); + Redraw(); +} + +void JFJochViewerImage::SetROICircle(double x, double y, double radius) { + roi_type = RoiType::RoiCircle; + roi_box = QRectF(x - radius, y - radius, 2 * radius, 2 * radius).normalized(); + roiStartPos = roi_box.topLeft(); + roiEndPos = roi_box.bottomRight(); + Redraw(); +} diff --git a/viewer/JFJochViewerImage.h b/viewer/JFJochViewerImage.h index 2c55f941..88a15689 100644 --- a/viewer/JFJochViewerImage.h +++ b/viewer/JFJochViewerImage.h @@ -101,6 +101,9 @@ public slots: void highlightIceRings(bool input); void centerOnSpot(double x, double y); + + void SetROIBox(QRect box); + void SetROICircle(double x, double y, double radius); }; diff --git a/viewer/JFJochViewerImageROIStatistics.cpp b/viewer/JFJochViewerImageROIStatistics.cpp index 11bddf81..af450909 100644 --- a/viewer/JFJochViewerImageROIStatistics.cpp +++ b/viewer/JFJochViewerImageROIStatistics.cpp @@ -10,16 +10,29 @@ JFJochViewerImageROIStatistics::JFJochViewerImageROIStatistics(QWidget *parent) QVBoxLayout* layout = new QVBoxLayout(this); box_radio = new QRadioButton("Box", this); - box_radio->setChecked(true); layout->addWidget(box_radio); + box_settings = new JFJochViewerImageROIStatistics_Box(this); + layout->addWidget(box_settings); + circle_radio = new QRadioButton("Circle", this); layout->addWidget(circle_radio); + circle_settings = new JFJochViewerImageROIStatistics_Circle(this); + layout->addWidget(circle_settings); + radio_group = new QButtonGroup(this); radio_group->addButton(box_radio, 1); radio_group->addButton(circle_radio, 2); + connect(box_radio, &QRadioButton::clicked, this, &JFJochViewerImageROIStatistics::BoxButtonClicked); + connect(circle_radio, &QRadioButton::clicked, this, &JFJochViewerImageROIStatistics::CircleButtonClicked); + connect(box_settings, &JFJochViewerImageROIStatistics_Box::Updated, this, &JFJochViewerImageROIStatistics::BoxButtonClicked); + connect(circle_settings, &JFJochViewerImageROIStatistics_Circle::Updated, this, &JFJochViewerImageROIStatistics::CircleButtonClicked); + + circle_settings->Disable(); + box_radio->setChecked(true); + layout->addWidget(new QLabel("", this)); roi_label = new QLabel("", this); layout->addWidget(roi_label); @@ -50,9 +63,29 @@ void JFJochViewerImageROIStatistics::loadImage(std::shared_ptrsetChecked(true); + box_settings->ROIBoxConfigured(box); + circle_settings->Disable(); } void JFJochViewerImageROIStatistics::SetROICircle(double x, double y, double radius) { circle_radio->setChecked(true); + circle_settings->SetROICircle(CircleSettings{.x = x, .y = y, .r = radius}); + box_settings->Disable(); +} + +void JFJochViewerImageROIStatistics::BoxButtonClicked() { + box_radio->setChecked(true); + box_settings->Enable(); + circle_settings->Disable(); + + emit ROIBoxConfigured(box_settings->GetROIBox()); +} + +void JFJochViewerImageROIStatistics::CircleButtonClicked() { + circle_settings->Enable(); + box_settings->Disable(); + circle_radio->setChecked(true); + auto tmp = circle_settings->GetROICircle(); + emit ROICircleConfigured(tmp.x, tmp.y, tmp.r); } diff --git a/viewer/JFJochViewerImageROIStatistics.h b/viewer/JFJochViewerImageROIStatistics.h index 5c538843..447f8cfd 100644 --- a/viewer/JFJochViewerImageROIStatistics.h +++ b/viewer/JFJochViewerImageROIStatistics.h @@ -10,6 +10,8 @@ #include #include "JFJochImageReadingWorker.h" +#include "JFJochViewerImageROIStatistics_Box.h" +#include "JFJochViewerImageROIStatistics_Circle.h" #include "../reader/JFJochReaderImage.h" class JFJochViewerImageROIStatistics : public QWidget { @@ -20,10 +22,16 @@ class JFJochViewerImageROIStatistics : public QWidget { QRadioButton *azim_radio; QButtonGroup *radio_group; + JFJochViewerImageROIStatistics_Box *box_settings; + JFJochViewerImageROIStatistics_Circle *circle_settings; + QLabel *roi_pos; QLabel *roi_label; public: JFJochViewerImageROIStatistics(QWidget *parent); +private slots: + void BoxButtonClicked(); + void CircleButtonClicked(); public slots: void loadImage(std::shared_ptr image); void SetROIBox(QRect box); diff --git a/viewer/JFJochViewerImageROIStatistics_Box.cpp b/viewer/JFJochViewerImageROIStatistics_Box.cpp new file mode 100644 index 00000000..dc49a4be --- /dev/null +++ b/viewer/JFJochViewerImageROIStatistics_Box.cpp @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include +#include "JFJochViewerImageROIStatistics_Box.h" + +#include + +JFJochViewerImageROIStatistics_Box::JFJochViewerImageROIStatistics_Box(QWidget *parent) + : QWidget(parent) { + auto layout = new QHBoxLayout(this); + + setFixedWidth(300); + layout->addWidget(new QLabel("x:")); + + x0 = new NumberLineEdit(0, 10000, 0, 0, "", this); + x0->setFixedWidth(50); + layout->addWidget(x0); + + layout->addWidget(new QLabel(" - ")); + + x1 = new NumberLineEdit(0, 10000, 0, 0, "", this); + x1->setFixedWidth(50); + layout->addWidget(x1); + + layout->addWidget(new QLabel(" y:")); + y0 = new NumberLineEdit(0, 10000, 0, 0, "", this); + y0->setFixedWidth(50); + layout->addWidget(y0); + layout->addWidget(new QLabel(" - ")); + + y1 = new NumberLineEdit(0, 10000, 0, 0, "", this); + y1->setFixedWidth(50); + layout->addWidget(y1); + + connect(x0, &NumberLineEdit::newValue, [this] (float) { emit Updated(); } ); + connect(y0, &NumberLineEdit::newValue, [this] (float) { emit Updated(); } ); + connect(x1, &NumberLineEdit::newValue, [this] (float) { emit Updated(); } ); + connect(y1, &NumberLineEdit::newValue, [this] (float) { emit Updated(); } ); +} + +void JFJochViewerImageROIStatistics_Box::ROIBoxConfigured(QRect box) { + Enable(); + x0->setValue(box.left()); + x1->setValue(box.right()); + y0->setValue(box.top()); + y1->setValue(box.bottom()); +} + +void JFJochViewerImageROIStatistics_Box::Disable() { + x0->setEnabled(false); + x1->setEnabled(false); + y0->setEnabled(false); + y1->setEnabled(false); +} + +void JFJochViewerImageROIStatistics_Box::Enable() { + x0->setEnabled(true); + x1->setEnabled(true); + y0->setEnabled(true); + y1->setEnabled(true); +} + +QRect JFJochViewerImageROIStatistics_Box::GetROIBox() { + int64_t out_x0 = std::lround(x0->value()); + int64_t out_x1 = std::lround(x1->value()); + int64_t out_y0 = std::lround(y0->value()); + int64_t out_y1 = std::lround(y1->value()); + + return QRect(out_x0, out_y0, out_x1 - out_x0, out_y1 - out_y0).normalized(); +} diff --git a/viewer/JFJochViewerImageROIStatistics_Box.h b/viewer/JFJochViewerImageROIStatistics_Box.h new file mode 100644 index 00000000..da88b577 --- /dev/null +++ b/viewer/JFJochViewerImageROIStatistics_Box.h @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#ifndef JFJOCH_JFJOCHVIEWERIMAGEROISTATISTICS_BOX_H +#define JFJOCH_JFJOCHVIEWERIMAGEROISTATISTICS_BOX_H + +#include + +#include "widgets/NumberLineEdit.h" + +class JFJochViewerImageROIStatistics_Box : public QWidget { + Q_OBJECT + + NumberLineEdit *x0 = nullptr; + NumberLineEdit *x1 = nullptr; + NumberLineEdit *y0 = nullptr; + NumberLineEdit *y1 = nullptr; + +public: + JFJochViewerImageROIStatistics_Box(QWidget *parent = nullptr); + QRect GetROIBox(); +signals: + void Updated(); // Signal emitted when Box ROI is set + +public slots: + void ROIBoxConfigured(QRect box); // Signal emitted when Box ROI is set + void Disable(); + void Enable(); +}; + + +#endif //JFJOCH_JFJOCHVIEWERIMAGEROISTATISTICS_BOX_H \ No newline at end of file diff --git a/viewer/JFJochViewerImageROIStatistics_Circle.cpp b/viewer/JFJochViewerImageROIStatistics_Circle.cpp new file mode 100644 index 00000000..d6442f5b --- /dev/null +++ b/viewer/JFJochViewerImageROIStatistics_Circle.cpp @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include +#include + +#include "JFJochViewerImageROIStatistics_Circle.h" + +JFJochViewerImageROIStatistics_Circle::JFJochViewerImageROIStatistics_Circle(QWidget *parent) + :QWidget(parent) { + auto layout = new QHBoxLayout(this); + + setFixedWidth(300); + + layout->addWidget(new QLabel("x: ")); + x = new NumberLineEdit(0, 10000, 0, 1, "", this); + layout->addWidget(x); + + layout->addWidget(new QLabel(" y: ")); + y = new NumberLineEdit(0, 10000, 0, 1, "", this); + layout->addWidget(y); + + + layout->addWidget(new QLabel(" r: ")); + r = new NumberLineEdit(0, 10000, 0, 1, "", this); + layout->addWidget(r); + + connect(x, &NumberLineEdit::newValue, [this] (float) {emit Updated();}); + connect(y, &NumberLineEdit::newValue, [this] (float) {emit Updated();}); + connect(r, &NumberLineEdit::newValue, [this] (float) {emit Updated();}); +} + +void JFJochViewerImageROIStatistics_Circle::SetROICircle(const CircleSettings& input) { + Enable(); + x->setValue(input.x); + y->setValue(input.y); + r->setValue(input.r); +} + +void JFJochViewerImageROIStatistics_Circle::Disable() { + x->setEnabled(false); + y->setEnabled(false); + r->setEnabled(false); +} + +void JFJochViewerImageROIStatistics_Circle::Enable() { + x->setEnabled(true); + y->setEnabled(true); + r->setEnabled(true); +} + +CircleSettings JFJochViewerImageROIStatistics_Circle::GetROICircle() { + return CircleSettings{.x = x->value(), .y = y->value(), .r = r->value()}; +} + diff --git a/viewer/JFJochViewerImageROIStatistics_Circle.h b/viewer/JFJochViewerImageROIStatistics_Circle.h new file mode 100644 index 00000000..ca35aff3 --- /dev/null +++ b/viewer/JFJochViewerImageROIStatistics_Circle.h @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#ifndef JFJOCH_JFJOCHVIEWERIMAGEROISTATISTICS_CIRCLE_H +#define JFJOCH_JFJOCHVIEWERIMAGEROISTATISTICS_CIRCLE_H + +#include + +#include "widgets/NumberLineEdit.h" + +struct CircleSettings { + double x, y, r; +}; + +class JFJochViewerImageROIStatistics_Circle : public QWidget { + Q_OBJECT + + NumberLineEdit *x = nullptr; + NumberLineEdit *y = nullptr; + NumberLineEdit *r = nullptr; +public: + JFJochViewerImageROIStatistics_Circle(QWidget *parent = nullptr); + void SetROICircle(const CircleSettings &input); + CircleSettings GetROICircle(); + + void Disable(); + void Enable(); +signals: + void Updated(); +}; + + +#endif //JFJOCH_JFJOCHVIEWERIMAGEROISTATISTICS_CIRCLE_H \ No newline at end of file diff --git a/viewer/JFJochViewerSidePanel.cpp b/viewer/JFJochViewerSidePanel.cpp index 2c16f619..ecb3ad41 100644 --- a/viewer/JFJochViewerSidePanel.cpp +++ b/viewer/JFJochViewerSidePanel.cpp @@ -31,6 +31,14 @@ JFJochViewerSidePanel::JFJochViewerSidePanel(QWidget *parent) : QWidget(parent) layout->addWidget(roi); connect(this, &JFJochViewerSidePanel::imageLoaded, roi, &JFJochViewerImageROIStatistics::loadImage); + connect(roi, &JFJochViewerImageROIStatistics::ROIBoxConfigured, [this] (QRect box) { + emit ROIBoxConfigured(box); + }); + + connect(roi, &JFJochViewerImageROIStatistics::ROICircleConfigured, [this] (double x, double y, double radius) { + emit ROICircleConfigured(x, y, radius); + }); + layout->addWidget(new TitleLabel("Image features", this)); auto spotToggleCheckBox = new QCheckBox("Show spots", this); diff --git a/viewer/JFJochViewerSidePanel.h b/viewer/JFJochViewerSidePanel.h index 518e1698..840ff327 100644 --- a/viewer/JFJochViewerSidePanel.h +++ b/viewer/JFJochViewerSidePanel.h @@ -40,6 +40,9 @@ signals: void analyze(); void imageLoaded(std::shared_ptr image); + + void ROIBoxConfigured(QRect box); + void ROICircleConfigured(double center_x, double center_y, double radius); public: JFJochViewerSidePanel(QWidget *parent); public slots: diff --git a/viewer/JFJochViewerWindow.cpp b/viewer/JFJochViewerWindow.cpp index 7cffce77..1e4f5af9 100644 --- a/viewer/JFJochViewerWindow.cpp +++ b/viewer/JFJochViewerWindow.cpp @@ -176,6 +176,17 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString connect(viewer, &JFJochViewerImage::roiCircleUpdated, side_panel, &JFJochViewerSidePanel::SetROICircle); + connect(side_panel, &JFJochViewerSidePanel::ROIBoxConfigured, + reading_worker, &JFJochImageReadingWorker::SetROIBox); + + connect(side_panel, &JFJochViewerSidePanel::ROICircleConfigured, + reading_worker, &JFJochImageReadingWorker::SetROICircle); + + connect(side_panel, &JFJochViewerSidePanel::ROIBoxConfigured, + viewer, &JFJochViewerImage::SetROIBox); + + connect(side_panel, &JFJochViewerSidePanel::ROICircleConfigured, + viewer, &JFJochViewerImage::SetROICircle); connect(reading_worker, &JFJochImageReadingWorker::datasetLoaded, dataset_info, &JFJochViewerDatasetInfo::datasetLoaded);