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 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 13:56:09 +02:00
co-authored by Claude Opus 4.8
parent a433399106
commit 4e45680e96
2 changed files with 48 additions and 1 deletions
+44 -1
View File
@@ -90,6 +90,7 @@ JFJochImageReadingWorker::JFJochImageReadingWorker(const SpotFindingSettings &se
azint_settings(experiment.GetAzimuthalIntegrationSettings()) {
qRegisterMetaType<QVector<QRect>>("QVector<QRect>");
qRegisterMetaType<BrokerStatus>("BrokerStatus");
qRegisterMetaType<ROIDefinition>("ROIDefinition");
spot_finding_settings = settings;
indexing = std::make_unique<IndexerThreadPool>(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<const JFJochReaderDataset> dataset = mutable_dataset;
current_image_ptr = std::make_shared<JFJochReaderImage>(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<uint32_t> &mask) {
std::shared_ptr<const JFJochReaderDataset> dataset;
if (http_mode) {
+4
View File
@@ -31,6 +31,7 @@ Q_DECLARE_METATYPE(AzimuthalIntegrationSettings)
Q_DECLARE_METATYPE(UnitCell)
Q_DECLARE_METATYPE(std::shared_ptr<const SimpleImage>)
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<DiffractionExperiment>& experiment);
void UpdateAzint_i(const JFJochReaderDataset *dataset);
void UpdateUserMask_i(const std::vector<uint32_t> &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();