From 4e45680e969debf212ab7826502111a93d3c3b26 Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Fri, 19 Jun 2026 13:02:03 +0200 Subject: [PATCH] viewer: worker can update ROIs and recompute them without full re-analysis The reading worker's experiment is the source of truth for ROIs. Add a SetROIDefinition slot that updates curr_experiment.ROI(), rebuilds the analysis ROI engine, mutates the dataset (so the canvas reflects the new ROIs) and recomputes only the ROIs for the current image via RunROIOnly. On image load when full re-analysis is off, ROIs are still computed via AnalyzeROIOnly so the statistics stay current. Co-Authored-By: Claude Opus 4.8 --- viewer/JFJochImageReadingWorker.cpp | 45 ++++++++++++++++++++++++++++- viewer/JFJochImageReadingWorker.h | 4 +++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/viewer/JFJochImageReadingWorker.cpp b/viewer/JFJochImageReadingWorker.cpp index a86e4619..0e8de2c5 100644 --- a/viewer/JFJochImageReadingWorker.cpp +++ b/viewer/JFJochImageReadingWorker.cpp @@ -90,6 +90,7 @@ JFJochImageReadingWorker::JFJochImageReadingWorker(const SpotFindingSettings &se azint_settings(experiment.GetAzimuthalIntegrationSettings()) { qRegisterMetaType>("QVector"); qRegisterMetaType("BrokerStatus"); + qRegisterMetaType("ROIDefinition"); spot_finding_settings = settings; indexing = std::make_unique(indexing_settings); @@ -382,8 +383,16 @@ void JFJochImageReadingWorker::LoadImage_i(int64_t image_number, int64_t summati auto end = std::chrono::high_resolution_clock::now(); - if (auto_reanalyze) + if (auto_reanalyze) { ReanalyzeImage_i(); + } else if (image_analysis && !curr_experiment.ROI().empty()) { + // ROIs are wanted even when a full re-analysis is not; compute only those. + try { + image_analysis->AnalyzeROIOnly(current_image_ptr->ImageData()); + } catch (const std::exception &e) { + logger.Error("ROI-only analysis failed: {}", e.what()); + } + } auto end_analysis = std::chrono::high_resolution_clock::now(); @@ -580,6 +589,40 @@ void JFJochImageReadingWorker::UpdateAzintSettings(const AzimuthalIntegrationSet UpdateDataset_i(std::nullopt); } +void JFJochImageReadingWorker::SetROIDefinition(const ROIDefinition &rois) { + QMutexLocker locker(&m); + SetROIDefinition_i(rois); +} + +void JFJochImageReadingWorker::SetROIDefinition_i(const ROIDefinition &rois) { + // The worker experiment is the source of truth; the analysis ROI engine is rebuilt + // for it so newly loaded images pick up the change automatically. + curr_experiment.ROI().SetROI(rois); + if (image_analysis) + image_analysis->RebuildROI(); + + if (!current_image_ptr) + return; + + // Mutate the dataset too, so the canvas (which draws image->Dataset().experiment.ROI()) + // reflects the edit, then recompute only the ROIs for the current image. + auto mutable_dataset = current_image_ptr->CreateMutableDataset(); + mutable_dataset->experiment.ROI().SetROI(rois); + std::shared_ptr dataset = mutable_dataset; + current_image_ptr = std::make_shared(current_image_ptr->ImageData(), dataset); + + if (image_analysis) { + try { + image_analysis->RunROIOnly(current_image_ptr->ImageData()); + } catch (const std::exception &e) { + logger.Error("ROI-only analysis failed: {}", e.what()); + } + } + + emit datasetLoaded(dataset); + emit imageLoaded(current_image_ptr); +} + void JFJochImageReadingWorker::UpdateUserMask_i(const std::vector &mask) { std::shared_ptr dataset; if (http_mode) { diff --git a/viewer/JFJochImageReadingWorker.h b/viewer/JFJochImageReadingWorker.h index 07144f52..3db9e495 100644 --- a/viewer/JFJochImageReadingWorker.h +++ b/viewer/JFJochImageReadingWorker.h @@ -31,6 +31,7 @@ Q_DECLARE_METATYPE(AzimuthalIntegrationSettings) Q_DECLARE_METATYPE(UnitCell) Q_DECLARE_METATYPE(std::shared_ptr) Q_DECLARE_METATYPE(BrokerStatus) +Q_DECLARE_METATYPE(ROIDefinition) class JFJochImageReadingWorker : public QObject { Q_OBJECT @@ -117,6 +118,7 @@ private: void UpdateDataset_i(const std::optional& experiment); void UpdateAzint_i(const JFJochReaderDataset *dataset); void UpdateUserMask_i(const std::vector &mask); + void SetROIDefinition_i(const ROIDefinition &rois); void setAutoLoadMode_i(AutoloadMode mode); signals: @@ -164,6 +166,8 @@ public slots: void AddROIToUserMask(); void SubtractROIFromUserMask(); + void SetROIDefinition(const ROIDefinition &rois); + void SaveUserMaskTIFF(QString filename); void UploadUserMask(); void ClearUserMask();