// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include "JFJochImageReadingWorker.h" #include "../image_analysis/geom_refinement/AssignSpotsToRings.h" #include "../image_analysis/spot_finding/StrongPixelSet.h" #include "../image_analysis/spot_finding/SpotUtils.h" #include "../image_analysis/spot_finding/ImageSpotFinder.h" #include #include JFJochImageReadingWorker::JFJochImageReadingWorker(const SpotFindingSettings& settings, const DiffractionExperiment& experiment, QObject *parent) : QObject(parent), indexing_settings(experiment.GetIndexingSettings()) { spot_finding_settings = settings;; indexing = std::make_unique(indexing_settings); http_reader.Experiment(experiment); file_reader.Experiment(experiment); } void JFJochImageReadingWorker::LoadFile(const QString &filename, qint64 image_number, qint64 summation) { QMutexLocker ul(&m); try { std::shared_ptr dataset; auto start = std::chrono::high_resolution_clock::now(); if (!http_mode && filename == current_file) { logger.Info("File {} already loaded", filename.toStdString()); } else { if (filename.startsWith("http://")) { http_mode = true; http_reader.ReadURL(filename.toStdString()); total_images = http_reader.GetNumberOfImages(); dataset = http_reader.GetDataset(); if (image_number < 0) emit setToolbarMode(JFJochViewerToolbar::ToolbarMode::Autoload); else emit setToolbarMode(JFJochViewerToolbar::ToolbarMode::None); } else { http_mode = false; file_reader.ReadFile(filename.toStdString()); total_images = file_reader.GetNumberOfImages(); dataset = file_reader.GetDataset(); emit setToolbarMode(JFJochViewerToolbar::ToolbarMode::None); } current_image.reset(); current_summation = 1; current_file = filename; curr_experiment = dataset->experiment; curr_experiment.ImportIndexingSettings(indexing_settings); UpdateAzint_i(dataset.get()); emit datasetLoaded(dataset); } auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(end - start).count(); logger.Info("Loaded file {} in {} ms", filename.toStdString(), duration); LoadImage_i(image_number, summation); } catch (std::exception &e) { logger.Error("Error loading file {} {}", filename.toStdString(), e.what()); } } void JFJochImageReadingWorker::CloseFile() { QMutexLocker ul(&m); if (http_mode) http_reader.Close(); else file_reader.Close(); current_image_ptr.reset(); current_image.reset(); current_summation = 1; total_images = 0; current_file = ""; emit imageLoaded({}); emit datasetLoaded({}); } void JFJochImageReadingWorker::LoadImage(int64_t image_number, int64_t summation) { QMutexLocker ul(&m); if ((image_number == current_image) && (current_summation == summation)) return; LoadImage_i(image_number, summation); } void JFJochImageReadingWorker::CalcROI_i() { if (current_image_ptr) { if (roi) current_image_ptr->CalcROI(roi.get()); } } void JFJochImageReadingWorker::UpdateAzint_i(const JFJochReaderDataset *dataset) { if (dataset) { azint_mapping = std::make_unique(curr_experiment, dataset->pixel_mask); image_analysis = std::make_unique(curr_experiment, *azint_mapping, dataset->pixel_mask, indexing.get()); } } void JFJochImageReadingWorker::LoadImage_i(int64_t image_number, int64_t summation) { // Assumes m locked! try { if (summation <= 0 || image_number + summation > total_images) return; std::vector image; auto start = std::chrono::high_resolution_clock::now(); if (http_mode) { if (image_number < 0 && summation != 1) return; current_image_ptr = http_reader.LoadImage(image_number, summation); total_images = http_reader.GetNumberOfImages(); emit datasetLoaded(http_reader.GetDataset()); } else { if (image_number < 0) return; current_image_ptr = file_reader.LoadImage(image_number, summation); } if (!current_image_ptr) { emit imageLoaded({}); return; } current_image = current_image_ptr->ImageData().number; current_summation = summation; auto end = std::chrono::high_resolution_clock::now(); CalcROI_i(); auto end_analysis = std::chrono::high_resolution_clock::now(); auto duration_1 = std::chrono::duration_cast(end - start).count(); auto duration_2 = std::chrono::duration_cast(end_analysis - end).count(); logger.Info("Loaded image {} in {}/{} ms", image_number, duration_1, duration_2); if (auto_reanalyze) ReanalyzeImage_i(); emit imageNumberChanged(total_images, current_image.value()); emit imageLoaded(current_image_ptr); } catch (std::exception &e) { logger.Error("Error loading image {}: {}", image_number, e.what()); } } void JFJochImageReadingWorker::SetROIBox(QRect box) { QMutexLocker ul(&m); roi = std::make_unique("roi1", box.left(), box.right(), box.bottom(), box.top()); if (current_image_ptr) { current_image_ptr->CalcROI(roi.get()); emit imageStatsUpdated(current_image_ptr); } } void JFJochImageReadingWorker::SetROICircle(double x, double y, double radius) { QMutexLocker ul(&m); if (radius <= 0) roi.reset(); else roi = std::make_unique("roi1", x, y, radius); if (current_image_ptr) { current_image_ptr->CalcROI(roi.get()); emit imageStatsUpdated(current_image_ptr); } } void JFJochImageReadingWorker::UpdateDataset_i(const DiffractionExperiment &experiment) { if (!current_image_ptr) return; std::shared_ptr dataset; if (http_mode) { http_reader.UpdateGeomMetadata(experiment); dataset = http_reader.GetDataset(); } else { file_reader.UpdateGeomMetadata(experiment); dataset = file_reader.GetDataset(); } curr_experiment = dataset->experiment; curr_experiment.ImportIndexingSettings(indexing_settings); UpdateAzint_i(dataset.get()); emit datasetLoaded(dataset); current_image_ptr = std::make_shared(current_image_ptr->ImageData(), dataset); CalcROI_i(); if (auto_reanalyze) ReanalyzeImage_i(); emit imageLoaded(current_image_ptr); } void JFJochImageReadingWorker::UpdateDataset(const DiffractionExperiment &experiment) { QMutexLocker ul(&m); UpdateDataset_i(experiment); } void JFJochImageReadingWorker::ReanalyzeImage_i() { if (!current_image_ptr || !azint_mapping || !image_analysis) return; auto start_time = std::chrono::high_resolution_clock::now(); auto new_image = std::make_shared(*current_image_ptr); auto new_image_dataset = new_image->CreateMutableDataset(); new_image_dataset->experiment.ImportIndexingSettings(indexing_settings); new_image_dataset->az_int_bin_to_phi = azint_mapping->GetBinToPhi(); new_image_dataset->az_int_bin_to_q = azint_mapping->GetBinToQ(); new_image_dataset->azimuthal_bins = azint_mapping->GetAzimuthalBinCount(); new_image_dataset->q_bins = azint_mapping->GetQBinCount(); std::vector buffer; AzimuthalIntegrationProfile azint_profile(*azint_mapping); image_analysis->Analyze(new_image->ImageData(), buffer, azint_profile, spot_finding_settings); current_image_ptr = new_image; auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(end_time - start_time); logger.Info("Analysis of image in {} ms", duration.count()); } void JFJochImageReadingWorker::Analyze() { QMutexLocker locker(&m); ReanalyzeImage_i(); emit imageLoaded(current_image_ptr); } void JFJochImageReadingWorker::FindCenter(const UnitCell& calibrant, bool guess) { QMutexLocker locker(&m); if (!current_image_ptr) return; logger.Info("Finding center"); DiffractionGeometry geom = current_image_ptr->Dataset().experiment.GetDiffractionGeometry(); try { if (guess) GuessGeometry(geom, current_image_ptr->ImageData().spots, calibrant); else OptimizeGeometry(geom, current_image_ptr->ImageData().spots, calibrant); } catch (const JFJochException &e) { logger.ErrorException(e); return; } logger.Info("Geometry found X: {} pxl Y: {} pxl Dist: {} mm", geom.GetBeamX_pxl(), geom.GetBeamY_pxl(), geom.GetDetectorDistance_mm()); DiffractionExperiment new_experiment = current_image_ptr->Dataset().experiment; new_experiment.BeamX_pxl(geom.GetBeamX_pxl()).BeamY_pxl(geom.GetBeamY_pxl()) .DetectorDistance_mm(geom.GetDetectorDistance_mm()) .PoniRot1_rad(geom.GetPoniRot1_rad()) .PoniRot2_rad(geom.GetPoniRot2_rad()) .PoniRot3_rad(geom.GetPoniRot3_rad()); UpdateDataset_i(new_experiment); std::vector ring_Q = CalculateXtalRings(calibrant); QVector rings; for (int i = 0; i < 6 && i < ring_Q.size(); i++) { rings.push_back(2 * M_PI / ring_Q[i]); } emit setRings(rings); } void JFJochImageReadingWorker::UpdateSpotFindingSettings(const SpotFindingSettings &settings, const IndexingSettings &indexing, int64_t max_spots, bool reanalyze) { QMutexLocker locker(&m); spot_finding_settings = settings; // "local" indexing settings indexing_settings.Tolerance(indexing.GetTolerance()); indexing_settings.ViableCellMinSpots(indexing.GetViableCellMinSpots()); indexing_settings.IndexIceRings(indexing.GetIndexIceRings()); indexing_settings.UnitCellDistTolerance(indexing.GetUnitCellDistTolerance()); curr_experiment.ImportIndexingSettings(indexing_settings); curr_experiment.MaxSpotCount(max_spots); auto_reanalyze = reanalyze; if (auto_reanalyze) { ReanalyzeImage_i(); emit imageLoaded(current_image_ptr); } }