diff --git a/image_analysis/MXAnalysisWithoutFPGA.cpp b/image_analysis/MXAnalysisWithoutFPGA.cpp index a846bf30..4e320d96 100644 --- a/image_analysis/MXAnalysisWithoutFPGA.cpp +++ b/image_analysis/MXAnalysisWithoutFPGA.cpp @@ -14,7 +14,6 @@ MXAnalysisWithoutFPGA::MXAnalysisWithoutFPGA(const DiffractionExperiment &in_exp IndexerThreadPool *in_indexer) : experiment(in_experiment), integration(in_integration), - updated_image(experiment.GetPixelsNum()), roi_count(0), npixels(experiment.GetPixelsNum()), xpixels(experiment.GetXPixelsNum()), @@ -35,6 +34,7 @@ MXAnalysisWithoutFPGA::MXAnalysisWithoutFPGA(const DiffractionExperiment &in_exp mask_1bit[i] = (in_mask.GetMask().at(i) != 0); spotFinder = std::make_unique(experiment.GetXPixelsNum(), experiment.GetYPixelsNum()); + updated_image = spotFinder->GetHostBuffer(); } void MXAnalysisWithoutFPGA::Analyze(DataMessage &output, std::vector &image, AzimuthalIntegrationProfile &profile, @@ -159,10 +159,12 @@ void MXAnalysisWithoutFPGA::Analyze(DataMessage &output, || mask_low_res != settings.low_resolution_limit) UpdateMaskResolution(settings); - const std::vector spots = spotFinder->Run(updated_image.data(), settings, mask_resolution); + const std::vector spots = spotFinder->Run(settings, mask_resolution); SpotAnalyze(experiment, settings, spots, - CompressedImage(updated_image, experiment.GetXPixelsNum(), experiment.GetYPixelsNum()), + CompressedImage(updated_image, sizeof(int32_t) * experiment.GetPixelsNum(), + experiment.GetXPixelsNum(), experiment.GetYPixelsNum(), + CompressedImageMode::Int32), indexer, output); } diff --git a/image_analysis/MXAnalysisWithoutFPGA.h b/image_analysis/MXAnalysisWithoutFPGA.h index 654b950c..5e0a4132 100644 --- a/image_analysis/MXAnalysisWithoutFPGA.h +++ b/image_analysis/MXAnalysisWithoutFPGA.h @@ -19,7 +19,7 @@ class MXAnalysisWithoutFPGA { const DiffractionExperiment &experiment; const AzimuthalIntegration &integration; - std::vector updated_image; + int32_t *updated_image; std::vector roi_map; std::map roi_names; size_t roi_count; @@ -28,7 +28,7 @@ class MXAnalysisWithoutFPGA { size_t xpixels; std::vector mask_1bit; - std::unique_ptr spotFinder; + std::unique_ptr spotFinder; IndexerThreadPool *indexer; uint16_t azint_bins; diff --git a/image_analysis/spot_finding/CMakeLists.txt b/image_analysis/spot_finding/CMakeLists.txt index ba38adf5..44bd6ca1 100644 --- a/image_analysis/spot_finding/CMakeLists.txt +++ b/image_analysis/spot_finding/CMakeLists.txt @@ -7,6 +7,8 @@ ADD_LIBRARY(JFJochSpotFinding STATIC StrongPixelSet.cpp StrongPixelSet.h DetModuleSpotFinder_cpu.h + ImageSpotFinder.cpp + ImageSpotFinder.h ) TARGET_LINK_LIBRARIES(JFJochSpotFinding JFJochCommon) diff --git a/image_analysis/spot_finding/ImageSpotFinder.cpp b/image_analysis/spot_finding/ImageSpotFinder.cpp new file mode 100644 index 00000000..78bf2b87 --- /dev/null +++ b/image_analysis/spot_finding/ImageSpotFinder.cpp @@ -0,0 +1,8 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +// +// Created by leonarski_f on 04.10.25. +// + +#include "ImageSpotFinder.h" \ No newline at end of file diff --git a/image_analysis/spot_finding/ImageSpotFinder.h b/image_analysis/spot_finding/ImageSpotFinder.h new file mode 100644 index 00000000..b3b4b66d --- /dev/null +++ b/image_analysis/spot_finding/ImageSpotFinder.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#ifndef JFJOCH_IMAGESPOTFINDER_H +#define JFJOCH_IMAGESPOTFINDER_H + +#include +#include + +#include "../../common/DiffractionSpot.h" + +class ImageSpotFinder { +public: + virtual ~ImageSpotFinder() = default; + virtual int32_t *GetHostBuffer() = 0; + virtual std::vector Run(const SpotFindingSettings &settings, const std::vector &res_mask) = 0; +}; + + +#endif //JFJOCH_IMAGESPOTFINDER_H \ No newline at end of file diff --git a/image_analysis/spot_finding/ImageSpotFinderCPU.cpp b/image_analysis/spot_finding/ImageSpotFinderCPU.cpp index ee47098b..2b34b298 100644 --- a/image_analysis/spot_finding/ImageSpotFinderCPU.cpp +++ b/image_analysis/spot_finding/ImageSpotFinderCPU.cpp @@ -5,15 +5,19 @@ #include "StrongPixelSet.h" ImageSpotFinderCPU::ImageSpotFinderCPU(size_t in_width, size_t in_height) - : width(in_width), height(in_height) {} + : width(in_width), height(in_height), in_buffer(in_width * in_height) { +} void ImageSpotFinderCPU::nbx(int input) { NBX = input; } -std::vector ImageSpotFinderCPU::Run(const int32_t *input, - const SpotFindingSettings &settings, - const std::vector &res_mask) { +int32_t *ImageSpotFinderCPU::GetHostBuffer() { + return in_buffer.data(); +} + +std::vector ImageSpotFinderCPU::Run(const SpotFindingSettings &settings, + const std::vector &res_mask) { std::vector output; StrongPixelSet strong_pixel_set; @@ -21,11 +25,11 @@ std::vector ImageSpotFinderCPU::Run(const int32_t *input, if (settings.photon_count_threshold > 0) { for (int line = 0; line < height; line++) { for (int col = 0; col < width; col++) { - int32_t pxl_val = input[line * width + col]; + int32_t pxl_val = in_buffer[line * width + col]; if (pxl_val == INT32_MAX || (pxl_val > settings.photon_count_threshold - && pxl_val != INT32_MIN - && !res_mask[line * width + col])) + && pxl_val != INT32_MIN + && !res_mask[line * width + col])) strong_pixel_set.AddStrongPixel(col, line, pxl_val); } } @@ -47,8 +51,8 @@ std::vector ImageSpotFinderCPU::Run(const int32_t *input, for (int col = 0; col < width; col++) { auto pxl = line * width + col; - if (input[pxl] != INT32_MAX && input[pxl] != INT32_MIN) { - int64_t tmp = input[pxl]; + if (in_buffer[pxl] != INT32_MAX && in_buffer[pxl] != INT32_MIN) { + int64_t tmp = in_buffer[pxl]; sum_vert[col] += tmp; sum2_vert[col] += tmp * tmp; valid_vert[col] += 1; @@ -62,8 +66,8 @@ std::vector ImageSpotFinderCPU::Run(const int32_t *input, if (line < height - NBX) { auto pxl = (line + NBX) * width + col; - if (input[pxl] != INT32_MAX && input[pxl] != INT32_MIN) { - int64_t tmp = input[pxl]; + if (in_buffer[pxl] != INT32_MAX && in_buffer[pxl] != INT32_MIN) { + int64_t tmp = in_buffer[pxl]; sum_vert[col] += tmp; sum2_vert[col] += tmp * tmp; valid_vert[col] += 1; @@ -72,8 +76,8 @@ std::vector ImageSpotFinderCPU::Run(const int32_t *input, if (line >= NBX + 1) { auto pxl = (line - (NBX + 1)) * width + col; - if (input[pxl] != INT32_MAX && input[pxl] != INT32_MIN) { - int64_t tmp = input[pxl]; + if (in_buffer[pxl] != INT32_MAX && in_buffer[pxl] != INT32_MIN) { + int64_t tmp = in_buffer[pxl]; sum_vert[col] -= tmp; sum2_vert[col] -= tmp * tmp; valid_vert[col] -= 1; @@ -104,7 +108,7 @@ std::vector ImageSpotFinderCPU::Run(const int32_t *input, valid -= valid_vert[col - NBX - 1]; } - int32_t pxl_val = input[line * width + col]; + int32_t pxl_val = in_buffer[line * width + col]; int64_t var = valid * sum2 - (sum * sum); int64_t in_minus_mean = pxl_val * valid - sum; @@ -113,11 +117,8 @@ std::vector ImageSpotFinderCPU::Run(const int32_t *input, (pxl_val > settings.photon_count_threshold) && // pixel is above count threshold (in_minus_mean > 0) && // pixel value is larger than mean (in_minus_mean * in_minus_mean > std::ceil(var * strong2)) && // pixel is above SNR threshold - (res_mask[line * width + col] == 0))) { - // pixel is within a valid resolution range - std::cout << line << " " << col << std::endl; + (res_mask[line * width + col] == 0))) // pixel is within a valid resolution range strong_pixel_set.AddStrongPixel(col, line, pxl_val); - } } } diff --git a/image_analysis/spot_finding/ImageSpotFinderCPU.h b/image_analysis/spot_finding/ImageSpotFinderCPU.h index a1889265..74d630a2 100644 --- a/image_analysis/spot_finding/ImageSpotFinderCPU.h +++ b/image_analysis/spot_finding/ImageSpotFinderCPU.h @@ -1,13 +1,14 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#ifndef JFJOCH_IMAGESPOTFINDER_H -#define JFJOCH_IMAGESPOTFINDER_H +#ifndef JFJOCH_IMAGESPOTFINDERCPU_H +#define JFJOCH_IMAGESPOTFINDERCPU_H #include #include +#include "ImageSpotFinder.h" #include "SpotFindingSettings.h" #include "../../common/AzimuthalIntegration.h" #include "../../common/DiffractionSpot.h" @@ -17,15 +18,17 @@ // This one is expected to be used in cases, where images are already assembled // and it aims for 100 ms execution -class ImageSpotFinderCPU { +class ImageSpotFinderCPU : public ImageSpotFinder { size_t width; size_t height; + std::vector in_buffer; int NBX = 15; public: + int32_t *GetHostBuffer(); ImageSpotFinderCPU(size_t width, size_t height); void nbx(int input); - std::vector Run(const int32_t *input, const SpotFindingSettings &settings, const std::vector &res_mask); + std::vector Run(const SpotFindingSettings &settings, const std::vector &res_mask); }; #endif //JFJOCH_IMAGESPOTFINDER_H diff --git a/image_analysis/spot_finding/ImageSpotFinderGPU.h b/image_analysis/spot_finding/ImageSpotFinderGPU.h index 4bc34789..3767778f 100644 --- a/image_analysis/spot_finding/ImageSpotFinderGPU.h +++ b/image_analysis/spot_finding/ImageSpotFinderGPU.h @@ -10,10 +10,11 @@ #include #include "SpotFindingSettings.h" #include "StrongPixelSet.h" +#include "ImageSpotFinder.h" struct CudaStreamWrapper; -class ImageSpotFinderGPU { +class ImageSpotFinderGPU : public ImageSpotFinder { std::mutex m; CudaStreamWrapper *cudastream; diff --git a/tests/ImageSpotFinderCPUTest.cpp b/tests/ImageSpotFinderCPUTest.cpp index f92a6792..0c2ab595 100644 --- a/tests/ImageSpotFinderCPUTest.cpp +++ b/tests/ImageSpotFinderCPUTest.cpp @@ -10,7 +10,7 @@ TEST_CASE("ImageSpotFinderCPU_SignalToNoise") { ImageSpotFinderCPU s(width, height); - std::vector input (width * height); + int32_t *input = s.GetHostBuffer(); for (int i = 0; i < width * height; i++) input[i] = (i % 2) * 5 + 5; @@ -29,7 +29,7 @@ TEST_CASE("ImageSpotFinderCPU_SignalToNoise") { }; std::vector mask_resolution(width * height, false); - auto spots = s.Run(input.data(), settings, mask_resolution); + auto spots = s.Run(settings, mask_resolution); REQUIRE(spots.size() == 2); REQUIRE(spots[0].RawCoord().y == 25); @@ -42,7 +42,7 @@ TEST_CASE("ImageSpotFinderCPU_SignalToNoise_Resolution") { ImageSpotFinderCPU s(width, height); - std::vector input (width * height); + int32_t *input = s.GetHostBuffer(); for (int i = 0; i < width * height; i++) input[i] = (i % 2) * 5 + 5; @@ -62,7 +62,7 @@ TEST_CASE("ImageSpotFinderCPU_SignalToNoise_Resolution") { std::vector mask_resolution(width * height, false); mask_resolution[width * 50 + 50] = true; - auto spots = s.Run(input.data(), settings, mask_resolution); + auto spots = s.Run(settings, mask_resolution); REQUIRE(spots.size() == 1); REQUIRE(spots[0].RawCoord().x == 26); @@ -75,7 +75,7 @@ TEST_CASE("ImageSpotFinderCPU_CountThreshold_Resolution") { ImageSpotFinderCPU s(width, height); - std::vector input (width * height); + int32_t *input = s.GetHostBuffer(); for (int i = 0; i < width * height; i++) input[i] = (i % 2) * 5 + 5; @@ -95,7 +95,7 @@ TEST_CASE("ImageSpotFinderCPU_CountThreshold_Resolution") { std::vector mask_resolution(width * height, false); mask_resolution[width * 50 + 50] = true; - auto spots = s.Run(input.data(), settings, mask_resolution); + auto spots = s.Run(settings, mask_resolution); REQUIRE(spots.size() == 2); REQUIRE(spots[0].RawCoord().y == 25); @@ -108,7 +108,7 @@ TEST_CASE("ImageSpotFinderCPU_CountThreshold_Mask") { ImageSpotFinderCPU s( width, height); - std::vector input (width * height); + int32_t *input = s.GetHostBuffer(); for (int i = 0; i < width * height; i++) input[i] = (i % 2) * 5 + 5; @@ -128,7 +128,7 @@ TEST_CASE("ImageSpotFinderCPU_CountThreshold_Mask") { }; std::vector mask_resolution(width * height, false); - auto spots = s.Run(input.data(), settings, mask_resolution); + auto spots = s.Run(settings, mask_resolution); REQUIRE(spots.size() == 3); REQUIRE(spots[0].RawCoord().x == 26); @@ -144,7 +144,7 @@ TEST_CASE("ImageSpotFinderCPU_SignalToNoise_Mask") { size_t height = 100; ImageSpotFinderCPU s(width, height); - std::vector input (width * height); + int32_t *input = s.GetHostBuffer(); for (int i = 0; i < width * height; i++) input[i] = (i % 2) * 5 + 5; @@ -166,7 +166,7 @@ TEST_CASE("ImageSpotFinderCPU_SignalToNoise_Mask") { }; std::vector mask_resolution(width * height, false); - auto spots = s.Run(input.data(), settings, mask_resolution); + auto spots = s.Run(settings, mask_resolution); REQUIRE(spots.size() == 3); REQUIRE(spots[0].RawCoord().x == 26);