From f72911a39deeea6d2a96acef65bfa68109adb5f3 Mon Sep 17 00:00:00 2001 From: Jerome Lesaint Date: Mon, 27 Oct 2025 12:18:49 +0100 Subject: [PATCH 1/2] Add a rtkaddgaussiannoise app --- applications/CMakeLists.txt | 1 + .../rtkaddgaussiannoise/CMakeLists.txt | 13 +++++ applications/rtkaddgaussiannoise/README.md | 0 .../rtkaddgaussiannoise.cxx | 58 +++++++++++++++++++ .../rtkaddgaussiannoise.ggo | 7 +++ 5 files changed, 79 insertions(+) create mode 100644 applications/rtkaddgaussiannoise/CMakeLists.txt create mode 100644 applications/rtkaddgaussiannoise/README.md create mode 100644 applications/rtkaddgaussiannoise/rtkaddgaussiannoise.cxx create mode 100644 applications/rtkaddgaussiannoise/rtkaddgaussiannoise.ggo diff --git a/applications/CMakeLists.txt b/applications/CMakeLists.txt index b4a222711..ff0195dc9 100644 --- a/applications/CMakeLists.txt +++ b/applications/CMakeLists.txt @@ -25,6 +25,7 @@ include(${ITK_USE_FILE}) #----------------------------------------------------------------------------- # Executables +add_subdirectory(rtkaddgaussiannoise) add_subdirectory(rtkamsterdamshroud) add_subdirectory(rtkbackprojections) add_subdirectory(rtkfdk) diff --git a/applications/rtkaddgaussiannoise/CMakeLists.txt b/applications/rtkaddgaussiannoise/CMakeLists.txt new file mode 100644 index 000000000..92e637eef --- /dev/null +++ b/applications/rtkaddgaussiannoise/CMakeLists.txt @@ -0,0 +1,13 @@ +WRAP_GGO(rtkaddgaussiannoise_GGO_C rtkaddgaussiannoise.ggo ${RTK_BINARY_DIR}/rtkVersion.ggo) +add_executable(rtkaddgaussiannoise rtkaddgaussiannoise.cxx ${rtkaddgaussiannoise_GGO_C}) +target_link_libraries(rtkaddgaussiannoise RTK) + +# Installation code +if(NOT RTK_INSTALL_NO_EXECUTABLES) + foreach(EXE_NAME rtkaddgaussiannoise) + install(TARGETS ${EXE_NAME} + RUNTIME DESTINATION ${RTK_INSTALL_RUNTIME_DIR} COMPONENT Runtime + LIBRARY DESTINATION ${RTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries + ARCHIVE DESTINATION ${RTK_INSTALL_ARCHIVE_DIR} COMPONENT Development) + endforeach() +endif() diff --git a/applications/rtkaddgaussiannoise/README.md b/applications/rtkaddgaussiannoise/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/applications/rtkaddgaussiannoise/rtkaddgaussiannoise.cxx b/applications/rtkaddgaussiannoise/rtkaddgaussiannoise.cxx new file mode 100644 index 000000000..252fb5596 --- /dev/null +++ b/applications/rtkaddgaussiannoise/rtkaddgaussiannoise.cxx @@ -0,0 +1,58 @@ +/*========================================================================= + * + * Copyright RTK Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +#include "rtkaddgaussiannoise_ggo.h" +#include "rtkGgoFunctions.h" +#include "rtkConfiguration.h" + +#include +#include + +#include "rtkProjectionsReader.h" +#include "rtkConstantImageSource.h" +#include "rtkAdditiveGaussianNoiseImageFilter.h" + +int +main(int argc, char * argv[]) +{ + GGO(rtkaddgaussiannoise, args_info); + + using OutputPixelType = float; + constexpr unsigned int Dimension = 3; + +#ifdef RTK_USE_CUDA + using ImageType = itk::CudaImage; +#else + using ImageType = itk::Image; +#endif + + auto reader = itk::ImageFileReader::New(); + reader->SetFileName(args_info.input_arg); + + // Add noise + auto noisy = rtk::AdditiveGaussianNoiseImageFilter::New(); + noisy->SetInput(reader->GetOutput()); + noisy->SetMean(args_info.mean_arg); + noisy->SetStandardDeviation(args_info.sigma_arg); + TRY_AND_EXIT_ON_ITK_EXCEPTION(noisy->Update()) + + // Write + TRY_AND_EXIT_ON_ITK_EXCEPTION(itk::WriteImage(noisy->GetOutput(), args_info.output_arg)) + + return EXIT_SUCCESS; +} diff --git a/applications/rtkaddgaussiannoise/rtkaddgaussiannoise.ggo b/applications/rtkaddgaussiannoise/rtkaddgaussiannoise.ggo new file mode 100644 index 000000000..8ea01b9cf --- /dev/null +++ b/applications/rtkaddgaussiannoise/rtkaddgaussiannoise.ggo @@ -0,0 +1,7 @@ +purpose "Add Gaussian noise to analytic projections. By default, mean=0., std=1." + +option "verbose" v "Verbose execution" flag off +option "input" i "Input file name" string yes +option "output" o "Output file name" string +option "mean" m "Noise level (mean)" float no default="0.0" +option "sigma" s "Noise standard deviation (std)" float no default="1.0" From 0942c27a182a8a3366a51d9e95706c73f8bff080 Mon Sep 17 00:00:00 2001 From: Jerome Lesaint Date: Mon, 27 Oct 2025 12:20:41 +0100 Subject: [PATCH 2/2] Add a rtkaddpoissonnoise app --- applications/CMakeLists.txt | 1 + .../rtkaddpoissonnoise/CMakeLists.txt | 13 +++ applications/rtkaddpoissonnoise/README.md | 0 .../rtkaddpoissonnoise/rtkaddpoissonnoise.cxx | 81 +++++++++++++++++++ .../rtkaddpoissonnoise/rtkaddpoissonnoise.ggo | 7 ++ 5 files changed, 102 insertions(+) create mode 100644 applications/rtkaddpoissonnoise/CMakeLists.txt create mode 100644 applications/rtkaddpoissonnoise/README.md create mode 100644 applications/rtkaddpoissonnoise/rtkaddpoissonnoise.cxx create mode 100644 applications/rtkaddpoissonnoise/rtkaddpoissonnoise.ggo diff --git a/applications/CMakeLists.txt b/applications/CMakeLists.txt index ff0195dc9..0cbe4aa9d 100644 --- a/applications/CMakeLists.txt +++ b/applications/CMakeLists.txt @@ -26,6 +26,7 @@ include(${ITK_USE_FILE}) #----------------------------------------------------------------------------- # Executables add_subdirectory(rtkaddgaussiannoise) +add_subdirectory(rtkaddpoissonnoise) add_subdirectory(rtkamsterdamshroud) add_subdirectory(rtkbackprojections) add_subdirectory(rtkfdk) diff --git a/applications/rtkaddpoissonnoise/CMakeLists.txt b/applications/rtkaddpoissonnoise/CMakeLists.txt new file mode 100644 index 000000000..b43fc2e46 --- /dev/null +++ b/applications/rtkaddpoissonnoise/CMakeLists.txt @@ -0,0 +1,13 @@ +WRAP_GGO(rtkaddpoissonnoise_GGO_C rtkaddpoissonnoise.ggo ${RTK_BINARY_DIR}/rtkVersion.ggo) +add_executable(rtkaddpoissonnoise rtkaddpoissonnoise.cxx ${rtkaddpoissonnoise_GGO_C}) +target_link_libraries(rtkaddpoissonnoise RTK) + +# Installation code +if(NOT RTK_INSTALL_NO_EXECUTABLES) + foreach(EXE_NAME rtkaddpoissonnoise) + install(TARGETS ${EXE_NAME} + RUNTIME DESTINATION ${RTK_INSTALL_RUNTIME_DIR} COMPONENT Runtime + LIBRARY DESTINATION ${RTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries + ARCHIVE DESTINATION ${RTK_INSTALL_ARCHIVE_DIR} COMPONENT Development) + endforeach() +endif() diff --git a/applications/rtkaddpoissonnoise/README.md b/applications/rtkaddpoissonnoise/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/applications/rtkaddpoissonnoise/rtkaddpoissonnoise.cxx b/applications/rtkaddpoissonnoise/rtkaddpoissonnoise.cxx new file mode 100644 index 000000000..ee0a135bc --- /dev/null +++ b/applications/rtkaddpoissonnoise/rtkaddpoissonnoise.cxx @@ -0,0 +1,81 @@ +/*========================================================================= + * + * Copyright RTK Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#include +#include +#include +#include +#include +#include +#include + +#include "rtkaddpoissonnoise_ggo.h" +#include "rtkGgoFunctions.h" +#include "rtkConfiguration.h" + +int +main(int argc, char * argv[]) +{ + GGO(rtkaddpoissonnoise, args_info); + + using OutputPixelType = float; + constexpr unsigned int Dimension = 3; + +#ifdef RTK_USE_CUDA + using ImageType = itk::CudaImage; +#else + using ImageType = itk::Image; +#endif + + auto reader = itk::ImageFileReader::New(); + reader->SetFileName(args_info.input_arg); + + // Use ITK to add pre-log Poisson noise + auto multiply = itk::MultiplyImageFilter::New(); + multiply->SetInput(reader->GetOutput()); + multiply->SetConstant(-args_info.muref_arg); + + auto exp = itk::ExpImageFilter::New(); + exp->SetInput(multiply->GetOutput()); + + auto multiply2 = itk::MultiplyImageFilter::New(); + multiply2->SetInput(exp->GetOutput()); + multiply2->SetConstant(args_info.I0_arg); + + auto poisson = itk::ShotNoiseImageFilter::New(); + poisson->SetInput(multiply2->GetOutput()); + + auto threshold = itk::ThresholdImageFilter::New(); + threshold->SetInput(poisson->GetOutput()); + threshold->SetLower(1.); + threshold->SetOutsideValue(1.); + + auto multiply3 = itk::MultiplyImageFilter::New(); + multiply3->SetInput(threshold->GetOutput()); + multiply3->SetConstant(1. / args_info.I0_arg); + + auto log = itk::LogImageFilter::New(); + log->SetInput(multiply3->GetOutput()); + + auto multiply4 = itk::MultiplyImageFilter::New(); + multiply4->SetInput(log->GetOutput()); + multiply4->SetConstant(-1. / args_info.muref_arg); + + itk::WriteImage(multiply4->GetOutput(), args_info.output_arg); + + return EXIT_SUCCESS; +} diff --git a/applications/rtkaddpoissonnoise/rtkaddpoissonnoise.ggo b/applications/rtkaddpoissonnoise/rtkaddpoissonnoise.ggo new file mode 100644 index 000000000..87d9f15e2 --- /dev/null +++ b/applications/rtkaddpoissonnoise/rtkaddpoissonnoise.ggo @@ -0,0 +1,7 @@ +purpose "Add Poisson noise to analytic projections. It estimates the number of photons by applying Beer-Lambert law with the linear attenuation coefficient of Liquid Water at 75keV and then apply a Poisson distribution on that." + +option "verbose" v "Verbose execution" flag off +option "input" i "Input file name" string yes +option "output" o "Output file name" string yes +option "I0" - "Number of impinging photons per pixel." int no +option "muref" - "Reference Linear attenuation coeff. Default: 0.01879" float no default="0.01879"