diff --git a/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/PABeamformingTool.cpp b/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/PABeamformingTool.cpp index 9d0c1a0959..51012071e5 100644 --- a/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/PABeamformingTool.cpp +++ b/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/PABeamformingTool.cpp @@ -1,285 +1,285 @@ /*=================================================================== 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 { int above; int below; int right; int left; int zStart; int zEnd; }; struct BModeSettings { mitk::PhotoacousticFilterService::BModeMethod method; bool UseLogFilter; }; struct ProcessSettings { bool DoBeamforming; bool DoCropping; 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 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.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, mitk::BeamformingSettings::Pointer *bfSet, CropSettings cropSet, BModeSettings bmodeSet, ProcessSettings processSet) +void ParseXML(std::string xmlFile, InputParameters input, mitk::BeamformingSettings::Pointer *bfSet, CropSettings& cropSet, 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) { 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 == "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 == "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); mitk::BeamformingSettings::Pointer bfSettings; BModeSettings bmodeSettings{ mitk::PhotoacousticFilterService::BModeMethod::EnvelopeDetection, false }; CropSettings cropSettings{ 0,0,0,0,0,0 }; ProcessSettings processSettings{ true, false, false }; MITK_INFO << "Parsing settings XML..."; try { ParseXML(input.settingsFile, input, &bfSettings, cropSettings, bmodeSettings, processSettings); } catch (mitk::Exception e) { MITK_INFO << e; return -1; } 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)")) { // 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(input.verbose) << "Casting input image to float...[Done]"; } mitk::PhotoacousticFilterService::Pointer m_FilterService = mitk::PhotoacousticFilterService::New(); mitk::Image::Pointer output; if (processSettings.DoBeamforming) { MITK_INFO(input.verbose) << "Beamforming input image..."; output = m_FilterService->ApplyBeamforming(inputImage, bfSettings); MITK_INFO(input.verbose) << "Beamforming input image...[Done]"; } if (processSettings.DoCropping) { 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 (processSettings.DoBmode) { 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]"; } MITK_INFO(input.verbose) << "Saving image..."; 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/PAResampleCropTool.cpp b/Modules/PhotoacousticsAlgorithms/MitkPAResampleCropTool/PAResampleCropTool.cpp index 38bcf60347..9adbc00fa5 100644 --- a/Modules/PhotoacousticsAlgorithms/MitkPAResampleCropTool/PAResampleCropTool.cpp +++ b/Modules/PhotoacousticsAlgorithms/MitkPAResampleCropTool/PAResampleCropTool.cpp @@ -1,190 +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 cutBelow; + 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) +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.cutBelow = std::stoi(elem->Attribute("cutBelow")); - resSet.spacing[0] = std::stoi(elem->Attribute("spacingX")); - resSet.spacing[1] = std::stoi(elem->Attribute("spacingY")); - resSet.spacing[2] = std::stoi(elem->Attribute("spacingZ")); + 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,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 above = input.inputImage->GetDimension(1) - cropSettings.dimY - cropSettings.cutBelow; - if (above < 0) - mitkThrow() << "Cannot crop an image to a larger dimension than before"; + 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) << "Cropping input image..."; - output = m_FilterService->ApplyCropping(output, above, cropSettings.cutBelow, 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/include/mitkPhotoacousticFilterService.h b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticFilterService.h index 3eb528c679..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 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/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(); }