// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include "ImageAnalysisCPU.h" #include "spot_finding/StrongPixelSet.h" #include "../compression/JFJochDecompress.h" #include "SpotAnalyze.h" ImageAnalysisCPU::ImageAnalysisCPU(const DiffractionExperiment &in_experiment, const AzimuthalIntegration &in_integration, const PixelMask &in_mask) : experiment(in_experiment), integration(in_integration), npixels(experiment.GetPixelsNum()), xpixels(experiment.GetXPixelsNum()), mask_1byte(npixels, 0), spotFinder(in_integration), saturation_limit(experiment.GetSaturationLimit()), roi_count(0), mask(in_mask), indexer(nullptr) { UpdateROI(); for (int i = 0; i < npixels; i++) mask_1byte[i] = (in_mask.GetMask().at(i) != 0); } void ImageAnalysisCPU::UpdateROI() { roi_map = experiment.ExportROIMap(); roi_count = experiment.ROI().size(); roi_names = experiment.ROI().GetROINameMap(); } void ImageAnalysisCPU::Analyze(DataMessage &output, std::vector &image, AzimuthalIntegrationProfile &profile, const SpotFindingSettings &spot_finding_settings) { if ((output.image.GetWidth() != xpixels) || (output.image.GetWidth() * output.image.GetHeight() != npixels)) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mismatch in pixel size"); const uint8_t *image_ptr = output.image.GetUncompressedPtr(image); switch (output.image.GetMode()) { case CompressedImageMode::Int8: Analyze(output, image_ptr, INT8_MIN, INT8_MAX, profile, spot_finding_settings); break; case CompressedImageMode::Int16: Analyze(output, image_ptr, INT16_MIN, INT16_MAX, profile, spot_finding_settings); break; case CompressedImageMode::Int32: Analyze(output, image_ptr, INT32_MIN, INT32_MAX, profile, spot_finding_settings); break; case CompressedImageMode::Uint8: Analyze(output, image_ptr, UINT8_MAX, UINT8_MAX, profile, spot_finding_settings); break; case CompressedImageMode::Uint16: Analyze(output, image_ptr, UINT16_MAX, UINT16_MAX, profile, spot_finding_settings); break; case CompressedImageMode::Uint32: Analyze(output, image_ptr, UINT32_MAX, UINT32_MAX, profile, spot_finding_settings); break; default: throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "RGB/float mode not supported"); } } template void ImageAnalysisCPU::Analyze(DataMessage &output, const uint8_t *in_image, T err_pixel_val, T sat_pixel_val, AzimuthalIntegrationProfile &profile, const SpotFindingSettings &spot_finding_settings) { auto image = (T *) in_image; std::vector roi(roi_count); size_t err_pixels = 0; size_t masked_pixels = 0; size_t sat_pixels = 0; int64_t min_value = INT64_MAX; int64_t max_value = INT64_MIN; if (sat_pixel_val > saturation_limit) sat_pixel_val = static_cast(saturation_limit); auto &pixel_to_bin = integration.GetPixelToBin(); auto &corrections = integration.Corrections(); auto nbins = integration.GetBinNumber(); std::vector updated_image(experiment.GetPixelsNum()); std::vector sum(nbins); std::vector sum2(nbins); std::vector count(nbins); for (int i = 0; i < npixels; i++) { auto bin = pixel_to_bin[i]; auto value = image[i] * corrections[i]; if (mask_1byte[i] != 0) { updated_image[i] = INT32_MIN; ++masked_pixels; } else if (image[i] >= sat_pixel_val) { updated_image[i] = INT32_MIN; ++sat_pixels; } else if (std::is_signed::value && (image[i] == err_pixel_val)) {// Error pixels are possible only for signed types updated_image[i] = INT32_MIN; ++err_pixels; } else { updated_image[i] = static_cast(image[i]); if (image[i] > max_value) max_value = image[i]; if (image[i] < min_value) min_value = image[i]; if (roi_count > 0 && (roi_map[i] != 0)) { int64_t x = i % xpixels; int64_t y = i / xpixels; for (int8_t r = 0; r < roi_count; r++) { if ((roi_map[i] & (1< roi[r].max_count) roi[r].max_count = image[i]; roi[r].x_weighted += x * image[i]; roi[r].y_weighted += y * image[i]; } } } if (bin < nbins) { sum[bin] += value; sum2[bin] += value * value; count[bin] += 1; } } } profile.Clear(integration); profile.Add(sum, count); std::vector spots; if (spot_finding_settings.enable) spots = spotFinder.Run(image, spot_finding_settings); SpotAnalyze(experiment, spot_finding_settings, spots, CompressedImage(updated_image, experiment.GetXPixelsNum(), experiment.GetYPixelsNum()), indexer, output); output.max_viable_pixel_value = max_value; output.min_viable_pixel_value = min_value; output.error_pixel_count = err_pixels; output.saturated_pixel_count = sat_pixels; output.az_int_profile = profile.GetResult(); output.bkg_estimate = profile.GetBkgEstimate(integration.Settings()); for (const auto &[key, val]: roi_names) output.roi[key] = roi[val]; } ImageAnalysisCPU &ImageAnalysisCPU::SetIndexer(IndexerThreadPool *new_indexer) { indexer = new_indexer; return *this; }