diff --git a/Modules/PhotoacousticsLib/include/mitkPALinearSpectralUnmixingFilter.h b/Modules/PhotoacousticsLib/include/mitkPALinearSpectralUnmixingFilter.h index 7e02475cec..3f710b79a2 100644 --- a/Modules/PhotoacousticsLib/include/mitkPALinearSpectralUnmixingFilter.h +++ b/Modules/PhotoacousticsLib/include/mitkPALinearSpectralUnmixingFilter.h @@ -1,103 +1,103 @@ /*=================================================================== 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 MITKLINEARPHOTOACOUSTICSPECTRALUNMIXINGFILTER_H #define MITKLINEARPHOTOACOUSTICSPECTRALUNMIXINGFILTER_H #include #include namespace mitk { namespace pa { /** * \brief This filter is subclass of the spectral unmixing filter base. All algorithms in this class are * based on the Eigen open source c++ library. It takes a multispectral pixel as input and returns a vector * with the unmixing result. * * Input: * - endmemberMatrix Eigen Matrix with number of chromophores colums and number of wavelengths rows so matrix element (i,j) contains * the absorbtion of chromophore j @ wavelength i taken from the database by PropertyElement method. * - inputVector Eigen Vector containing values of one pixel of XY-plane image with number of wavelength rows (z-dimension of a sequenece) * so the pixelvalue of the first wavelength is stored in inputVector[0] and so on. * * Output: * - Eigen vector with unmixing result of one multispectral pixel. The ith element of the vector corresponds to the ith entry of the * m_Chromophore vector. * * Algorithms (see AlgortihmType enum): * - HOUSEHOLDERQR computes the solution by QR decomposition * - COLPIVHOUSEHOLDERQR computes the solution by QR decomposition * - FULLPIVHOUSEHOLDERQR computes the solution by QR decomposition * - LDLT computes the solution by Cholesky decomposition * - LLT computes the solution by Cholesky decomposition * - JACOBISVD computes the solution by singular value decomposition uses least square solver * * Possible exceptions: * - "algorithm not working": doesn't work now (2018/06/19) * - "404 VIGRA ALGORITHM NOT FOUND": Algorithm not implemented */ class MITKPHOTOACOUSTICSLIB_EXPORT LinearSpectralUnmixingFilter : public SpectralUnmixingFilterBase { public: mitkClassMacro(LinearSpectralUnmixingFilter, SpectralUnmixingFilterBase) itkFactorylessNewMacro(Self) /** * \brief Contains all implemented Eigen algorithms for spectral unmixing. For detailed information of the algorithms look at the * mitkPALinearSpectralUnmixingFilter.h documentation (section Algorithms). */ enum AlgortihmType { HOUSEHOLDERQR, LDLT, LLT, COLPIVHOUSEHOLDERQR, JACOBISVD, FULLPIVLU, FULLPIVHOUSEHOLDERQR }; /** * \brief Takes a mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType and fix it for usage at the "SpectralUnmixingAlgorithm" method. * @param algorithmName has to be a mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType */ - void mitk::pa::LinearSpectralUnmixingFilter::SetAlgorithm(AlgortihmType inputAlgorithmName); + void SetAlgorithm(AlgortihmType inputAlgorithmName); protected: LinearSpectralUnmixingFilter(); virtual ~LinearSpectralUnmixingFilter(); /** * \brief overrides the baseclass method with a mehtod to calculate the spectral unmixing result vector. Herain the class performs the * algorithm set by the "SetAlgorithm" method and writes the result into a Eigen vector which is the return value. * @param endmemberMatrix Matrix with number of chromophores colums and number of wavelengths rows so matrix element (i,j) contains * the absorbtion of chromophore j @ wavelength i taken from the database by PropertyElement method. * @param inputVector Vector containing values of one pixel of XY-plane image with number of wavelength rows (z-dimension of a sequenece) * so the pixelvalue of the first wavelength is stored in inputVector[0] and so on. * @throws if the algorithmName is not a member of the enum VigraAlgortihmType * @throws if one chooses the ldlt/llt solver which doens't work yet */ virtual Eigen::VectorXf SpectralUnmixingAlgorithm(Eigen::Matrix endmemberMatrix, Eigen::VectorXf inputVector) override; private: - mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType algorithmName; + AlgortihmType algorithmName; }; } } #endif // MITKLINEARPHOTOACOUSTICSPECTRALUNMIXINGFILTER_H diff --git a/Modules/PhotoacousticsLib/include/mitkPASpectralUnmixingFilterVigra.h b/Modules/PhotoacousticsLib/include/mitkPASpectralUnmixingFilterVigra.h index f29fdea5fc..a8b7926a5b 100644 --- a/Modules/PhotoacousticsLib/include/mitkPASpectralUnmixingFilterVigra.h +++ b/Modules/PhotoacousticsLib/include/mitkPASpectralUnmixingFilterVigra.h @@ -1,108 +1,108 @@ /*=================================================================== 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 MITKPHOTOACOUSTICSPECTRALUNMIXINGFILTERVIGRA_H #define MITKPHOTOACOUSTICSPECTRALUNMIXINGFILTERVIGRA_H #include #include #include namespace mitk { namespace pa { /** * \brief This filter is subclass of the spectral unmixing filter base. All algorithms in this class are * based on the vigra open source c++ library. It takes a multispectral pixel as input and returns a vector * with the unmixing result. * * Input: * - endmemberMatrix Eigen Matrix with number of chromophores colums and number of wavelengths rows so matrix element (i,j) contains * the absorbtion of chromophore j @ wavelength i taken from the database by PropertyElement method. * - inputVector Eigen Vector containing values of one pixel of XY-plane image with number of wavelength rows (z-dimension of a sequenece) * so the pixelvalue of the first wavelength is stored in inputVector[0] and so on. * * Output: * - Eigen vector with unmixing result of one multispectral pixel. The ith element of the vector corresponds to the ith entry of the * m_Chromophore vector. * * Algorithms (see VigraAlgortihmType enum): * - LARS algorithm minimizes (A*x-b)^2 s.t. x>=0 using least angle regression * - GOLDFARB minimizes (A*x-b)^2 s.t. x>=0 using the Goldfarb-Idnani algorithm * - WEIGHTED minimizes transpose(A*x-b)*diag(weights)*(A*x-b) using QR decomposition * - LS minimizes (A*x-b)^2 using QR decomposition * * Possible exceptions: * - "404 VIGRA ALGORITHM NOT FOUND": Algorithm not implemented */ class MITKPHOTOACOUSTICSLIB_EXPORT SpectralUnmixingFilterVigra : public SpectralUnmixingFilterBase { public: mitkClassMacro(SpectralUnmixingFilterVigra, SpectralUnmixingFilterBase) itkFactorylessNewMacro(Self) /** * \brief Contains all implemented Vigra algorithms for spectral unmixing. For detailed information of the algorithms look at the * mitkPASpectralUnmixingFilterVigra.h documentation (section Algorithms). */ enum VigraAlgortihmType { LARS, GOLDFARB, WEIGHTED, LS }; /** * \brief AddWeight takes integers and writes them at the end of the weightsvec vector. The first call of the method then * corresponds to the first input image/wavelength and so on. * @param weight is a percentage (integer) between 1 and 100 */ void AddWeight(unsigned int weight); /** * \brief Takes a mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType and fix it for usage at the "SpectralUnmixingAlgorithm" * method. * @param algorithmName has to be a mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType */ - void mitk::pa::SpectralUnmixingFilterVigra::SetAlgorithm(VigraAlgortihmType inputAlgorithmName); + void SetAlgorithm(VigraAlgortihmType inputAlgorithmName); protected: SpectralUnmixingFilterVigra(); virtual ~SpectralUnmixingFilterVigra(); /** * \brief overrides the baseclass method with a mehtod to calculate the spectral unmixing result vector. Herain it first converts the * Eigen inputs to the Vigra class. Afterwards the class performs the algorithm set by the "SetAlgorithm" method and writes the result * into a Eigen vector which is the return value. * @param endmemberMatrix Matrix with number of chromophores colums and number of wavelengths rows so matrix element (i,j) contains * the absorbtion of chromophore j @ wavelength i taken from the database by PropertyElement method. * @param inputVector Vector containing values of one pixel of XY-plane image with number of wavelength rows (z-dimension of a sequenece) * so the pixelvalue of the first wavelength is stored in inputVector[0] and so on. * @throws if the algorithmName is not a member of the enum VigraAlgortihmType */ virtual Eigen::VectorXf SpectralUnmixingAlgorithm(Eigen::Matrix EndmemberMatrix, Eigen::VectorXf inputVector) override; private: std::vector weightsvec; - mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType algorithmName; + SpectralUnmixingFilterVigra::VigraAlgortihmType algorithmName; }; } } #endif // MITKPHOTOACOUSTICSPECTRALUNMIXINGFILTERVIGRA_H diff --git a/Modules/PhotoacousticsLib/src/SUFilter/mitkPALinearSpectralUnmixingFilter.cpp b/Modules/PhotoacousticsLib/src/SUFilter/mitkPALinearSpectralUnmixingFilter.cpp index feb1b59449..ec6b845795 100644 --- a/Modules/PhotoacousticsLib/src/SUFilter/mitkPALinearSpectralUnmixingFilter.cpp +++ b/Modules/PhotoacousticsLib/src/SUFilter/mitkPALinearSpectralUnmixingFilter.cpp @@ -1,84 +1,84 @@ /*=================================================================== 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 "mitkPALinearSpectralUnmixingFilter.h" // Testing algorithms -#include +#include // ImageAccessor #include #include mitk::pa::LinearSpectralUnmixingFilter::LinearSpectralUnmixingFilter() { } mitk::pa::LinearSpectralUnmixingFilter::~LinearSpectralUnmixingFilter() { } void mitk::pa::LinearSpectralUnmixingFilter::SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType inputAlgorithmName) { algorithmName = inputAlgorithmName; } Eigen::VectorXf mitk::pa::LinearSpectralUnmixingFilter::SpectralUnmixingAlgorithm( Eigen::Matrix endmemberMatrix, Eigen::VectorXf inputVector) { Eigen::VectorXf resultVector; if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::HOUSEHOLDERQR == algorithmName) resultVector = endmemberMatrix.householderQr().solve(inputVector); else if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::LDLT == algorithmName) { Eigen::LLT lltOfA(endmemberMatrix); if (lltOfA.info() == Eigen::NumericalIssue) { mitkThrow() << "Possibly non semi-positive definitie endmembermatrix!"; } else resultVector = endmemberMatrix.ldlt().solve(inputVector); } else if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::LLT == algorithmName) { Eigen::LLT lltOfA(endmemberMatrix); if (lltOfA.info() == Eigen::NumericalIssue) { mitkThrow() << "Possibly non semi-positive definitie endmembermatrix!"; } else resultVector = endmemberMatrix.llt().solve(inputVector); } else if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::COLPIVHOUSEHOLDERQR == algorithmName) resultVector = endmemberMatrix.colPivHouseholderQr().solve(inputVector); else if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::JACOBISVD == algorithmName) resultVector = endmemberMatrix.jacobiSvd(Eigen::ComputeFullU | Eigen::ComputeFullV).solve(inputVector); else if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::FULLPIVLU == algorithmName) resultVector = endmemberMatrix.fullPivLu().solve(inputVector); else if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::FULLPIVHOUSEHOLDERQR == algorithmName) resultVector = endmemberMatrix.fullPivHouseholderQr().solve(inputVector); else mitkThrow() << "404 VIGRA ALGORITHM NOT FOUND"; return resultVector; } diff --git a/Modules/PhotoacousticsLib/src/SUFilter/mitkPASpectralUnmixingSO2.cpp b/Modules/PhotoacousticsLib/src/SUFilter/mitkPASpectralUnmixingSO2.cpp index 907c784bcd..17a9e05863 100644 --- a/Modules/PhotoacousticsLib/src/SUFilter/mitkPASpectralUnmixingSO2.cpp +++ b/Modules/PhotoacousticsLib/src/SUFilter/mitkPASpectralUnmixingSO2.cpp @@ -1,165 +1,165 @@ /*=================================================================== 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 "mitkPASpectralUnmixingSO2.h" // ImageAccessor #include #include mitk::pa::SpectralUnmixingSO2::SpectralUnmixingSO2() { this->SetNumberOfIndexedInputs(2); this->SetNumberOfIndexedOutputs(1); this->SetNthOutput(0, mitk::Image::New()); } mitk::pa::SpectralUnmixingSO2::~SpectralUnmixingSO2() { } void mitk::pa::SpectralUnmixingSO2::Verbose(bool verbose) { m_Verbose = verbose; } void mitk::pa::SpectralUnmixingSO2::GenerateData() { MITK_INFO(m_Verbose) << "GENERATING DATA.."; // Get input image mitk::Image::Pointer inputHbO2 = GetInput(0); mitk::Image::Pointer inputHb = GetInput(1); CheckPreConditions(inputHbO2, inputHb); unsigned int xDim = inputHbO2->GetDimensions()[0]; unsigned int yDim = inputHbO2->GetDimensions()[1]; unsigned int zDim = inputHbO2->GetDimensions()[2]; InitializeOutputs(); mitk::ImageReadAccessor readAccessHbO2(inputHbO2); mitk::ImageReadAccessor readAccessHb(inputHb); const float* inputDataArrayHbO2 = ((const float*)readAccessHbO2.GetData()); const float* inputDataArrayHb = ((const float*)readAccessHb.GetData()); auto output = GetOutput(0); mitk::ImageWriteAccessor writeOutput(output); float* writeBuffer = (float *)writeOutput.GetData(); for (unsigned int x = 0; x < xDim; x++) { for (unsigned int y = 0; y < yDim; y++) { for (unsigned int z = 0;z < zDim; z++) { unsigned int pixelNumber = (xDim*yDim * z) + x * yDim + y; float pixelHb = inputDataArrayHb[pixelNumber]; float pixelHbO2 = inputDataArrayHbO2[pixelNumber]; float resultSO2 = CalculateSO2(pixelHb, pixelHbO2); writeBuffer[(xDim*yDim * z) + x * yDim + y] = resultSO2; } } } MITK_INFO(m_Verbose) << "GENERATING DATA...[DONE]"; } void mitk::pa::SpectralUnmixingSO2::CheckPreConditions(mitk::Image::Pointer inputHbO2, mitk::Image::Pointer inputHb) { unsigned int xDimHb = inputHb->GetDimensions()[0]; unsigned int yDimHb = inputHb->GetDimensions()[1]; unsigned int zDimHb = inputHb->GetDimensions()[2]; unsigned int xDimHbO2 = inputHbO2->GetDimensions()[0]; unsigned int yDimHbO2 = inputHbO2->GetDimensions()[1]; unsigned int zDimHbO2 = inputHbO2->GetDimensions()[2]; if (xDimHb != xDimHbO2 || yDimHb != yDimHbO2 || zDimHb != zDimHbO2) mitkThrow() << "DIMENTIONALITY ERROR!"; if (inputHbO2->GetPixelType() != mitk::MakeScalarPixelType()) mitkThrow() << "PIXELTYPE ERROR! FLOAT REQUIRED"; if (inputHb->GetPixelType() != mitk::MakeScalarPixelType()) mitkThrow() << "PIXELTYPE ERROR! FLOAT REQUIRED"; MITK_INFO(m_Verbose) << "CHECK PRECONDITIONS ...[DONE]"; } void mitk::pa::SpectralUnmixingSO2::InitializeOutputs() { - unsigned int numberOfInputs = GetNumberOfIndexedInputs(); + // UNUSED unsigned int numberOfInputs = GetNumberOfIndexedInputs(); unsigned int numberOfOutputs = GetNumberOfIndexedOutputs(); mitk::PixelType pixelType = mitk::MakeScalarPixelType(); const int NUMBER_OF_SPATIAL_DIMENSIONS = 3; auto* dimensions = new unsigned int[NUMBER_OF_SPATIAL_DIMENSIONS]; for(unsigned int dimIdx=0; dimIdxGetDimensions()[dimIdx]; } for (unsigned int outputIdx = 0; outputIdx < numberOfOutputs; outputIdx++) { GetOutput(outputIdx)->Initialize(pixelType, NUMBER_OF_SPATIAL_DIMENSIONS, dimensions); } } float mitk::pa::SpectralUnmixingSO2::CalculateSO2(float Hb, float HbO2) { float result = HbO2 / (Hb + HbO2); if (result != result) { MITK_WARN(m_Verbose) << "SO2 VALUE NAN! WILL BE SET TO ZERO!"; return 0; } else { if (SO2ValueNotSiginificant(Hb, HbO2, result)) { return 0; } else return result; } } void mitk::pa::SpectralUnmixingSO2::AddSO2Settings(int value) { m_SO2Settings.push_back(value); } bool mitk::pa::SpectralUnmixingSO2::SO2ValueNotSiginificant(float Hb, float HbO2, float result) { std::vector significant; significant.push_back(HbO2); significant.push_back(Hb); significant.push_back(HbO2 + Hb); significant.push_back(100*(result)); for (unsigned int i = 0; i < m_SO2Settings.size(); ++i) { if (m_SO2Settings[i] > significant[i] && (std::abs(m_SO2Settings[i] - significant[i]) > 1e-7)) { return true; } } return false; } diff --git a/Modules/PhotoacousticsLib/test/mitkSpectralUnmixingTest.cpp b/Modules/PhotoacousticsLib/test/mitkSpectralUnmixingTest.cpp index 8bf6f264b5..6ee48c6dcd 100644 --- a/Modules/PhotoacousticsLib/test/mitkSpectralUnmixingTest.cpp +++ b/Modules/PhotoacousticsLib/test/mitkSpectralUnmixingTest.cpp @@ -1,684 +1,684 @@ //*=================================================================== //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 class mitkSpectralUnmixingTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkSpectralUnmixingTestSuite); MITK_TEST(testEigenSUAlgorithm); MITK_TEST(testVigraSUAlgorithm); MITK_TEST(testSimplexSUAlgorithm); MITK_TEST(testSO2); MITK_TEST(testExceptionSO2); MITK_TEST(testWavelengthExceptions); MITK_TEST(testNoChromophoresSelected); MITK_TEST(testInputImage); MITK_TEST(testAddOutput); MITK_TEST(testWeightsError); MITK_TEST(testOutputs); CPPUNIT_TEST_SUITE_END(); private: mitk::pa::SpectralUnmixingFilterBase::Pointer m_SpectralUnmixingFilter; mitk::Image::Pointer inputImage; std::vector m_inputWavelengths; std::vector m_inputWeights; std::vector m_CorrectResult; float threshold; public: void setUp() override { //Set empty input image: inputImage = mitk::Image::New(); mitk::PixelType pixelType = mitk::MakeScalarPixelType(); const int NUMBER_OF_SPATIAL_DIMENSIONS = 3; auto* dimensions = new unsigned int[NUMBER_OF_SPATIAL_DIMENSIONS]; dimensions[0] = 1; dimensions[1] = 1; dimensions[2] = 5; inputImage->Initialize(pixelType, NUMBER_OF_SPATIAL_DIMENSIONS, dimensions); //Set wavelengths for unmixing: m_inputWavelengths.push_back(750); m_inputWavelengths.push_back(800); m_inputWeights.push_back(50); m_inputWeights.push_back(100); //Set fraction of Hb and HbO2 to unmix: float fracHb = 100; float fracHbO2 = 300; m_CorrectResult.push_back(fracHbO2); m_CorrectResult.push_back(fracHb); m_CorrectResult.push_back(fracHbO2 + 10); m_CorrectResult.push_back(fracHb - 10); threshold = 0.01; //Multiply values of wavelengths (750,800,850 nm) with fractions to get pixel values: float px1 = fracHb * 7.52 + fracHbO2 * 2.77; float px2 = fracHb * 4.08 + fracHbO2 * 4.37; float px3 = (fracHb - 10) * 7.52 + (fracHbO2 + 10) * 2.77; float px4 = (fracHb - 10) * 4.08 + (fracHbO2 + 10) * 4.37; float* data = new float[3]; data[0] = px1; data[1] = px2; data[2] = px3; data[3] = px4; data[5] = 0; inputImage->SetImportVolume(data, mitk::Image::ImportMemoryManagementType::CopyMemory); delete[] data; } // Tests implemented EIGEN algortihms with correct inputs void testEigenSUAlgorithm() { MITK_INFO << "START FILTER TEST ... "; // Set input image auto m_SpectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New(); m_SpectralUnmixingFilter->Verbose(false); m_SpectralUnmixingFilter->RelativeError(false); m_SpectralUnmixingFilter->SetInput(inputImage); m_SpectralUnmixingFilter->AddOutputs(2); //Set wavelengths to filter for (unsigned int imageIndex = 0; imageIndex < m_inputWavelengths.size(); imageIndex++) { unsigned int wavelength = m_inputWavelengths[imageIndex]; m_SpectralUnmixingFilter->AddWavelength(wavelength); } //Set Chromophores to filter m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::OXYGENATED); m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::DEOXYGENATED); ofstream myfile; myfile.open("EigenTestResult.txt"); std::vector m_Eigen = { mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::HOUSEHOLDERQR, /* mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::LDLT, mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::LLT,*/ mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::COLPIVHOUSEHOLDERQR, mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::JACOBISVD, mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::FULLPIVLU, mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::FULLPIVHOUSEHOLDERQR}; - for (int Algorithmidx = 0; Algorithmidx < m_Eigen.size();++Algorithmidx) + for (unsigned int Algorithmidx = 0; Algorithmidx < m_Eigen.size();++Algorithmidx) { m_SpectralUnmixingFilter->SetAlgorithm(m_Eigen[Algorithmidx]); m_SpectralUnmixingFilter->Update(); /*For printed pixel values and results look at: [...]\mitk-superbuild\MITK-build\Modules\PhotoacousticsLib\test\*/ for (int i = 0; i < 2; ++i) { mitk::Image::Pointer output = m_SpectralUnmixingFilter->GetOutput(i); mitk::ImageReadAccessor readAccess(output); const float* inputDataArray = ((const float*)readAccess.GetData()); auto pixel = inputDataArray[0]; auto pixel2 = inputDataArray[1]; myfile << "Algorithmidx: " << Algorithmidx << "\n Output " << i << ": " << "\n" << inputDataArray[0] << "\n" << inputDataArray[1] << "\n"; myfile << "Correct Result: " << "\n" << m_CorrectResult[i] << "\n" << m_CorrectResult[i + 2] << "\n"; CPPUNIT_ASSERT(std::abs(pixel - m_CorrectResult[i]) < threshold); CPPUNIT_ASSERT(std::abs(pixel2 - m_CorrectResult[i + 2]) < threshold); } } myfile.close(); MITK_INFO << "EIGEN FILTER TEST SUCCESFULL :)"; } // Tests implemented VIGRA algortihms with correct inputs void testVigraSUAlgorithm() { MITK_INFO << "START FILTER TEST ... "; // Set input image auto m_SpectralUnmixingFilter = mitk::pa::SpectralUnmixingFilterVigra::New(); m_SpectralUnmixingFilter->SetInput(inputImage); m_SpectralUnmixingFilter->AddOutputs(2); m_SpectralUnmixingFilter->Verbose(false); m_SpectralUnmixingFilter->RelativeError(false); //Set wavelengths to filter for (unsigned int imageIndex = 0; imageIndex < m_inputWavelengths.size(); imageIndex++) { unsigned int wavelength = m_inputWavelengths[imageIndex]; double Weight = m_inputWeights[imageIndex]; m_SpectralUnmixingFilter->AddWavelength(wavelength); m_SpectralUnmixingFilter->AddWeight(Weight); } //Set Chromophores to filter m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::OXYGENATED); m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::DEOXYGENATED); std::vector Vigra = { mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType::LARS, mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType::GOLDFARB, mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType::WEIGHTED, mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType::LS/*, mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType::vigratest*/}; ofstream myfile; myfile.open("VigraTestResult.txt"); - for (int Algorithmidx = 0; Algorithmidx < Vigra.size();++Algorithmidx) + for (unsigned int Algorithmidx = 0; Algorithmidx < Vigra.size();++Algorithmidx) { m_SpectralUnmixingFilter->SetAlgorithm(Vigra[0]); m_SpectralUnmixingFilter->Update(); /*For printed pixel values and results look at: [...]\mitk-superbuild\MITK-build\Modules\PhotoacousticsLib\test\*/ for (int i = 0; i < 2; ++i) { mitk::Image::Pointer output = m_SpectralUnmixingFilter->GetOutput(i); mitk::ImageReadAccessor readAccess(output); const float* inputDataArray = ((const float*)readAccess.GetData()); auto pixel = inputDataArray[0]; auto pixel2 = inputDataArray[1]; myfile << "Algorithmidx: " << Algorithmidx << "\n Output " << i << ": " << "\n" << inputDataArray[0] << "\n" << inputDataArray[1] << "\n"; myfile << "Correct Result: " << "\n" << m_CorrectResult[i] << "\n" << m_CorrectResult[i + 2] << "\n"; CPPUNIT_ASSERT(std::abs(pixel - m_CorrectResult[i]) < threshold); CPPUNIT_ASSERT(std::abs(pixel2 - m_CorrectResult[i + 2]) < threshold); } } myfile.close(); MITK_INFO << "VIGRA FILTER TEST SUCCESFULL :)"; } void testSimplexSUAlgorithm() { MITK_INFO << "START FILTER TEST ... "; // Set input image auto m_SpectralUnmixingFilter = mitk::pa::SpectralUnmixingFilterSimplex::New(); m_SpectralUnmixingFilter->SetInput(inputImage); m_SpectralUnmixingFilter->AddOutputs(2); m_SpectralUnmixingFilter->Verbose(true); m_SpectralUnmixingFilter->RelativeError(false); //Set wavelengths to filter for (unsigned int imageIndex = 0; imageIndex < m_inputWavelengths.size(); imageIndex++) { unsigned int wavelength = m_inputWavelengths[imageIndex]; m_SpectralUnmixingFilter->AddWavelength(wavelength); } //Set Chromophores to filter m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::OXYGENATED); m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::DEOXYGENATED); m_SpectralUnmixingFilter->Update(); /*For printed pixel values and results look at: [...]\mitk-superbuild\MITK-build\Modules\PhotoacousticsLib\test\*/ ofstream myfile; myfile.open("SimplexTestResult.txt"); for (int i = 0; i < 2; ++i) { mitk::Image::Pointer output = m_SpectralUnmixingFilter->GetOutput(i); mitk::ImageReadAccessor readAccess(output); const float* inputDataArray = ((const float*)readAccess.GetData()); auto pixel = inputDataArray[0]; auto pixel2 = inputDataArray[1]; myfile << "Output " << i << ": " << "\n" << inputDataArray[0] << "\n" << inputDataArray[1] << "\n"; myfile << "Correct Result: " << "\n" << m_CorrectResult[i] << "\n" << m_CorrectResult[i + 2] << "\n"; CPPUNIT_ASSERT(std::abs(pixel - m_CorrectResult[i])SetInput(0, inputImage); inputImage = nullptr; inputImage = mitk::Image::New(); mitk::PixelType pixelType = mitk::MakeScalarPixelType(); const int NUMBER_OF_SPATIAL_DIMENSIONS = 3; auto* dimensions = new unsigned int[NUMBER_OF_SPATIAL_DIMENSIONS]; dimensions[0] = 1; dimensions[1] = 1; dimensions[2] = 4; inputImage->Initialize(pixelType, NUMBER_OF_SPATIAL_DIMENSIONS, dimensions); float* data = new float[3]; data[0] = 1; data[1] = 2; data[2] = 3; data[3] = 4; inputImage->SetImportVolume(data, mitk::Image::ImportMemoryManagementType::CopyMemory); delete[] data; m_sO2->SetInput(1, inputImage); MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ExceptionObject) m_sO2->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ExceptionObject) } // Tests SO2 Filter with correct inputs void testSO2() { MITK_INFO << "START SO2 TEST ... "; std::vector CorrectSO2Result1 = { 0, 0, 0, 0, 0 }; std::vector Test1 = { 0,0,0,51 }; std::vector CorrectSO2Result2 = { 0, 0.5, 0, 0.5, 0 }; std::vector Test2 = { 1584, 0, 0, 0 }; std::vector CorrectSO2Result3 = { 0.5, 0.5, 0, 0.5, 0 }; std::vector Test3 = { 0, 1536, 0, 0 }; std::vector CorrectSO2Result4 = { 0.5, 0.5, 0, 0.5, 0 }; std::vector Test4 = { 0, 0, 3072, 49 }; std::vector CorrectSO2Result5 = { 0.5, 0.5, 0.5, 0.5, 0 }; std::vector Test5 = { 1, 1, 1, 49 }; std::vector> TestList; std::vector> ResultList; TestList.push_back(Test1); TestList.push_back(Test2); TestList.push_back(Test3); TestList.push_back(Test4); TestList.push_back(Test5); ResultList.push_back(CorrectSO2Result1); ResultList.push_back(CorrectSO2Result2); ResultList.push_back(CorrectSO2Result3); ResultList.push_back(CorrectSO2Result4); ResultList.push_back(CorrectSO2Result5); /*For printed pixel values and results look at: [...]\mitk-superbuild\MITK-build\Modules\PhotoacousticsLib\test\*/ ofstream myfile; myfile.open("SO2TestResult.txt"); for (int k = 0; k < 5; ++k) { std::vector SO2Settings = TestList[k]; std::vector m_CorrectSO2Result = ResultList[k]; auto m_sO2 = mitk::pa::SpectralUnmixingSO2::New(); m_sO2->SetInput(0, inputImage); m_sO2->SetInput(1, inputImage); - for (int i = 0; i < SO2Settings.size(); ++i) + for (unsigned int i = 0; i < SO2Settings.size(); ++i) m_sO2->AddSO2Settings(SO2Settings[i]); m_sO2->Update(); mitk::Image::Pointer output = m_sO2->GetOutput(0); mitk::ImageReadAccessor readAccess(output); const float* inputDataArray = ((const float*)readAccess.GetData()); for (unsigned int Pixel = 0; Pixel < inputImage->GetDimensions()[2]; ++Pixel) { auto Value = inputDataArray[Pixel]; myfile << "Output(Test " << k << ") " << Pixel << ": " << "\n" << Value << "\n"; myfile << "Correct Result: " << "\n" << m_CorrectSO2Result[Pixel] << "\n"; CPPUNIT_ASSERT(std::abs(Value - m_CorrectSO2Result[Pixel]) < threshold); } } myfile.close(); MITK_INFO << "SO2 TEST SUCCESFULL :)"; } // Test exceptions for wrong wavelength inputs void testWavelengthExceptions() { MITK_INFO << "START WavelengthExceptions TEST ... "; // Set input image auto m_SpectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New(); m_SpectralUnmixingFilter->Verbose(false); m_SpectralUnmixingFilter->RelativeError(false); m_SpectralUnmixingFilter->SetInput(inputImage); m_SpectralUnmixingFilter->AddOutputs(2); m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::OXYGENATED); m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::DEOXYGENATED); m_SpectralUnmixingFilter->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::HOUSEHOLDERQR); MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ExceptionObject) m_SpectralUnmixingFilter->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ExceptionObject) m_SpectralUnmixingFilter->AddWavelength(300); MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ExceptionObject) m_SpectralUnmixingFilter->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ExceptionObject) m_SpectralUnmixingFilter->AddWavelength(299); MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ExceptionObject) m_SpectralUnmixingFilter->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ExceptionObject) MITK_INFO << "DONE"; } // Test exceptions for wrong chromophore inputs void testNoChromophoresSelected() { MITK_INFO << "testNoChromophoresSelected"; // Set input image auto m_SpectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New(); m_SpectralUnmixingFilter->Verbose(false); m_SpectralUnmixingFilter->RelativeError(false); m_SpectralUnmixingFilter->SetInput(inputImage); m_SpectralUnmixingFilter->AddOutputs(2); //Set wavelengths to filter for (unsigned int imageIndex = 0; imageIndex < m_inputWavelengths.size(); imageIndex++) { unsigned int wavelength = m_inputWavelengths[imageIndex]; m_SpectralUnmixingFilter->AddWavelength(wavelength); } m_SpectralUnmixingFilter->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::HOUSEHOLDERQR); MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ExceptionObject) m_SpectralUnmixingFilter->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ExceptionObject) } // Test exceptions for wrong input image void testInputImage() { MITK_INFO << "INPUT IMAGE TEST"; inputImage = nullptr; // Set input image auto m_SpectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New(); m_SpectralUnmixingFilter->Verbose(false); m_SpectralUnmixingFilter->RelativeError(false); //m_SpectralUnmixingFilter->SetInput(inputImage); m_SpectralUnmixingFilter->AddOutputs(2); //Set wavelengths to filter for (unsigned int imageIndex = 0; imageIndex < m_inputWavelengths.size(); imageIndex++) { unsigned int wavelength = m_inputWavelengths[imageIndex]; m_SpectralUnmixingFilter->AddWavelength(wavelength); } m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::OXYGENATED); m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::DEOXYGENATED); m_SpectralUnmixingFilter->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::HOUSEHOLDERQR); MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ExceptionObject) m_SpectralUnmixingFilter->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ExceptionObject) inputImage = mitk::Image::New(); mitk::PixelType pixelType = mitk::MakeScalarPixelType(); const int NUMBER_OF_SPATIAL_DIMENSIONS = 3; auto* dimensions = new unsigned int[NUMBER_OF_SPATIAL_DIMENSIONS]; dimensions[0] = 1; dimensions[1] = 1; dimensions[2] = 5; inputImage->Initialize(pixelType, NUMBER_OF_SPATIAL_DIMENSIONS, dimensions); double* data = new double[3]; data[0] = 1; data[1] = 2; data[2] = 3; data[3] = 4; data[5] = 0; inputImage->SetImportVolume(data, mitk::Image::ImportMemoryManagementType::CopyMemory); delete[] data; m_SpectralUnmixingFilter->SetInput(inputImage); MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ExceptionObject) m_SpectralUnmixingFilter->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ExceptionObject) } // Test exceptions for addOutputs method void testAddOutput() { MITK_INFO << "addOutputs TEST"; // Set input image auto m_SpectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New(); m_SpectralUnmixingFilter->Verbose(false); m_SpectralUnmixingFilter->RelativeError(false); m_SpectralUnmixingFilter->SetInput(inputImage); //Set wavelengths to filter for (unsigned int imageIndex = 0; imageIndex < m_inputWavelengths.size(); imageIndex++) { unsigned int wavelength = m_inputWavelengths[imageIndex]; m_SpectralUnmixingFilter->AddWavelength(wavelength); } m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::OXYGENATED); m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::DEOXYGENATED); m_SpectralUnmixingFilter->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::HOUSEHOLDERQR); for (int i = 0; i < 4; ++i) { MITK_INFO << "i: " << i; if (i != 2) { MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ExceptionObject) m_SpectralUnmixingFilter->AddOutputs(i); m_SpectralUnmixingFilter->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ExceptionObject) } else { m_SpectralUnmixingFilter->AddOutputs(2); m_SpectralUnmixingFilter->Update(); for (int i = 0; i < 2; ++i) { mitk::Image::Pointer output = m_SpectralUnmixingFilter->GetOutput(i); mitk::ImageReadAccessor readAccess(output); const float* inputDataArray = ((const float*)readAccess.GetData()); auto pixel = inputDataArray[0]; auto pixel2 = inputDataArray[1]; CPPUNIT_ASSERT(std::abs(pixel - m_CorrectResult[i]) < threshold); CPPUNIT_ASSERT(std::abs(pixel2 - m_CorrectResult[i + 2]) < threshold); } } } } // Test exceptions for weights error void testWeightsError() { MITK_INFO << "testWeightsError"; // Set input image auto m_SpectralUnmixingFilter = mitk::pa::SpectralUnmixingFilterVigra::New(); m_SpectralUnmixingFilter->Verbose(false); m_SpectralUnmixingFilter->RelativeError(false); m_SpectralUnmixingFilter->SetInput(inputImage); m_SpectralUnmixingFilter->AddOutputs(2); //Set wavelengths to filter for (unsigned int imageIndex = 0; imageIndex < m_inputWavelengths.size(); imageIndex++) { unsigned int wavelength = m_inputWavelengths[imageIndex]; m_SpectralUnmixingFilter->AddWavelength(wavelength); } m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::OXYGENATED); m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::DEOXYGENATED); m_SpectralUnmixingFilter->SetAlgorithm(mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType::WEIGHTED); MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ExceptionObject) m_SpectralUnmixingFilter->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ExceptionObject) m_SpectralUnmixingFilter->AddWeight(50); MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ExceptionObject) m_SpectralUnmixingFilter->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ExceptionObject) m_SpectralUnmixingFilter->AddWeight(50); m_SpectralUnmixingFilter->Update(); for (int i = 0; i < 2; ++i) { mitk::Image::Pointer output = m_SpectralUnmixingFilter->GetOutput(i); mitk::ImageReadAccessor readAccess(output); const float* inputDataArray = ((const float*)readAccess.GetData()); auto pixel = inputDataArray[0]; auto pixel2 = inputDataArray[1]; CPPUNIT_ASSERT(std::abs(pixel - m_CorrectResult[i]) < threshold); CPPUNIT_ASSERT(std::abs(pixel2 - m_CorrectResult[i + 2]) < threshold); } } // Test correct outputs void testOutputs() { MITK_INFO << "TEST"; // Set input image auto m_SpectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New(); m_SpectralUnmixingFilter->Verbose(false); m_SpectralUnmixingFilter->RelativeError(false); m_SpectralUnmixingFilter->SetInput(inputImage); m_SpectralUnmixingFilter->AddOutputs(2); //Set wavelengths to filter for (unsigned int imageIndex = 0; imageIndex < m_inputWavelengths.size(); imageIndex++) { unsigned int wavelength = m_inputWavelengths[imageIndex]; m_SpectralUnmixingFilter->AddWavelength(wavelength); } m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::OXYGENATED); m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::DEOXYGENATED); m_SpectralUnmixingFilter->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::HOUSEHOLDERQR); m_SpectralUnmixingFilter->Update(); for (int i = 0; i < 2; ++i) { mitk::Image::Pointer output = m_SpectralUnmixingFilter->GetOutput(i); mitk::ImageReadAccessor readAccess(output); const float* inputDataArray = ((const float*)readAccess.GetData()); auto pixel = inputDataArray[0]; auto pixel2 = inputDataArray[1]; CPPUNIT_ASSERT(std::abs(pixel - m_CorrectResult[i]) < threshold); CPPUNIT_ASSERT(std::abs(pixel2 - m_CorrectResult[i + 2]) < threshold); // test correct output dimensions and pixel type CPPUNIT_ASSERT(inputImage->GetDimensions()[0] == output->GetDimensions()[0]); CPPUNIT_ASSERT(inputImage->GetDimensions()[0] == output->GetDimensions()[1]); CPPUNIT_ASSERT(2 == output->GetDimensions()[2]); CPPUNIT_ASSERT(output->GetPixelType() != mitk::MakeScalarPixelType()); } } // TEST TEMPLATE: /* // Test exceptions for void test() { MITK_INFO << "TEST"; // Set input image auto m_SpectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New(); m_SpectralUnmixingFilter->Verbose(false); m_SpectralUnmixingFilter->RelativeError(false); m_SpectralUnmixingFilter->SetInput(inputImage); m_SpectralUnmixingFilter->AddOutputs(2); //Set wavelengths to filter for (unsigned int imageIndex = 0; imageIndex < m_inputWavelengths.size(); imageIndex++) { unsigned int wavelength = m_inputWavelengths[imageIndex]; m_SpectralUnmixingFilter->AddWavelength(wavelength); } m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::OXYGENATED); m_SpectralUnmixingFilter->AddChromophore( mitk::pa::PropertyCalculator::ChromophoreType::DEOXYGENATED); m_SpectralUnmixingFilter->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::HOUSEHOLDERQR); //MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ExceptionObject) m_SpectralUnmixingFilter->Update(); //MITK_TEST_FOR_EXCEPTION_END(itk::ExceptionObject) }*/ void tearDown() override { m_SpectralUnmixingFilter = nullptr; inputImage = nullptr; m_inputWavelengths.clear(); m_CorrectResult.clear(); } }; MITK_TEST_SUITE_REGISTRATION(mitkSpectralUnmixing)