diff --git a/image_analysis/ImageAnalysisCPU.cpp b/image_analysis/ImageAnalysisCPU.cpp index c21cf64b..16d78629 100644 --- a/image_analysis/ImageAnalysisCPU.cpp +++ b/image_analysis/ImageAnalysisCPU.cpp @@ -18,7 +18,8 @@ ImageAnalysisCPU::ImageAnalysisCPU(const DiffractionExperiment &in_experiment, mask_1byte(npixels, 0), spotFinder(in_integration), saturation_limit(experiment.GetSaturationLimit()), - roi_count(0) { + roi_count(0), + mask(in_mask) { nquads = 2; @@ -180,7 +181,7 @@ void ImageAnalysisCPU::Analyze(DataMessage &output, output.az_int_profile = profile.GetResult(); output.bkg_estimate = profile.GetBkgEstimate(integration.Settings()); if ((inference_client != nullptr) && spot_finding_settings.resolution_estimate) - output.resolution_estimate = inference_client->Inference(experiment, image, nquads); + output.resolution_estimate = inference_client->Inference(experiment, mask, image, nquads); for (const auto &[key, val]: roi_names) output.roi[key] = roi[val]; diff --git a/image_analysis/ImageAnalysisCPU.h b/image_analysis/ImageAnalysisCPU.h index 32623308..9569c607 100644 --- a/image_analysis/ImageAnalysisCPU.h +++ b/image_analysis/ImageAnalysisCPU.h @@ -34,6 +34,7 @@ class ImageAnalysisCPU { const int64_t saturation_limit; + const PixelMask &mask; int nquads = 2; template diff --git a/image_analysis/NeuralNetInferenceClient.cpp b/image_analysis/NeuralNetInferenceClient.cpp index 88725ebd..9cfc0c13 100644 --- a/image_analysis/NeuralNetInferenceClient.cpp +++ b/image_analysis/NeuralNetInferenceClient.cpp @@ -65,7 +65,10 @@ void NeuralNetInferenceClient::AddHost(std::string addr) { template -std::vector NeuralNetInferenceClient::PrepareInternal(const DiffractionExperiment& experiment, const T* image, Quarter q) { +std::vector NeuralNetInferenceClient::PrepareInternal(const DiffractionExperiment& experiment, + const PixelMask& mask, + const T* image, + Quarter q) { std::vector ret(512*512); int64_t pool_factor = GetMaxPoolFactor(experiment); @@ -102,31 +105,42 @@ std::vector NeuralNetInferenceClient::PrepareInternal(const DiffractionEx for (int64_t yp = y0; yp < max_yp; yp++) { for (int64_t xp = x0; xp < max_xp; xp++) { int64_t pxl = image[yp * xpixel + xp]; - if (pxl > INT16_MAX) + if (mask.GetMask().at(yp * xpixel + xp) != 0) + pxl = INT64_MAX; + else if (pxl > INT16_MAX) pxl = INT16_MAX; - if (val < pxl) + if (pxl > val) val = pxl; } } - float max_pool = floor(sqrt(static_cast(val))); - ret[512 * y + x] = max_pool; + + if (val == INT64_MAX) + ret[512 * y + x] = 0; + else + ret[512 * y + x] = floor(sqrt(static_cast(val))); } } return ret; } -std::vector NeuralNetInferenceClient::Prepare(const DiffractionExperiment& experiment, const int16_t *image, Quarter q) { - return PrepareInternal(experiment, image, q); +std::vector NeuralNetInferenceClient::Prepare(const DiffractionExperiment& experiment, + const PixelMask& mask, + const int16_t *image, Quarter q) { + return PrepareInternal(experiment, mask, image, q); } -std::vector NeuralNetInferenceClient::Prepare(const DiffractionExperiment& experiment, const int32_t *image, Quarter q) { - return PrepareInternal(experiment, image, q); +std::vector NeuralNetInferenceClient::Prepare(const DiffractionExperiment& experiment, + const PixelMask& mask, + const int32_t *image, Quarter q) { + return PrepareInternal(experiment, mask, image, q); } -std::vector NeuralNetInferenceClient::Prepare(const DiffractionExperiment& experiment, const int8_t *image, Quarter q) { - return PrepareInternal(experiment, image, q); +std::vector NeuralNetInferenceClient::Prepare(const DiffractionExperiment& experiment, + const PixelMask& mask, + const int8_t *image, Quarter q) { + return PrepareInternal(experiment, mask, image, q); } size_t NeuralNetInferenceClient::GetMaxPoolFactor(const DiffractionExperiment& experiment) const { @@ -206,20 +220,23 @@ std::optional NeuralNetInferenceClient::Run(const std::vector &inp } std::optional -NeuralNetInferenceClient::Inference(const DiffractionExperiment &experiment, const void *image, int nquads) { +NeuralNetInferenceClient::Inference(const DiffractionExperiment &experiment, + const PixelMask& mask, + const void *image, + int nquads) { if (!enable) return {}; std::optional quad[4]; if (nquads >= 1) - quad[0] = Inference(experiment, image, Quarter::BottomRight); + quad[0] = Inference(experiment, mask, image, Quarter::BottomRight); if (nquads >= 2) - quad[1] = Inference(experiment, image, Quarter::BottomRight); + quad[1] = Inference(experiment, mask, image, Quarter::BottomRight); if (nquads >= 3) - quad[2] = Inference(experiment, image, Quarter::BottomRight); + quad[2] = Inference(experiment, mask, image, Quarter::BottomRight); if (nquads >= 4) - quad[3] = Inference(experiment, image, Quarter::BottomLeft); + quad[3] = Inference(experiment, mask, image, Quarter::BottomLeft); int count = 0; float sum = 0.0f; @@ -234,7 +251,10 @@ NeuralNetInferenceClient::Inference(const DiffractionExperiment &experiment, con return sum / count; } -std::optional NeuralNetInferenceClient::Inference(const DiffractionExperiment& experiment, const void *image, Quarter q) { +std::optional NeuralNetInferenceClient::Inference(const DiffractionExperiment& experiment, + const PixelMask& mask, + const void *image, + Quarter q) { if (!enable) return {}; @@ -243,21 +263,21 @@ std::optional NeuralNetInferenceClient::Inference(const DiffractionExperi switch (experiment.GetByteDepthImage()) { case 1: if (experiment.IsPixelSigned()) - v = PrepareInternal(experiment, (int8_t *) image, q); + v = PrepareInternal(experiment, mask, (int8_t *) image, q); else - v = PrepareInternal(experiment, (uint8_t *) image, q); + v = PrepareInternal(experiment, mask, (uint8_t *) image, q); break; case 2: if (experiment.IsPixelSigned()) - v = PrepareInternal(experiment, (int16_t *) image, q); + v = PrepareInternal(experiment, mask, (int16_t *) image, q); else - v = PrepareInternal(experiment, (uint16_t *) image, q); + v = PrepareInternal(experiment, mask, (uint16_t *) image, q); break; case 4: if (experiment.IsPixelSigned()) - v = PrepareInternal(experiment, (int32_t *) image, q); + v = PrepareInternal(experiment, mask, (int32_t *) image, q); else - v = PrepareInternal(experiment, (uint32_t *) image, q); + v = PrepareInternal(experiment, mask, (uint32_t *) image, q); break; default: throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Bit depth not supported"); diff --git a/image_analysis/NeuralNetInferenceClient.h b/image_analysis/NeuralNetInferenceClient.h index ab3eaa1e..7d30e82a 100644 --- a/image_analysis/NeuralNetInferenceClient.h +++ b/image_analysis/NeuralNetInferenceClient.h @@ -10,6 +10,7 @@ #include "../common/Logger.h" #include "../common/DiffractionExperiment.h" +#include "../common/PixelMask.h" // Based on model described in: // Mendez, D., Holton, J. M., Lyubimov, A. Y., Hollatz, S., Mathews, I. I., Cichosz, A., Martirosyan, V., @@ -41,7 +42,10 @@ class NeuralNetInferenceClient { void ReturnNode(size_t node); template - std::vector PrepareInternal(const DiffractionExperiment& experiment, const T* image, Quarter q); + std::vector PrepareInternal(const DiffractionExperiment& experiment, + const PixelMask& mask, + const T* image, + Quarter q); public: void AddHost(std::string hostname, uint16_t port); void AddHost(std::string addr); @@ -49,12 +53,12 @@ public: void AddLogger(Logger *logger); size_t GetMaxPoolFactor(const DiffractionExperiment& experiment) const; - std::vector Prepare(const DiffractionExperiment& experiment, const int16_t* image, Quarter q); - std::vector Prepare(const DiffractionExperiment& experiment, const int32_t* image, Quarter q); - std::vector Prepare(const DiffractionExperiment& experiment, const int8_t* image, Quarter q); + std::vector Prepare(const DiffractionExperiment& experiment, const PixelMask& mask, const int16_t* image, Quarter q); + std::vector Prepare(const DiffractionExperiment& experiment, const PixelMask& mask, const int32_t* image, Quarter q); + std::vector Prepare(const DiffractionExperiment& experiment, const PixelMask& mask, const int8_t* image, Quarter q); - std::optional Inference(const DiffractionExperiment& experiment, const void* image, int nquads); - std::optional Inference(const DiffractionExperiment& experiment, const void* image, Quarter q); + std::optional Inference(const DiffractionExperiment& experiment, const PixelMask& mask, const void* image, int nquads); + std::optional Inference(const DiffractionExperiment& experiment, const PixelMask& mask, const void* image, Quarter q); }; diff --git a/receiver/JFJochReceiverFPGA.cpp b/receiver/JFJochReceiverFPGA.cpp index af62d683..dffa6caf 100644 --- a/receiver/JFJochReceiverFPGA.cpp +++ b/receiver/JFJochReceiverFPGA.cpp @@ -426,7 +426,8 @@ void JFJochReceiverFPGA::FrameTransformationThread(uint32_t threadid) { message.receiver_free_send_buf = image_buffer.GetAvailSlots(); message.az_int_profile = az_int_profile_image.GetResult(); message.bkg_estimate = az_int_profile_image.GetBkgEstimate(experiment.GetAzimuthalIntegrationSettings()); - message.resolution_estimate = inference_client.Inference(experiment, transformation.GetImage(), 1); + message.resolution_estimate = inference_client.Inference(experiment, pixel_mask, + transformation.GetImage(), 1); plots.Add(message, az_int_profile_image); scan_result.Add(message); diff --git a/tests/NeuralNetResPredictorTest.cpp b/tests/NeuralNetResPredictorTest.cpp index 46071f1b..6819509f 100644 --- a/tests/NeuralNetResPredictorTest.cpp +++ b/tests/NeuralNetResPredictorTest.cpp @@ -18,6 +18,8 @@ TEST_CASE("NeuralNetResPredictor_Prepare", "[LinearAlgebra][Coord]") { v[1001 * experiment.GetXPixelsNum() + 1000] = 30; v[1001 * experiment.GetXPixelsNum() + 1001] = INT16_MIN; + v[600 * experiment.GetXPixelsNum() + 600] = 121; + v[1050 * experiment.GetXPixelsNum() + 1050] = 52; v[2000 * experiment.GetXPixelsNum() + 1500] = 160; @@ -29,22 +31,64 @@ TEST_CASE("NeuralNetResPredictor_Prepare", "[LinearAlgebra][Coord]") { REQUIRE(predictor.GetMaxPoolFactor(experiment) == 2); - auto br = predictor.Prepare(experiment, v.data(), Quarter::BottomRight); + PixelMask mask(experiment); + std::vector mask_vec(experiment.GetPixelsNum()); + + mask.LoadUserMask(experiment, mask_vec); + + auto br = predictor.Prepare(experiment, mask, v.data(), Quarter::BottomRight); REQUIRE(br.size() == 512 * 512); CHECK(br[0] == 10); CHECK(br[25 * 512 + 25] == 7); CHECK(br[500 * 512 + 250] == 12); - auto tl = predictor.Prepare(experiment, v.data(), Quarter::TopLeft); + auto tl = predictor.Prepare(experiment, mask, v.data(), Quarter::TopLeft); REQUIRE(tl.size() == 512 * 512); CHECK(tl[100 * 512 + 200] == 7); + CHECK(tl[200 * 512 + 200] == 11); - auto tr = predictor.Prepare(experiment, v.data(), Quarter::TopRight); + auto tr = predictor.Prepare(experiment, mask, v.data(), Quarter::TopRight); REQUIRE(tr.size() == 512 * 512); CHECK(tr[100 * 512 + 200] == 8); - auto bl = predictor.Prepare(experiment, v.data(), Quarter::BottomLeft); + auto bl = predictor.Prepare(experiment, mask, v.data(), Quarter::BottomLeft); REQUIRE(bl.size() == 512 * 512); CHECK(bl[100 * 512 + 200] == 6); } + +TEST_CASE("NeuralNetResPredictor_Prepare_PixelMask", "[LinearAlgebra][Coord]") { + DiffractionExperiment experiment(DetJF4M()); + experiment.DetectorDistance_mm(75).IncidentEnergy_keV(12.4).BeamX_pxl(1000).BeamY_pxl(1000); + + std::vector v(experiment.GetPixelsNum(),0); + v[1000 * experiment.GetXPixelsNum() + 1000] = 100; + v[1000 * experiment.GetXPixelsNum() + 1001] = 20; + v[1001 * experiment.GetXPixelsNum() + 1000] = 30; + v[1001 * experiment.GetXPixelsNum() + 1001] = INT16_MIN; + + v[600 * experiment.GetXPixelsNum() + 600] = 121; + + v[1050 * experiment.GetXPixelsNum() + 1050] = 52; + v[2000 * experiment.GetXPixelsNum() + 1500] = 160; + + v[800 * experiment.GetXPixelsNum() + 600] = 49; + v[1200 * experiment.GetXPixelsNum() + 600] = 36; + v[800 * experiment.GetXPixelsNum() + 1400] = 64; + + NeuralNetInferenceClient predictor; + + REQUIRE(predictor.GetMaxPoolFactor(experiment) == 2); + + PixelMask mask(experiment); + std::vector mask_vec(experiment.GetPixelsNum()); + + mask_vec[600 * experiment.GetXPixelsNum() + 600] = 8; + + mask.LoadUserMask(experiment, mask_vec); + + auto tl = predictor.Prepare(experiment, mask, v.data(), Quarter::TopLeft); + REQUIRE(tl.size() == 512 * 512); + CHECK(tl[100 * 512 + 200] == 7); + CHECK(tl[200 * 512 + 200] == 0); +} diff --git a/tools/jfjoch_resonet_test.cpp b/tools/jfjoch_resonet_test.cpp index e12d8f33..93f70ed3 100644 --- a/tools/jfjoch_resonet_test.cpp +++ b/tools/jfjoch_resonet_test.cpp @@ -134,6 +134,8 @@ int main(int argc, char **argv) { std::atomic done = 0; + PixelMask mask(experiment); + std::vector> futures; for (int t = 0; t < nthreads; t++) { futures.emplace_back(std::async(std::launch::async, [&] { @@ -142,7 +144,7 @@ int main(int argc, char **argv) { size_t image_number = i % nimages; const auto image = image_conv.data() + image_number * xpixel * ypixel; - auto val = predictor.Inference(experiment, image, nquads); + auto val = predictor.Inference(experiment, mask, image, nquads); auto iter_end_time = std::chrono::high_resolution_clock::now(); std::chrono::duration iter_diff = iter_end_time - iter_start_time;