diff --git a/Modules/PhotoacousticsAlgorithms/CMakeLists.txt b/Modules/PhotoacousticsAlgorithms/CMakeLists.txt index 428b04798e..7872f0baab 100644 --- a/Modules/PhotoacousticsAlgorithms/CMakeLists.txt +++ b/Modules/PhotoacousticsAlgorithms/CMakeLists.txt @@ -1,19 +1,20 @@ set(dependencies_list MitkCore MitkAlgorithmsExt MitkOpenCVVideoSupport) IF(MITK_USE_OpenCL) add_definitions(-DPHOTOACOUSTICS_USE_GPU) set(dependencies_list ${dependencies_list} MitkOpenCL) message("Using OpenCL in PhotoacousticAlgorithms") ENDIF(MITK_USE_OpenCL) MITK_CREATE_MODULE( SUBPROJECTS DEPENDS ${dependencies_list} #AUTOLOAD_WITH MitkCore INCLUDE_DIRS PUBLIC include INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} - PACKAGE_DEPENDS ITK|ITKFFT+ITKImageCompose+ITKImageIntensity OpenCV + PACKAGE_DEPENDS ITK|ITKFFT+ITKImageCompose+ITKImageIntensity OpenCV TinyXML ) add_subdirectory(test) add_subdirectory(MitkPABeamformingTool) +add_subdirectory(MitkPAResampleCropTool) diff --git a/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/CMakeLists.txt b/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/CMakeLists.txt index 3bd8ae1dec..2ca7c7bd17 100644 --- a/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/CMakeLists.txt +++ b/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/CMakeLists.txt @@ -1,11 +1,11 @@ OPTION(BUILD_PhotoacousticBeamformingTool "Build MiniApp for beamforming of a PA image" OFF) IF(BUILD_PhotoacousticBeamformingTool) PROJECT( MitkPABeamformingTool ) mitk_create_executable(PABeamformingTool DEPENDS MitkCommandLine MitkCore MitkPhotoacousticsAlgorithms - PACKAGE_DEPENDS + PACKAGE_DEPENDS TinyXML CPP_FILES PABeamformingTool.cpp) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) ENDIF() diff --git a/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/PABeamformingTool.cpp b/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/PABeamformingTool.cpp index 1a9ce11188..6f07e6ebf0 100644 --- a/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/PABeamformingTool.cpp +++ b/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/PABeamformingTool.cpp @@ -1,230 +1,305 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include +#include struct InputParameters { mitk::Image::Pointer inputImage; std::string outputFilename; bool verbose; - float speedOfSound; - unsigned int cutoff; - float angle; - unsigned int samples; - mitk::BeamformingSettings::BeamformingAlgorithm algorithm; + std::string settingsFile; +}; + +struct CropSettings +{ + int above; + int below; + int right; + int left; + int zStart; + int zEnd; +}; + +struct ResampleSettings +{ + double spacing; +}; + +struct BModeSettings +{ + mitk::PhotoacousticFilterService::BModeMethod method; + bool UseLogFilter; +}; + +struct ProcessSettings +{ + bool DoBeamforming; + bool DoCropping; + bool DoResampling; + bool DoBmode; }; InputParameters parseInput(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setCategory("MITK-Photoacoustics"); parser.setTitle("Mitk Photoacoustics Beamforming Tool"); - parser.setDescription("Reads a nrrd file as an input and applies a beamforming method as set with the parameters."); + parser.setDescription("Reads a nrrd file as an input and applies a beamforming method as set with the parameters defined in an additionally provided xml file."); parser.setContributor("Computer Assisted Medical Interventions, DKFZ"); parser.setArgumentPrefix("--", "-"); parser.beginGroup("Required parameters"); parser.addArgument( "inputImage", "i", mitkCommandLineParser::InputImage, "Input image (mitk::Image)", "input image (.nrrd file)", us::Any(), false); parser.addArgument( "output", "o", mitkCommandLineParser::OutputFile, "Output filename", "output image (.nrrd file)", us::Any(), false); + parser.addArgument( + "settings", "s", mitkCommandLineParser::String, + "settings file", "file containing beamforming and other specifications(.xml file)", + us::Any(), false); parser.endGroup(); parser.beginGroup("Optional parameters"); parser.addArgument( "verbose", "v", mitkCommandLineParser::Bool, "Verbose Output", "Whether to produce verbose, or rather debug output. (default: false)"); - parser.addArgument( - "speed-of-sound", "sos", mitkCommandLineParser::Float, - "Speed of Sound [m/s]", "The average speed of sound as assumed for the reconstruction in [m/s]. (default: 1500)"); - parser.addArgument( - "cutoff", "co", mitkCommandLineParser::Int, - "cutoff margin on the top of the image [pixels]", "The number of pixels to be ignored for this filter in [pixels] (default: 0)."); - parser.addArgument( - "angle", "a", mitkCommandLineParser::Float, - "field of view of the transducer elements [degrees]", "The field of view of each individual transducer element [degrees] (default: 27)."); - parser.addArgument( - "samples", "s", mitkCommandLineParser::Int, - "samples per reconstruction line [pixels]", "The pixels along the y axis in the beamformed image [pixels] (default: 2048)."); - parser.addArgument( - "algorithm", "alg", mitkCommandLineParser::String, - "one of [\"DAS\", \"DMAS\", \"sDMAS\"]", "The beamforming algorithm to be used for reconstruction (default: DAS)."); parser.endGroup(); InputParameters input; std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size() == 0) exit(-1); - if (parsedArgs.count("verbose")) - { - input.verbose = true; - } - else - { - input.verbose = false; - } + input.verbose = (bool)parsedArgs.count("verbose"); MITK_INFO(input.verbose) << "### VERBOSE OUTPUT ENABLED ###"; if (parsedArgs.count("inputImage")) { MITK_INFO(input.verbose) << "Reading input image..."; input.inputImage = mitk::IOUtil::Load(us::any_cast(parsedArgs["inputImage"])); MITK_INFO(input.verbose) << "Reading input image...[Done]"; } else - { mitkThrow() << "No input image given."; - } if (parsedArgs.count("output")) - { input.outputFilename = us::any_cast(parsedArgs["output"]); - } else - { mitkThrow() << "No output image path given.."; - } - if (parsedArgs.count("speed-of-sound")) + if (parsedArgs.count("settings")) + input.settingsFile = us::any_cast(parsedArgs["settings"]); + else + mitkThrow() << "No settings image path given.."; + + return input; +} + +void ParseXML(std::string xmlFile, InputParameters input, mitk::BeamformingSettings::Pointer *bfSet, CropSettings& cropSet, ResampleSettings& resSet, BModeSettings& bmodeSet, ProcessSettings& processSet) +{ + MITK_INFO << "Loading configuration File \"" << xmlFile << "\""; + TiXmlDocument doc(xmlFile); + if (!doc.LoadFile()) + mitkThrow() << "Failed to load settings file \"" << xmlFile << "\" Error: " << doc.ErrorDesc(); + + TiXmlElement* root = doc.FirstChildElement(); + if (root == NULL) { - input.speedOfSound = us::any_cast(parsedArgs["speed-of-sound"]); + mitkThrow() << "Failed to load file: No root element."; + doc.Clear(); } - else + for (TiXmlElement* elem = root->FirstChildElement(); elem != NULL; elem = elem->NextSiblingElement()) { - input.speedOfSound = 1500; + std::string elemName = elem->Value(); + if (elemName == "Beamforming") + { + float PitchInMeters = std::stof(elem->Attribute("pitchInMeters")); + float SpeedOfSound = std::stof(elem->Attribute("speedOfSound")); + float Angle = std::stof(elem->Attribute("angle")); + bool IsPhotoacousticImage = std::stoi(elem->Attribute("isPhotoacousticImage")); + unsigned int SamplesPerLine = std::stoi(elem->Attribute("samplesPerLine")); + unsigned int ReconstructionLines = std::stoi(elem->Attribute("reconstructionLines")); + float ReconstructionDepth = std::stof(elem->Attribute("reconstructionDepth")); + bool UseGPU = std::stoi(elem->Attribute("useGPU")); + unsigned int GPUBatchSize = std::stoi(elem->Attribute("GPUBatchSize")); + + std::string apodizationStr = elem->Attribute("apodization"); + mitk::BeamformingSettings::Apodization Apodization = mitk::BeamformingSettings::Apodization::Box; + if (apodizationStr == "Box") + Apodization = mitk::BeamformingSettings::Apodization::Box; + else if (apodizationStr == "Hann") + Apodization = mitk::BeamformingSettings::Apodization::Hann; + else if (apodizationStr == "Hamm") + Apodization = mitk::BeamformingSettings::Apodization::Hamm; + else + mitkThrow() << "Apodization incorrectly defined in settings"; + + unsigned int ApodizationArraySize = std::stoi(elem->Attribute("apodizationArraySize")); + + std::string algorithmStr = elem->Attribute("algorithm"); + mitk::BeamformingSettings::BeamformingAlgorithm Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; + if (algorithmStr == "DAS") + Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; + else if (algorithmStr == "DMAS") + Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DMAS; + else if (algorithmStr == "sDMAS") + Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::sDMAS; + else + { + mitkThrow() << "Beamforming algorithm incorrectly defined in settings"; + } + + *bfSet = mitk::BeamformingSettings::New( + (float)(input.inputImage->GetGeometry()->GetSpacing()[0] / 1000), + SpeedOfSound, + (float)(input.inputImage->GetGeometry()->GetSpacing()[1] / 1000000), + Angle, + IsPhotoacousticImage, + SamplesPerLine, + ReconstructionLines, + input.inputImage->GetDimensions(), + ReconstructionDepth, + UseGPU, + GPUBatchSize, + mitk::BeamformingSettings::DelayCalc::Spherical, + Apodization, + ApodizationArraySize, + Algorithm + ); + processSet.DoBeamforming = std::stoi(elem->Attribute("do")); + } + if (elemName == "Cropping") + { + cropSet.above = std::stoi(elem->Attribute("cutAbove")); + cropSet.below = std::stoi(elem->Attribute("cutBelow")); + cropSet.right = std::stoi(elem->Attribute("cutRight")); + cropSet.left = std::stoi(elem->Attribute("cutLeft")); + cropSet.zStart = std::stoi(elem->Attribute("firstSlice")); + cropSet.zEnd = std::stoi(elem->Attribute("cutSlices")); + processSet.DoCropping = std::stoi(elem->Attribute("do")); + } + if (elemName == "Resampling") + { + resSet.spacing = std::stod(elem->Attribute("spacing")); + processSet.DoResampling = std::stoi(elem->Attribute("do")); + } + if (elemName == "BMode") + { + std::string methodStr = elem->Attribute("method"); + if (methodStr == "EnvelopeDetection") + bmodeSet.method = mitk::PhotoacousticFilterService::BModeMethod::EnvelopeDetection; + else if (elem->Attribute("method") == "Abs") + bmodeSet.method = mitk::PhotoacousticFilterService::BModeMethod::Abs; + else + mitkThrow() << "BMode method incorrectly set in configuration file"; + bmodeSet.UseLogFilter = (bool)std::stoi(elem->Attribute("useLogFilter")); + processSet.DoBmode = std::stoi(elem->Attribute("do")); + } } +} + +int main(int argc, char * argv[]) +{ + auto input = parseInput(argc, argv); - if (parsedArgs.count("cutoff")) + mitk::BeamformingSettings::Pointer bfSettings; + BModeSettings bmodeSettings{ mitk::PhotoacousticFilterService::BModeMethod::EnvelopeDetection, false }; + CropSettings cropSettings{ 0,0,0,0,0,0 }; + ResampleSettings resSettings{ 0.15 }; + ProcessSettings processSettings{ true, false, false }; + + MITK_INFO << "Parsing settings XML..."; + try { - input.cutoff = us::any_cast(parsedArgs["cutoff"]); + ParseXML(input.settingsFile, input, &bfSettings, cropSettings, resSettings, bmodeSettings, processSettings); } - else + catch (mitk::Exception e) { - input.cutoff = 0; + MITK_INFO << e; + return -1; } - if (parsedArgs.count("angle")) - { - input.angle = us::any_cast(parsedArgs["angle"]); - } - else + MITK_INFO << "Parsing settings XML...[Done]"; + + MITK_INFO(input.verbose) << "Beamforming input image..."; + mitk::Image::Pointer inputImage = input.inputImage; + if (!(inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)")) { - input.angle = 27; + // we need a float image, so cast it here + MITK_INFO(input.verbose) << "Casting input image to float..."; + mitk::CastToFloatImageFilter::Pointer castFilter = mitk::CastToFloatImageFilter::New(); + castFilter->SetInput(inputImage); + castFilter->Update(); + inputImage = castFilter->GetOutput(); + MITK_INFO << inputImage->GetPixelType().GetPixelTypeAsString(); + MITK_INFO(input.verbose) << "Casting input image to float...[Done]"; } - if (parsedArgs.count("samples")) + mitk::PhotoacousticFilterService::Pointer m_FilterService = mitk::PhotoacousticFilterService::New(); + + mitk::Image::Pointer output = inputImage; + if (processSettings.DoBeamforming) { - input.samples = us::any_cast(parsedArgs["samples"]); + MITK_INFO(input.verbose) << "Beamforming input image..."; + output = m_FilterService->ApplyBeamforming(output, bfSettings); + MITK_INFO(input.verbose) << "Beamforming input image...[Done]"; } - else + if (processSettings.DoCropping) { - input.samples = 2048; + int err; + MITK_INFO(input.verbose) << "Applying Crop filter to image..."; + output = m_FilterService->ApplyCropping(output, + cropSettings.above, cropSettings.below, cropSettings.right, cropSettings.left, cropSettings.zStart, cropSettings.zEnd, &err); + MITK_INFO(input.verbose) << "Applying Crop filter to image...[Done]"; } - - if (parsedArgs.count("algorithm")) + if (processSettings.DoResampling) { - std::string algorithm = us::any_cast(parsedArgs["algorithm"]); - MITK_INFO(input.verbose) << "Parsing algorithm: " << algorithm; - if (algorithm == "DAS") - input.algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; - else if (algorithm == "DMAS") - input.algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DMAS; - else if (algorithm == "sDMAS") - input.algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::sDMAS; - else - { - MITK_INFO(input.verbose) << "Not a valid beamforming algorithm: " << algorithm << " Reverting to DAS"; - input.algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; - } - - MITK_INFO(input.verbose) << "Sucessfully set algorithm: " << algorithm; + double spacing[3] = {output->GetGeometry()->GetSpacing()[0], resSettings.spacing, output->GetGeometry()->GetSpacing()[2]}; + MITK_INFO(input.verbose) << "Applying Resample filter to image..."; + output = m_FilterService->ApplyResampling(output, spacing); + MITK_INFO(input.verbose) << "Applying Resample filter to image...[Done]"; } - else + if (processSettings.DoBmode) { - input.algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; - MITK_INFO(input.verbose) << "No matching algorithm found. Using DAS."; + MITK_INFO(input.verbose) << "Applying BModeFilter to image..."; + output = m_FilterService->ApplyBmodeFilter(output, bmodeSettings.method, bmodeSettings.UseLogFilter); + MITK_INFO(input.verbose) << "Applying BModeFilter to image...[Done]"; } - return input; -} - -mitk::BeamformingSettings::Pointer ParseSettings(InputParameters &input) -{ - mitk::BeamformingSettings::Pointer outputSettings = mitk::BeamformingSettings::New( - (float)(input.inputImage->GetGeometry()->GetSpacing()[0] / 1000), - (float)(input.speedOfSound), - (float)(input.inputImage->GetGeometry()->GetSpacing()[1] / 1000000), - input.angle, - true, - input.inputImage->GetDimension(1), - input.inputImage->GetDimension(0), - input.inputImage->GetDimensions(), - 0.04, - false, - 16, - mitk::BeamformingSettings::DelayCalc::Spherical, - mitk::BeamformingSettings::Apodization::Box, - input.inputImage->GetDimension(0), - input.algorithm - ); - - return outputSettings; -} - -int main(int argc, char * argv[]) -{ - auto input = parseInput(argc, argv); - - MITK_INFO(input.verbose) << "Beamforming input image..."; - - mitk::PhotoacousticFilterService::Pointer m_BeamformingService = mitk::PhotoacousticFilterService::New(); - - mitk::BeamformingSettings::Pointer settings = ParseSettings(input); - - mitk::CastToFloatImageFilter::Pointer castFilter = mitk::CastToFloatImageFilter::New(); - castFilter->SetInput(input.inputImage); - castFilter->Update(); - auto floatImage = castFilter->GetOutput(); - - auto output = m_BeamformingService->ApplyBeamforming(floatImage, settings); - MITK_INFO(input.verbose) << "Applying BModeFilter to image..."; - auto output2 = m_BeamformingService->ApplyBmodeFilter(output, mitk::PhotoacousticFilterService::EnvelopeDetection, false); - MITK_INFO(input.verbose) << "Applying BModeFilter to image...[Done]"; - MITK_INFO(input.verbose) << "Saving image..."; - mitk::IOUtil::Save(output2, input.outputFilename); + mitk::IOUtil::Save(output, input.outputFilename); MITK_INFO(input.verbose) << "Saving image...[Done]"; MITK_INFO(input.verbose) << "Beamforming input image...[Done]"; } diff --git a/Modules/PhotoacousticsAlgorithms/MitkPAResampleCropTool/CMakeLists.txt b/Modules/PhotoacousticsAlgorithms/MitkPAResampleCropTool/CMakeLists.txt new file mode 100644 index 0000000000..7341757828 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/MitkPAResampleCropTool/CMakeLists.txt @@ -0,0 +1,11 @@ +OPTION(BUILD_PhotoacousticResampleCropTool "Build MiniApp for resampling and cropping of images" OFF) + +IF(BUILD_PhotoacousticResampleCropTool) + PROJECT( MitkPAResampleCropTool ) + mitk_create_executable(PAResampleCropTool + DEPENDS MitkCommandLine MitkCore MitkPhotoacousticsAlgorithms + PACKAGE_DEPENDS TinyXML + CPP_FILES PAResampleCropTool.cpp) + + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) + ENDIF() diff --git a/Modules/PhotoacousticsAlgorithms/MitkPAResampleCropTool/PAResampleCropTool.cpp b/Modules/PhotoacousticsAlgorithms/MitkPAResampleCropTool/PAResampleCropTool.cpp new file mode 100644 index 0000000000..9adbc00fa5 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/MitkPAResampleCropTool/PAResampleCropTool.cpp @@ -0,0 +1,198 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +struct InputParameters +{ + mitk::Image::Pointer inputImage; + std::string outputFilename; + bool verbose; + std::string settingsFile; +}; + +struct CropSettings +{ + unsigned int dimX; + unsigned int dimY; + unsigned int cutAbove; +}; + +struct ResamplingSettings +{ + double spacing[3]; +}; + + +InputParameters parseInput(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + parser.setCategory("MITK-Photoacoustics"); + parser.setTitle("Mitk Photoacoustics Resample and Crop Tool"); + parser.setDescription("Reads a nrrd file as an input and crops and resamples it as set with the parameters defined in an additionally provided xml file."); + parser.setContributor("Computer Assisted Medical Interventions, DKFZ"); + + parser.setArgumentPrefix("--", "-"); + + parser.beginGroup("Required parameters"); + parser.addArgument( + "inputImage", "i", mitkCommandLineParser::InputImage, + "Input image (mitk::Image)", "input image (.nrrd file)", + us::Any(), false); + parser.addArgument( + "output", "o", mitkCommandLineParser::OutputFile, + "Output filename", "output image (.nrrd file)", + us::Any(), false); + parser.addArgument( + "settings", "s", mitkCommandLineParser::String, + "settings file", "file containing specifications (.xml file)", + us::Any(), false); + parser.endGroup(); + + parser.beginGroup("Optional parameters"); + parser.addArgument( + "verbose", "v", mitkCommandLineParser::Bool, + "Verbose Output", "Whether to produce verbose, or rather debug output. (default: false)"); + parser.endGroup(); + + InputParameters input; + + std::map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size() == 0) + exit(-1); + + input.verbose = (bool)parsedArgs.count("verbose"); + MITK_INFO(input.verbose) << "### VERBOSE OUTPUT ENABLED ###"; + + if (parsedArgs.count("inputImage")) + { + MITK_INFO(input.verbose) << "Reading input image..."; + input.inputImage = mitk::IOUtil::Load(us::any_cast(parsedArgs["inputImage"])); + MITK_INFO(input.verbose) << "Reading input image...[Done]"; + } + else + mitkThrow() << "No input image given."; + + if (parsedArgs.count("output")) + input.outputFilename = us::any_cast(parsedArgs["output"]); + else + mitkThrow() << "No output image path given.."; + + if (parsedArgs.count("settings")) + input.settingsFile = us::any_cast(parsedArgs["settings"]); + else + mitkThrow() << "No settings image path given.."; + + return input; +} + +void ParseXML(std::string xmlFile, InputParameters input, CropSettings& cropSet, ResamplingSettings& resSet) +{ + MITK_INFO << "Loading configuration File \"" << xmlFile << "\""; + TiXmlDocument doc(xmlFile); + if (!doc.LoadFile()) + mitkThrow() << "Failed to load settings file \"" << xmlFile << "\" Error: " << doc.ErrorDesc(); + + TiXmlElement* root = doc.FirstChildElement(); + if (root == NULL) + { + mitkThrow() << "Failed to load file: No root element."; + doc.Clear(); + } + for (TiXmlElement* elem = root->FirstChildElement(); elem != NULL; elem = elem->NextSiblingElement()) + { + std::string elemName = elem->Value(); + if (elemName == "ResampleCrop") + { + cropSet.dimX = std::stoi(elem->Attribute("dimX")); + cropSet.dimY = std::stoi(elem->Attribute("dimY")); + cropSet.cutAbove = std::stoi(elem->Attribute("cutAbove")); + resSet.spacing[0] = std::stod(elem->Attribute("spacingX")); + resSet.spacing[1] = std::stod(elem->Attribute("spacingY")); + resSet.spacing[2] = std::stod(elem->Attribute("spacingZ")); + } + } +} + +int main(int argc, char * argv[]) +{ + auto input = parseInput(argc, argv); + + CropSettings cropSettings{ 0,0,0 }; + ResamplingSettings resSettings{ 0 }; + + MITK_INFO << "Parsing settings XML..."; + try + { + ParseXML(input.settingsFile, input, cropSettings, resSettings); + } + catch (mitk::Exception e) + { + MITK_INFO << e; + return -1; + } + + MITK_INFO << "Parsing settings XML...[Done]"; + + MITK_INFO(input.verbose) << "Processing input image..."; + + mitk::PhotoacousticFilterService::Pointer m_FilterService = mitk::PhotoacousticFilterService::New(); + + mitk::Image::Pointer output = input.inputImage; + MITK_INFO(input.verbose) << "Resampling input image..."; + MITK_INFO << resSettings.spacing[0]; + output = m_FilterService->ApplyResampling(output, resSettings.spacing); + MITK_INFO(input.verbose) << "Resampling input image...[Done]"; + + if (output->GetDimension(0) != cropSettings.dimX) + { + double outputDim[] = {(double)cropSettings.dimX, (double)output->GetDimension(1), (double)output->GetDimension(2)}; + output = m_FilterService->ApplyResamplingToDim(output, outputDim); + } + + int err = 0; + int below = output->GetDimension(1) - cropSettings.dimY - cropSettings.cutAbove; + if (below < 0) + { + MITK_INFO(input.verbose) << "Extending input image..."; + output = m_FilterService->ExtendImage(output, 0, cropSettings.dimY); + MITK_INFO(input.verbose) << "Extending input image...[Done]"; + } + else + { + MITK_INFO(input.verbose) << "Cropping input image..."; + output = m_FilterService->ApplyCropping(output, cropSettings.cutAbove, below, 0, 0, 0, 0, &err); + MITK_INFO(input.verbose) << "Cropping input image...[Done]"; + } + + + MITK_INFO(input.verbose) << "Saving image..."; + mitk::IOUtil::Save(output, input.outputFilename); + MITK_INFO(input.verbose) << "Saving image...[Done]"; + + MITK_INFO(input.verbose) << "Processing input image...[Done]"; +} diff --git a/Modules/PhotoacousticsAlgorithms/MitkPAResampleCropTool/files.cmake b/Modules/PhotoacousticsAlgorithms/MitkPAResampleCropTool/files.cmake new file mode 100644 index 0000000000..f8bb3ffe66 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/MitkPAResampleCropTool/files.cmake @@ -0,0 +1,3 @@ +set(CPP_FILES + PAResampleCropTool.cpp +) diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingSettings.h b/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingSettings.h index 5b76798dee..cddcf8d7fe 100644 --- a/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingSettings.h +++ b/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingSettings.h @@ -1,223 +1,218 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITK_BEAMFORMING_SETTINGS #define MITK_BEAMFORMING_SETTINGS #include #include #include #include namespace mitk { /*! * \brief Class holding the configuration data for the beamforming filters mitk::BeamformingFilter and mitk::PhotoacousticOCLBeamformingFilter * * A detailed description can be seen below. All parameters should be set manually for successfull beamforming. */ class MITKPHOTOACOUSTICSALGORITHMS_EXPORT BeamformingSettings : public itk::Object { public: mitkClassMacroItkParent(BeamformingSettings, itk::Object); - mitkNewMacro1Param(BeamformingSettings, std::string); itkCloneMacro(Self); /** \brief Available delay calculation methods: * - Spherical delay for best results. * - DEPRECATED quadratic Taylor approximation for slightly faster results with hardly any quality loss. */ enum DelayCalc { QuadApprox, Spherical }; /** \brief Available apodization functions: * - Hamming function. * - Von-Hann function. * - Box function. */ enum Apodization { Hamm, Hann, Box }; /** \brief Available beamforming algorithms: * - DAS (Delay and sum). * - DMAS (Delay multiply and sum). */ enum BeamformingAlgorithm { DMAS, DAS, sDMAS }; itkGetConstMacro(PitchInMeters, float); itkGetConstMacro(SpeedOfSound, float); itkGetConstMacro(TimeSpacing, float); itkGetConstMacro(Angle, float); itkGetConstMacro(IsPhotoacousticImage, bool); itkGetConstMacro(TransducerElements, unsigned int); itkGetConstMacro(SamplesPerLine, unsigned int); itkGetConstMacro(ReconstructionLines, unsigned int); itkGetConstMacro(InputDim, const unsigned int*); itkGetConstMacro(UseGPU, bool); itkGetConstMacro(GPUBatchSize, unsigned int); itkGetConstMacro(DelayCalculationMethod, DelayCalc); itkGetConstMacro(ApodizationFunction, const float*); itkGetConstMacro(Apod, Apodization); itkGetConstMacro(ApodizationArraySize, int); itkGetConstMacro(Algorithm, BeamformingAlgorithm); itkGetConstMacro(ReconstructionDepth, float); /** \brief function for mitk::PhotoacousticOCLBeamformingFilter to check whether buffers need to be updated * this method only checks parameters relevant for the openCL implementation */ static bool SettingsChangedOpenCL(const BeamformingSettings::Pointer lhs, const BeamformingSettings::Pointer rhs) { return !((abs(lhs->GetAngle() - rhs->GetAngle()) < 0.01f) && // 0.01 degree error margin (lhs->GetApod() == rhs->GetApod()) && (lhs->GetDelayCalculationMethod() == rhs->GetDelayCalculationMethod()) && (lhs->GetIsPhotoacousticImage() == rhs->GetIsPhotoacousticImage()) && (abs(lhs->GetPitchInMeters() - rhs->GetPitchInMeters()) < 0.000001f) && // 0.0001 mm error margin (lhs->GetReconstructionLines() == rhs->GetReconstructionLines()) && (lhs->GetSamplesPerLine() == rhs->GetSamplesPerLine()) && (lhs->GetReconstructionDepth() == rhs->GetReconstructionDepth()) && (abs(lhs->GetSpeedOfSound() - rhs->GetSpeedOfSound()) < 0.01f) && (abs(lhs->GetTimeSpacing() - rhs->GetTimeSpacing()) < 0.00000000001f) && //0.01 ns error margin (lhs->GetTransducerElements() == rhs->GetTransducerElements())); } static Pointer New(float pitchInMeters, float speedOfSound, float timeSpacing, float angle, bool isPhotoacousticImage, unsigned int samplesPerLine, unsigned int reconstructionLines, unsigned int* inputDim, float reconstructionDepth, bool useGPU, unsigned int GPUBatchSize, DelayCalc delayCalculationMethod, Apodization apod, unsigned int apodizationArraySize, BeamformingAlgorithm algorithm) { Pointer smartPtr = new BeamformingSettings(pitchInMeters, speedOfSound, timeSpacing, angle, isPhotoacousticImage, samplesPerLine, reconstructionLines, inputDim, reconstructionDepth, useGPU, GPUBatchSize, delayCalculationMethod, apod, apodizationArraySize, algorithm); smartPtr->UnRegister(); return smartPtr; } protected: - /** - */ - BeamformingSettings(std::string xmlFile); - /** */ BeamformingSettings(float pitchInMeters, float speedOfSound, float timeSpacing, float angle, bool isPhotoacousticImage, unsigned int samplesPerLine, unsigned int reconstructionLines, unsigned int* inputDim, float reconstructionDepth, bool useGPU, unsigned int GPUBatchSize, DelayCalc delayCalculationMethod, Apodization apod, unsigned int apodizationArraySize, BeamformingAlgorithm algorithm ); ~BeamformingSettings(); /** \brief Pitch of the used transducer in [m]. */ float m_PitchInMeters; /** \brief Speed of sound in the used medium in [m/s]. */ float m_SpeedOfSound; /** \brief The time spacing of the input image */ float m_TimeSpacing; // [s] /** \brief The angle of the transducer elements */ float m_Angle; /** \brief Flag whether processed image is a photoacoustic image or an ultrasound image */ bool m_IsPhotoacousticImage; /** \brief How many transducer elements the used transducer had. */ unsigned int m_TransducerElements; /** \brief How many vertical samples should be used in the final image. */ unsigned int m_SamplesPerLine; /** \brief How many lines should be reconstructed in the final image. */ unsigned int m_ReconstructionLines; /** \brief Sets the dimensions of the inputImage. */ const unsigned int* m_InputDim; /** \brief The Depth up to which the filter should reconstruct the image [m] */ float m_ReconstructionDepth; /** \brief Decides whether GPU computing should be used */ bool m_UseGPU; unsigned int m_GPUBatchSize; /** \brief Sets the amount of image slices in batches when GPU is used */ /** \brief Sets how the delays for beamforming should be calculated. */ DelayCalc m_DelayCalculationMethod; const float* m_ApodizationFunction; /** \brief Sets the used apodization function. */ Apodization m_Apod; /** \brief Sets the resolution of the apodization array (must be greater than 0). */ int m_ApodizationArraySize; /** \brief Sets the used beamforming algorithm. */ BeamformingAlgorithm m_Algorithm; }; } #endif //MITK_BEAMFORMING_SETTINGS diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticFilterService.h b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticFilterService.h index 23c13bca1d..5f3de39773 100644 --- a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticFilterService.h +++ b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticFilterService.h @@ -1,128 +1,130 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkPhotoacousticFilterService_H_HEADER_INCLUDED #define mitkPhotoacousticFilterService_H_HEADER_INCLUDED #include "itkObject.h" #include "mitkCommon.h" #include "mitkImage.h" #include #include "mitkBeamformingSettings.h" #include "mitkBeamformingFilter.h" #include "MitkPhotoacousticsAlgorithmsExports.h" namespace mitk { /*! * \brief Class holding methods to apply all Filters within the Photoacoustics Algorithms Module * * Implemented are: * - A B-Mode Filter * - A Resampling Filter * - Beamforming on GPU and CPU * - A Bandpass Filter */ class MITKPHOTOACOUSTICSALGORITHMS_EXPORT PhotoacousticFilterService : public itk::Object { public: mitkClassMacroItkParent(mitk::PhotoacousticFilterService, itk::Object); itkFactorylessNewMacro(Self); /** \brief Defines the methods for the B-Mode filter * Currently implemented are an Envelope Detection filter and a simple Absolute filter. */ enum BModeMethod { EnvelopeDetection, Abs }; /** \brief Applies a B-Mode Filter * * Applies a B-Mode filter using the given parameters. * @param inputImage The image to be processed. * @param method The kind of B-Mode Filter to be used. * @param UseLogFilter Setting this to true will apply a simple logarithm to the image after the B-Mode Filter has been applied. * @param resampleSpacing If this is set to 0, nothing will be done; otherwise, the image is resampled to a spacing of resampleSpacing mm per pixel. * @return The processed image is returned after the filter has finished. */ mitk::Image::Pointer ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method = BModeMethod::Abs, bool UseLogFilter = false); /** \brief Resamples the given image * * Resamples an image using the given parameters. * @param inputImage The image to be processed. * @param outputSize An array of dimensions the image should be resampled to. * @return The processed image is returned after the filter has finished. */ mitk::Image::Pointer ApplyResampling(mitk::Image::Pointer inputImage, double* outputSpacing); mitk::Image::Pointer ApplyResamplingToDim(mitk::Image::Pointer inputImage, double* outputDimension); /** \brief Beamforms the given image * * Resamples an image using the given parameters. * @param inputImage The image to be processed. * @param config The configuration set to be used for beamforming. * @param progressHandle An std::function, through which progress of the currently updating filter is reported. * The integer argument is a number between 0 an 100 to indicate how far completion has been achieved, the std::string argument indicates what the filter is currently doing. * @return The processed image is returned after the filter has finished. */ mitk::Image::Pointer ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingSettings::Pointer config, std::function progressHandle = [](int, std::string) {}); /** \brief Crops the given image * * Crops an image in 3 dimension using the given parameters. * @param inputImage The image to be processed. * @param above How many voxels will be cut from the top of the image. * @param below How many voxels will be cut from the bottom of the image. * @param right How many voxels will be cut from the right side of the image. * @param left How many voxels will be cut from the left side of the image. - * @param minSlice The first slice to be present in the resulting image. - * @param maxSlice The last slice to be present in the resulting image. + * @param minSlice The first slice to be present in the resulting volume. + * @param maxSlice How many slices are cut off from the end of the volume. * @return The processed image is returned after the filter has finished. For the purposes of this module, the returned image is always of type float. */ mitk::Image::Pointer ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice, int* errCode); + mitk::Image::Pointer ExtendImage(mitk::Image::Pointer inputImage, float pixelColor, unsigned int outputDimensionY); + /** \brief Applies a Bandpass filter to the given image * * Applies a bandpass filter to the given image using the given parameters. * @param data The image to be processed. * @param BPHighPass The position at which Lower frequencies are completely cut off in Hz. * @param BPLowPass The position at which Higher frequencies are completely cut off in Hz. * @param alphaHighPass The high pass tukey window parameter to control the shape of the bandpass filter: 0 will make it a Box function, 1 a Hann function. alpha can be set between those two bounds. * @param alphaLowPass The low passtukey window parameter to control the shape of the bandpass filter: 0 will make it a Box function, 1 a Hann function. alpha can be set between those two bounds. * @return The processed image is returned after the filter has finished. */ mitk::Image::Pointer ApplyBandpassFilter(mitk::Image::Pointer data, float BPHighPass, float BPLowPass, float alphaHighPass, float alphaLowPass, float timeSpacing, float SpeedOfSound, bool IsBFImage); protected: PhotoacousticFilterService(); ~PhotoacousticFilterService() override; /** \brief For performance reasons, an instance of the Beamforming filter is initialized as soon as possible and kept for all further uses. */ mitk::BeamformingFilter::Pointer m_BeamformingFilter; mitk::Image::Pointer ConvertToFloat(mitk::Image::Pointer); }; } // namespace mitk #endif /* mitkPhotoacousticFilterService_H_HEADER_INCLUDED */ diff --git a/Modules/PhotoacousticsAlgorithms/source/filters/mitkBeamformingSettings.cpp b/Modules/PhotoacousticsAlgorithms/source/filters/mitkBeamformingSettings.cpp index b052f15a5c..7508605611 100644 --- a/Modules/PhotoacousticsAlgorithms/source/filters/mitkBeamformingSettings.cpp +++ b/Modules/PhotoacousticsAlgorithms/source/filters/mitkBeamformingSettings.cpp @@ -1,105 +1,96 @@ /*=================================================================== mitkBeamformingSettings The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkBeamformingSettings.h" #include "mitkBeamformingUtils.h" #include "itkMutexLock.h" -mitk::BeamformingSettings::BeamformingSettings(std::string xmlFile) -{ - if((xmlFile.length())>0) - { - MITK_ERROR << "Not implemented yet."; - mitkThrow() << "Not implemented yet."; - } -} - mitk::BeamformingSettings::BeamformingSettings(float pitchInMeters, float speedOfSound, float timeSpacing, float angle, bool isPhotoacousticImage, unsigned int samplesPerLine, unsigned int reconstructionLines, unsigned int* inputDim, float reconstructionDepth, bool useGPU, unsigned int GPUBatchSize, DelayCalc delayCalculationMethod, Apodization apod, unsigned int apodizationArraySize, BeamformingAlgorithm algorithm ) : m_PitchInMeters(pitchInMeters), m_SpeedOfSound(speedOfSound), m_TimeSpacing(timeSpacing), m_Angle(angle), m_IsPhotoacousticImage(isPhotoacousticImage), m_SamplesPerLine(samplesPerLine), m_ReconstructionLines(reconstructionLines), m_ReconstructionDepth(reconstructionDepth), m_UseGPU(useGPU), m_GPUBatchSize(GPUBatchSize), m_DelayCalculationMethod(delayCalculationMethod), m_Apod(apod), m_ApodizationArraySize(apodizationArraySize), m_Algorithm(algorithm) { if (inputDim == nullptr) { MITK_ERROR << "No input dimension given."; mitkThrow() << "No input dimension given."; } switch (GetApod()) { case BeamformingSettings::Apodization::Hann: m_ApodizationFunction = mitk::BeamformingUtils::VonHannFunction(GetApodizationArraySize()); break; case BeamformingSettings::Apodization::Hamm: m_ApodizationFunction = mitk::BeamformingUtils::HammFunction(GetApodizationArraySize()); break; case BeamformingSettings::Apodization::Box: default: m_ApodizationFunction = mitk::BeamformingUtils::BoxFunction(GetApodizationArraySize()); break; } m_InputDim = new unsigned int[3]{ inputDim[0], inputDim[1], inputDim[2] }; m_TransducerElements = m_InputDim[0]; } mitk::BeamformingSettings::~BeamformingSettings() { MITK_INFO << "Destructing beamforming settings..."; //Free memory if (m_ApodizationFunction != nullptr) { MITK_INFO << "Deleting apodization function..."; delete[] m_ApodizationFunction; MITK_INFO << "Deleting apodization function...[Done]"; } if (m_InputDim != nullptr) { MITK_INFO << "Deleting input dim..."; delete[] m_InputDim; MITK_INFO << "Deleting input dim...[Done]"; } MITK_INFO << "Destructing beamforming settings...[Done]"; } diff --git a/Modules/PhotoacousticsAlgorithms/source/utils/mitkPhotoacousticFilterService.cpp b/Modules/PhotoacousticsAlgorithms/source/utils/mitkPhotoacousticFilterService.cpp index 9524e1db36..eb3940e9cc 100644 --- a/Modules/PhotoacousticsAlgorithms/source/utils/mitkPhotoacousticFilterService.cpp +++ b/Modules/PhotoacousticsAlgorithms/source/utils/mitkPhotoacousticFilterService.cpp @@ -1,282 +1,307 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPhotoacousticFilterService.h" #include "mitkITKImageImport.h" #include #include #include "./OpenCLFilter/mitkPhotoacousticBModeFilter.h" #include "mitkConvert2Dto3DImageFilter.h" #include #include "../ITKFilter/ITKUltrasound/itkBModeImageFilter.h" #include "../ITKFilter/itkPhotoacousticBModeImageFilter.h" #include // itk dependencies #include "itkImage.h" #include "itkResampleImageFilter.h" #include "itkCastImageFilter.h" #include "itkCropImageFilter.h" #include "itkRescaleIntensityImageFilter.h" #include "itkIntensityWindowingImageFilter.h" #include #include "itkBSplineInterpolateImageFunction.h" #include // needed itk image filters #include "mitkImageCast.h" mitk::PhotoacousticFilterService::PhotoacousticFilterService() { MITK_INFO << "[PhotoacousticFilterService] created filter service"; } mitk::PhotoacousticFilterService::~PhotoacousticFilterService() { MITK_INFO << "[PhotoacousticFilterService] destructed filter service"; } mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyBmodeFilter( mitk::Image::Pointer inputImage, BModeMethod method, bool UseLogFilter) { // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by the CastToItkImage typedef itk::Image< float, 3 > itkFloatImageType; auto floatImage = ConvertToFloat(inputImage); if (method == BModeMethod::Abs) { PhotoacousticBModeFilter::Pointer filter = PhotoacousticBModeFilter::New(); filter->UseLogFilter(UseLogFilter); filter->SetInput(floatImage); filter->Update(); return filter->GetOutput(); } typedef itk::BModeImageFilter < itkFloatImageType, itkFloatImageType > BModeFilterType; BModeFilterType::Pointer bModeFilter = BModeFilterType::New(); // LogFilter typedef itk::PhotoacousticBModeImageFilter < itkFloatImageType, itkFloatImageType > PhotoacousticBModeImageFilter; PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); // No LogFilter typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(floatImage, itkImage); if (UseLogFilter) { bModeFilter->SetInput(itkImage); bModeFilter->SetDirection(1); itkImage = bModeFilter->GetOutput(); } else { photoacousticBModeFilter->SetInput(itkImage); photoacousticBModeFilter->SetDirection(1); itkImage = photoacousticBModeFilter->GetOutput(); } return mitk::GrabItkImageMemory(itkImage); } mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyResampling( mitk::Image::Pointer inputImage, double *outputSpacing) { typedef itk::Image< float, 3 > itkFloatImageType; auto floatImage = ConvertToFloat(inputImage); typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(floatImage, itkImage); itkFloatImageType::SpacingType outputSpacingItk; itkFloatImageType::SizeType inputSizeItk = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSizeItk = inputSizeItk; outputSpacingItk[0] = outputSpacing[0]; outputSpacingItk[1] = outputSpacing[1]; outputSpacingItk[2] = itkImage->GetSpacing()[2]; outputSizeItk[0] = outputSizeItk[0] * (floatImage->GetGeometry()->GetSpacing()[0] / outputSpacing[0]); outputSizeItk[1] = outputSizeItk[1] * (floatImage->GetGeometry()->GetSpacing()[1] / outputSpacing[1]); resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSizeItk); resampleImageFilter->SetOutputSpacing(outputSpacingItk); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyResamplingToDim( mitk::Image::Pointer inputImage, double *outputDimension) { typedef itk::Image< float, 3 > itkFloatImageType; auto floatImage = ConvertToFloat(inputImage); typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(floatImage, itkImage); itkFloatImageType::SpacingType outputSpacingItk; itkFloatImageType::SizeType inputSizeItk = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSizeItk = inputSizeItk; outputSizeItk[0] = outputDimension[0]; outputSizeItk[1] = outputDimension[1]; MITK_INFO << outputSizeItk[0] << " " << outputSizeItk[1]; outputSpacingItk[0] = (double)inputSizeItk[0] / (double)outputSizeItk[0] * floatImage->GetGeometry()->GetSpacing()[0]; outputSpacingItk[1] = (double)inputSizeItk[1] / (double)outputSizeItk[1] * floatImage->GetGeometry()->GetSpacing()[1]; outputSpacingItk[2] = itkImage->GetSpacing()[2]; MITK_INFO << outputSpacingItk[0] << " " << outputSpacingItk[1]; resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSizeItk); resampleImageFilter->SetOutputSpacing(outputSpacingItk); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyCropping( mitk::Image::Pointer inputImage, int above, int below, int right, int left, int zStart, int zEnd, int* errCode) { *errCode = 0; try { auto floatImage = ConvertToFloat(inputImage); mitk::CropImageFilter::Pointer cropImageFilter = mitk::CropImageFilter::New(); cropImageFilter->SetInput(floatImage); cropImageFilter->SetXPixelsCropStart(left); cropImageFilter->SetXPixelsCropEnd(right); cropImageFilter->SetYPixelsCropStart(above); cropImageFilter->SetYPixelsCropEnd(below); cropImageFilter->SetZPixelsCropStart(zStart); cropImageFilter->SetZPixelsCropEnd(zEnd); cropImageFilter->Update(); return cropImageFilter->GetOutput(); } catch (mitk::Exception &e) { std::string errorMessage = "Caught unexpected exception "; errorMessage.append(e.what()); MITK_ERROR << errorMessage; *errCode = -1; mitk::Image::Pointer ret = mitk::Image::New(); unsigned int dim[3] = { 1,1,1 }; ret->Initialize(MakeScalarPixelType(), 3, dim); return ret; } } +mitk::Image::Pointer mitk::PhotoacousticFilterService::ExtendImage(mitk::Image::Pointer inputImage, float pixelColor, unsigned int outputDimensionY) +{ + mitk::Image::Pointer outputImage = mitk::Image::New(); + unsigned int dim[] = {inputImage->GetDimension(0), outputDimensionY, inputImage->GetDimension(2)}; + outputImage->Initialize(inputImage->GetPixelType(), 3, dim); + + float *sliceData = new float[dim[0] * dim[1]]; + + for (size_t i = inputImage->GetDimension(1) * dim[0]; i < dim[0] * dim[1]; ++i) + { + sliceData[i] = pixelColor; + } + + for (unsigned int slice = 0; slice < dim[2]; ++slice) + { + mitk::ImageReadAccessor cpy(inputImage, inputImage->GetSliceData(slice)); + cpy.GetData(); + std::memcpy((void*)sliceData, cpy.GetData(), sizeof(float) * inputImage->GetDimension(1) * dim[0]); + outputImage->SetSlice(sliceData, slice); + } + + delete[] sliceData; + return outputImage; +} + mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyBeamforming( mitk::Image::Pointer inputImage, BeamformingSettings::Pointer config, std::function progressHandle) { Image::Pointer processedImage = mitk::Image::New(); if (inputImage->GetDimension() != 3) { mitk::Convert2Dto3DImageFilter::Pointer dimensionImageFilter = mitk::Convert2Dto3DImageFilter::New(); dimensionImageFilter->SetInput(inputImage); dimensionImageFilter->Update(); processedImage = dimensionImageFilter->GetOutput(); } else { processedImage = inputImage; } m_BeamformingFilter = mitk::BeamformingFilter::New(config); m_BeamformingFilter->SetInput(ConvertToFloat(processedImage)); m_BeamformingFilter->SetProgressHandle(progressHandle); m_BeamformingFilter->UpdateLargestPossibleRegion(); processedImage = m_BeamformingFilter->GetOutput(); return processedImage; } mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyBandpassFilter( mitk::Image::Pointer data, float BPHighPass, float BPLowPass, float alphaHighPass, float alphaLowPass, float TimeSpacing, float SpeedOfSound, bool IsBFImage) { try { auto floatData = ConvertToFloat(data); mitk::BandpassFilter::Pointer bandpassFilter = mitk::BandpassFilter::New(); bandpassFilter->SetInput(floatData); bandpassFilter->SetHighPass(BPHighPass); bandpassFilter->SetLowPass(BPLowPass); bandpassFilter->SetHighPassAlpha(alphaHighPass); bandpassFilter->SetLowPassAlpha(alphaLowPass); bandpassFilter->SetSpeedOfSound(SpeedOfSound); bandpassFilter->SetTimeSpacing(TimeSpacing); bandpassFilter->SetIsBFImage(IsBFImage); bandpassFilter->Update(); return bandpassFilter->GetOutput(); } catch (mitk::Exception &e) { std::string errorMessage = "Caught unexpected exception "; errorMessage.append(e.what()); MITK_ERROR << errorMessage; return data; } } mitk::Image::Pointer mitk::PhotoacousticFilterService::ConvertToFloat(mitk::Image::Pointer inputImage) { if ((inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)")) { return inputImage; } mitk::CastToFloatImageFilter::Pointer castToFloatImageFilter = mitk::CastToFloatImageFilter::New(); castToFloatImageFilter->SetInput(inputImage); castToFloatImageFilter->Update(); return castToFloatImageFilter->GetOutput(); }