diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingSettings.h b/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingSettings.h index e53a234980..8d60c4fcd1 100644 --- a/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingSettings.h +++ b/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingSettings.h @@ -1,242 +1,242 @@ /*=================================================================== 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); 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 }; /** \brief Available geometries for Probes: * - Linear * - Concave */ enum ProbeGeometry { Linear, Concave}; 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); itkGetConstMacro(Geometry, ProbeGeometry); itkGetConstMacro(ProbeRadius, 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->GetGeometry() == rhs->GetGeometry()) && (abs(lhs->GetProbeRadius() - rhs->GetProbeRadius()) < 0.001f) && (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, ProbeGeometry geometry, float probeRadius) { Pointer smartPtr = new BeamformingSettings(pitchInMeters, speedOfSound, timeSpacing, angle, isPhotoacousticImage, samplesPerLine, reconstructionLines, inputDim, reconstructionDepth, useGPU, GPUBatchSize, delayCalculationMethod, apod, apodizationArraySize, algorithm, geometry, probeRadius); smartPtr->UnRegister(); return smartPtr; } protected: /** */ 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, ProbeGeometry geometry, float probeRadius ); ~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; /** \brief Sets the used probe geometry */ ProbeGeometry m_Geometry; - /** \brief Sets the radius of the curved probe + /** \brief Sets the radius of the curved probe [m] */ float m_ProbeRadius; }; } #endif //MITK_BEAMFORMING_SETTINGS diff --git a/Modules/PhotoacousticsAlgorithms/source/utils/mitkBeamformingUtils.cpp b/Modules/PhotoacousticsAlgorithms/source/utils/mitkBeamformingUtils.cpp index b000906692..d3c087beda 100644 --- a/Modules/PhotoacousticsAlgorithms/source/utils/mitkBeamformingUtils.cpp +++ b/Modules/PhotoacousticsAlgorithms/source/utils/mitkBeamformingUtils.cpp @@ -1,563 +1,609 @@ /*=================================================================== mitkPhotoacousticBeamformingFilter 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 "mitkProperties.h" #include "mitkImageReadAccessor.h" #include #include #include #include #include #include "mitkImageCast.h" #include "mitkBeamformingUtils.h" mitk::BeamformingUtils::BeamformingUtils() { } mitk::BeamformingUtils::~BeamformingUtils() { } float* mitk::BeamformingUtils::VonHannFunction(int samples) { float* ApodWindow = new float[samples]; for (int n = 0; n < samples; ++n) { ApodWindow[n] = (1 - cos(2 * itk::Math::pi * n / (samples - 1))) / 2; } return ApodWindow; } float* mitk::BeamformingUtils::HammFunction(int samples) { float* ApodWindow = new float[samples]; for (int n = 0; n < samples; ++n) { ApodWindow[n] = 0.54 - 0.46*cos(2 * itk::Math::pi*n / (samples - 1)); } return ApodWindow; } float* mitk::BeamformingUtils::BoxFunction(int samples) { float* ApodWindow = new float[samples]; for (int n = 0; n < samples; ++n) { ApodWindow[n] = 1; } return ApodWindow; } void mitk::BeamformingUtils::DASQuadraticLine( float* input, float* output, float inputDim[2], float outputDim[2], const short& line, const mitk::BeamformingSettings::Pointer config) { const float* apodisation = config->GetApodizationFunction(); const short apodArraySize = config->GetApodizationArraySize(); float& inputS = inputDim[1]; float& inputL = inputDim[0]; float& outputS = outputDim[1]; float& outputL = outputDim[0]; short AddSample = 0; short maxLine = 0; short minLine = 0; float delayMultiplicator = 0; float l_i = 0; float s_i = 0; float part = 0; float tan_phi = std::tan(config->GetAngle() / 360 * 2 * itk::Math::pi); float part_multiplicator = tan_phi * config->GetTimeSpacing() * config->GetSpeedOfSound() / config->GetPitchInMeters() * inputL / config->GetTransducerElements(); float apod_mult = 1; + float probeRadius = config->GetProbeRadius(); + bool concave = config->GetGeometry() == mitk::BeamformingSettings::ProbeGeometry::Concave; + float elementHeight = 0; + short usedLines = (maxLine - minLine); - float percentOfImageReconstructed = (float)(config->GetReconstructionDepth()) / - (float)(inputS * config->GetSpeedOfSound() * config->GetTimeSpacing() / (float)(2 - (int)config->GetIsPhotoacousticImage())); - percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + float totalSamples_i = (float)(config->GetReconstructionDepth()) / (float)(config->GetSpeedOfSound() * config->GetTimeSpacing()); + totalSamples_i = totalSamples_i <= inputS ? totalSamples_i : inputS; l_i = (float)line / outputL * inputL; for (short sample = 0; sample < outputS; ++sample) { - s_i = (float)sample / outputS * inputS / (float)(2 - (int)config->GetIsPhotoacousticImage()) * percentOfImageReconstructed; + s_i = (float)sample / outputS * totalSamples_i; part = part_multiplicator*s_i; if (part < 1) part = 1; - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); + maxLine = std::round(std::min((l_i + part) + 1, inputL)); + minLine = std::round(std::max((l_i - part), 0.0f)); usedLines = (maxLine - minLine); apod_mult = (float)apodArraySize / (float)usedLines; delayMultiplicator = pow((1 / (config->GetTimeSpacing()*config->GetSpeedOfSound()) * (config->GetPitchInMeters()*config->GetTransducerElements()) / inputL), 2) / s_i / 2; for (short l_s = minLine; l_s < maxLine; ++l_s) { - AddSample = delayMultiplicator * pow((l_s - l_i), 2) + s_i + (1 - config->GetIsPhotoacousticImage())*s_i; + if (concave) + { + elementHeight = (probeRadius - std::cos(((abs(inputL / 2.f - l_s)*config->GetPitchInMeters()) / (2 * itk::Math::pi*probeRadius)) * 2 * itk::Math::pi)*probeRadius) / (config->GetSpeedOfSound()*config->GetTimeSpacing()); + } + AddSample = delayMultiplicator * pow((l_s - l_i), 2) + (s_i - elementHeight) + (1 - config->GetIsPhotoacousticImage())*s_i; if (AddSample < inputS && AddSample >= 0) output[sample*(short)outputL + line] += input[l_s + AddSample*(short)inputL] * apodisation[(short)((l_s - minLine)*apod_mult)]; else --usedLines; } output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / usedLines; } } void mitk::BeamformingUtils::DASSphericalLine( float* input, float* output, float inputDim[2], float outputDim[2], const short& line, const mitk::BeamformingSettings::Pointer config) { const float* apodisation = config->GetApodizationFunction(); const short apodArraySize = config->GetApodizationArraySize(); float& inputS = inputDim[1]; float& inputL = inputDim[0]; float& outputS = outputDim[1]; float& outputL = outputDim[0]; short AddSample = 0; short maxLine = 0; short minLine = 0; float l_i = 0; float s_i = 0; - float part = 0.07 * inputL; + float part = 0.07 * inputL; // just a default value float tan_phi = std::tan(config->GetAngle() / 360 * 2 * itk::Math::pi); float part_multiplicator = tan_phi * config->GetTimeSpacing() * config->GetSpeedOfSound() / config->GetPitchInMeters() * inputL / (float)config->GetTransducerElements(); float apod_mult = 1; + float probeRadius = config->GetProbeRadius(); + bool concave = config->GetGeometry() == mitk::BeamformingSettings::ProbeGeometry::Concave; + float elementHeight = 0; + short usedLines = (maxLine - minLine); - float percentOfImageReconstructed = (float)(config->GetReconstructionDepth()) / - (float)(inputS * config->GetSpeedOfSound() * config->GetTimeSpacing() / (float)(2 - (int)config->GetIsPhotoacousticImage())); - percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + float totalSamples_i = (float)(config->GetReconstructionDepth()) / (float)(config->GetSpeedOfSound() * config->GetTimeSpacing()); + totalSamples_i = totalSamples_i <= inputS ? totalSamples_i : inputS; l_i = (float)line / outputL * inputL; for (short sample = 0; sample < outputS; ++sample) { - s_i = (float)sample / outputS * inputS / (float)(2 - (int)config->GetIsPhotoacousticImage()) * percentOfImageReconstructed; + s_i = (float)sample / outputS * totalSamples_i; part = part_multiplicator*s_i; if (part < 1) part = 1; - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); + maxLine = std::round(std::min((l_i + part) + 1, inputL)); + minLine = std::round(std::max((l_i - part), 0.0f)); usedLines = (maxLine - minLine); apod_mult = (float)apodArraySize / (float)usedLines; for (short l_s = minLine; l_s < maxLine; ++l_s) { + if (concave) + { + elementHeight = (probeRadius - std::cos(((abs(inputL / 2.f - l_s)*config->GetPitchInMeters()) / (2 * itk::Math::pi*probeRadius)) * 2 * itk::Math::pi)*probeRadius) / (config->GetSpeedOfSound()*config->GetTimeSpacing()); + } AddSample = (int)sqrt( - pow(s_i, 2) + pow(s_i-elementHeight, 2) + pow((1 / (config->GetTimeSpacing()*config->GetSpeedOfSound()) * (((float)l_s - l_i)*config->GetPitchInMeters()*(float)config->GetTransducerElements()) / inputL), 2) ) + (1 - config->GetIsPhotoacousticImage())*s_i; if (AddSample < inputS && AddSample >= 0) output[sample*(short)outputL + line] += input[l_s + AddSample*(short)inputL] * apodisation[(short)((l_s - minLine)*apod_mult)]; else --usedLines; } output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / usedLines; } } void mitk::BeamformingUtils::DMASQuadraticLine( float* input, float* output, float inputDim[2], float outputDim[2], const short& line, const mitk::BeamformingSettings::Pointer config) { const float* apodisation = config->GetApodizationFunction(); const short apodArraySize = config->GetApodizationArraySize(); float& inputS = inputDim[1]; float& inputL = inputDim[0]; float& outputS = outputDim[1]; float& outputL = outputDim[0]; short maxLine = 0; short minLine = 0; float delayMultiplicator = 0; float l_i = 0; float s_i = 0; float part = 0.07 * inputL; float tan_phi = std::tan(config->GetAngle() / 360 * 2 * itk::Math::pi); float part_multiplicator = tan_phi * config->GetTimeSpacing() * config->GetSpeedOfSound() / config->GetPitchInMeters() * inputL / (float)config->GetTransducerElements(); float apod_mult = 1; + float probeRadius = config->GetProbeRadius(); + bool concave = config->GetGeometry() == mitk::BeamformingSettings::ProbeGeometry::Concave; + float elementHeight = 0; + float mult = 0; short usedLines = (maxLine - minLine); - float percentOfImageReconstructed = (float)(config->GetReconstructionDepth()) / - (float)(inputS * config->GetSpeedOfSound() * config->GetTimeSpacing() / (float)(2 - (int)config->GetIsPhotoacousticImage())); - percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + float totalSamples_i = (float)(config->GetReconstructionDepth()) / + (float)(config->GetSpeedOfSound() * config->GetTimeSpacing()); + totalSamples_i = totalSamples_i <= inputS ? totalSamples_i : inputS; l_i = (float)line / outputL * inputL; for (short sample = 0; sample < outputS; ++sample) { - s_i = (float)sample / outputS * inputS / (float)(2 - (int)config->GetIsPhotoacousticImage()) * percentOfImageReconstructed; + s_i = (float)sample / outputS * totalSamples_i; part = part_multiplicator*s_i; if (part < 1) part = 1; - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); + maxLine = std::round(std::min((l_i + part) + 1, inputL)); + minLine = std::round(std::max((l_i - part), 0.0f)); usedLines = (maxLine - minLine); apod_mult = (float)apodArraySize / (float)usedLines; delayMultiplicator = pow((1 / (config->GetTimeSpacing()*config->GetSpeedOfSound()) * (config->GetPitchInMeters()*config->GetTransducerElements()) / inputL), 2) / s_i / 2; //calculate the AddSamples beforehand to save some time short* AddSample = new short[maxLine - minLine]; for (short l_s = 0; l_s < maxLine - minLine; ++l_s) { - AddSample[l_s] = (short)(delayMultiplicator * pow((minLine + l_s - l_i), 2) + s_i) + + if (concave) + { + elementHeight = (probeRadius - std::cos(((abs(inputL / 2.f - l_s)*config->GetPitchInMeters()) / (2 * itk::Math::pi*probeRadius)) * 2 * itk::Math::pi)*probeRadius) / (config->GetSpeedOfSound()*config->GetTimeSpacing()); + } + AddSample[l_s] = (short)(delayMultiplicator * pow((minLine + l_s - l_i), 2) + (s_i - elementHeight)) + (1 - config->GetIsPhotoacousticImage())*s_i; } float s_1 = 0; float s_2 = 0; for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) { if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) { for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) { if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) { s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); } } } else --usedLines; } output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)); delete[] AddSample; } } void mitk::BeamformingUtils::DMASSphericalLine( float* input, float* output, float inputDim[2], float outputDim[2], const short& line, const mitk::BeamformingSettings::Pointer config) { const float* apodisation = config->GetApodizationFunction(); const short apodArraySize = config->GetApodizationArraySize(); float& inputS = inputDim[1]; float& inputL = inputDim[0]; float& outputS = outputDim[1]; float& outputL = outputDim[0]; short maxLine = 0; short minLine = 0; float l_i = 0; float s_i = 0; float part = 0.07 * inputL; float tan_phi = std::tan(config->GetAngle() / 360 * 2 * itk::Math::pi); float part_multiplicator = tan_phi * config->GetTimeSpacing() * config->GetSpeedOfSound() / config->GetPitchInMeters() * inputL / (float)config->GetTransducerElements(); float apod_mult = 1; + float probeRadius = config->GetProbeRadius(); + bool concave = config->GetGeometry() == mitk::BeamformingSettings::ProbeGeometry::Concave; + float elementHeight = 0; + float mult = 0; short usedLines = (maxLine - minLine); - float percentOfImageReconstructed = (float)(config->GetReconstructionDepth()) / - (float)(inputS * config->GetSpeedOfSound() * config->GetTimeSpacing() / (float)(2 - (int)config->GetIsPhotoacousticImage())); - percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + float totalSamples_i = (float)(config->GetReconstructionDepth()) / + (float)(config->GetSpeedOfSound() * config->GetTimeSpacing()); + totalSamples_i = totalSamples_i <= inputS ? totalSamples_i : inputS; l_i = (float)line / outputL * inputL; for (short sample = 0; sample < outputS; ++sample) { - s_i = (float)sample / outputS * inputS / (float)(2 - (int)config->GetIsPhotoacousticImage()) * percentOfImageReconstructed; + s_i = (float)sample / outputS * totalSamples_i; part = part_multiplicator*s_i; if (part < 1) part = 1; - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); + maxLine = std::round(std::min((l_i + part) + 1, inputL)); + minLine = std::round(std::max((l_i - part), 0.0f)); usedLines = (maxLine - minLine); apod_mult = (float)apodArraySize / (float)usedLines; //calculate the AddSamples beforehand to save some time short* AddSample = new short[maxLine - minLine]; for (short l_s = 0; l_s < maxLine - minLine; ++l_s) { + if (concave) + { + elementHeight = (probeRadius - std::cos(((abs(inputL / 2.f - l_s)*config->GetPitchInMeters()) / (2 * itk::Math::pi*probeRadius)) * 2 * itk::Math::pi)*probeRadius) / (config->GetSpeedOfSound()*config->GetTimeSpacing()); + } AddSample[l_s] = (short)sqrt( - pow(s_i, 2) + pow(s_i - elementHeight, 2) + pow((1 / (config->GetTimeSpacing()*config->GetSpeedOfSound()) * (((float)minLine + (float)l_s - l_i)*config->GetPitchInMeters()*(float)config->GetTransducerElements()) / inputL), 2) ) + (1 - config->GetIsPhotoacousticImage())*s_i; } float s_1 = 0; float s_2 = 0; for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) { if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) { for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) { if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) { s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); } } } else --usedLines; } output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)); delete[] AddSample; } } void mitk::BeamformingUtils::sDMASQuadraticLine( float* input, float* output, float inputDim[2], float outputDim[2], const short& line, const mitk::BeamformingSettings::Pointer config) { const float* apodisation = config->GetApodizationFunction(); const short apodArraySize = config->GetApodizationArraySize(); float& inputS = inputDim[1]; float& inputL = inputDim[0]; float& outputS = outputDim[1]; float& outputL = outputDim[0]; short maxLine = 0; short minLine = 0; float delayMultiplicator = 0; float l_i = 0; float s_i = 0; float part = 0.07 * inputL; float tan_phi = std::tan(config->GetAngle() / 360 * 2 * itk::Math::pi); float part_multiplicator = tan_phi * config->GetTimeSpacing() * config->GetSpeedOfSound() / config->GetPitchInMeters() * inputL / (float)config->GetTransducerElements(); float apod_mult = 1; + float probeRadius = config->GetProbeRadius(); + bool concave = config->GetGeometry() == mitk::BeamformingSettings::ProbeGeometry::Concave; + float elementHeight = 0; + float mult = 0; short usedLines = (maxLine - minLine); - float percentOfImageReconstructed = (float)(config->GetReconstructionDepth()) / - (float)(inputS * config->GetSpeedOfSound() * config->GetTimeSpacing() / (float)(2 - (int)config->GetIsPhotoacousticImage())); - percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + float totalSamples_i = (float)(config->GetReconstructionDepth()) / + (float)(config->GetSpeedOfSound() * config->GetTimeSpacing()); + totalSamples_i = totalSamples_i <= inputS ? totalSamples_i : inputS; l_i = (float)line / outputL * inputL; for (short sample = 0; sample < outputS; ++sample) { - s_i = (float)sample / outputS * inputS / (float)(2 - (int)config->GetIsPhotoacousticImage()) * percentOfImageReconstructed; + s_i = (float)sample / outputS * totalSamples_i; part = part_multiplicator*s_i; if (part < 1) part = 1; - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); + maxLine = std::round(std::min((l_i + part) + 1, inputL)); + minLine = std::round(std::max((l_i - part), 0.0f)); usedLines = (maxLine - minLine); apod_mult = (float)apodArraySize / (float)usedLines; delayMultiplicator = pow((1 / (config->GetTimeSpacing()*config->GetSpeedOfSound()) * (config->GetPitchInMeters()*config->GetTransducerElements()) / inputL), 2) / s_i / 2; //calculate the AddSamples beforehand to save some time short* AddSample = new short[maxLine - minLine]; for (short l_s = 0; l_s < maxLine - minLine; ++l_s) { - AddSample[l_s] = (short)(delayMultiplicator * pow((minLine + l_s - l_i), 2) + s_i) + + if (concave) + { + elementHeight = (probeRadius - std::cos(((abs(inputL / 2.f - l_s)*config->GetPitchInMeters()) / (2 * itk::Math::pi*probeRadius)) * 2 * itk::Math::pi)*probeRadius) / (config->GetSpeedOfSound()*config->GetTimeSpacing()); + } + AddSample[l_s] = (short)(delayMultiplicator * pow((minLine + l_s - l_i), 2) + (s_i - elementHeight)) + (1 - config->GetIsPhotoacousticImage())*s_i; } float s_1 = 0; float s_2 = 0; float sign = 0; for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) { if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) { s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; sign += s_1; for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) { if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) { s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); } } } else --usedLines; } output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)) * ((sign > 0) - (sign < 0)); delete[] AddSample; } } void mitk::BeamformingUtils::sDMASSphericalLine( float* input, float* output, float inputDim[2], float outputDim[2], const short& line, const mitk::BeamformingSettings::Pointer config) { const float* apodisation = config->GetApodizationFunction(); const short apodArraySize = config->GetApodizationArraySize(); float& inputS = inputDim[1]; float& inputL = inputDim[0]; float& outputS = outputDim[1]; float& outputL = outputDim[0]; short maxLine = 0; short minLine = 0; float l_i = 0; float s_i = 0; float part = 0.07 * inputL; float tan_phi = std::tan(config->GetAngle() / 360 * 2 * itk::Math::pi); float part_multiplicator = tan_phi * config->GetTimeSpacing() * config->GetSpeedOfSound() / config->GetPitchInMeters() * inputL / (float)config->GetTransducerElements(); float apod_mult = 1; + float probeRadius = config->GetProbeRadius(); + bool concave = config->GetGeometry() == mitk::BeamformingSettings::ProbeGeometry::Concave; + float elementHeight = 0; + float mult = 0; short usedLines = (maxLine - minLine); - float percentOfImageReconstructed = (float)(config->GetReconstructionDepth()) / - (float)(inputS * config->GetSpeedOfSound() * config->GetTimeSpacing() / (float)(2 - (int)config->GetIsPhotoacousticImage())); - percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + float totalSamples_i = (float)(config->GetReconstructionDepth()) / + (float)(config->GetSpeedOfSound() * config->GetTimeSpacing()); + totalSamples_i = totalSamples_i <= inputS ? totalSamples_i : inputS; l_i = (float)line / outputL * inputL; for (short sample = 0; sample < outputS; ++sample) { - s_i = (float)sample / outputS * inputS / (float)(2 - (int)config->GetIsPhotoacousticImage()) * percentOfImageReconstructed; + s_i = (float)sample / outputS * totalSamples_i; part = part_multiplicator*s_i; if (part < 1) part = 1; - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); + maxLine = std::round(std::min((l_i + part) + 1, inputL)); + minLine = std::round(std::max((l_i - part), 0.0f)); usedLines = (maxLine - minLine); apod_mult = (float)apodArraySize / (float)usedLines; //calculate the AddSamples beforehand to save some time short* AddSample = new short[maxLine - minLine]; for (short l_s = 0; l_s < maxLine - minLine; ++l_s) { + if (concave) + { + elementHeight = (probeRadius - std::cos(((abs(inputL / 2.f - l_s)*config->GetPitchInMeters()) / (2 * itk::Math::pi*probeRadius)) * 2 * itk::Math::pi)*probeRadius) / (config->GetSpeedOfSound()*config->GetTimeSpacing()); + } AddSample[l_s] = (short)sqrt( - pow(s_i, 2) + pow(s_i - elementHeight, 2) + pow((1 / (config->GetTimeSpacing()*config->GetSpeedOfSound()) * (((float)minLine + (float)l_s - l_i)*config->GetPitchInMeters()*(float)config->GetTransducerElements()) / inputL), 2) ) + (1 - config->GetIsPhotoacousticImage())*s_i; } float s_1 = 0; float s_2 = 0; float sign = 0; for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) { if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) { s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; sign += s_1; for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) { if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) { s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); } } } else --usedLines; } output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)) * ((sign > 0) - (sign < 0)); delete[] AddSample; } }