diff --git a/Modules/PhotoacousticsLib/include/mitkPALinearSpectralUnmixingFilter.h b/Modules/PhotoacousticsLib/include/mitkPALinearSpectralUnmixingFilter.h index 62bd48b9e9..d4b9c6d2a0 100644 --- a/Modules/PhotoacousticsLib/include/mitkPALinearSpectralUnmixingFilter.h +++ b/Modules/PhotoacousticsLib/include/mitkPALinearSpectralUnmixingFilter.h @@ -1,65 +1,58 @@ /*=================================================================== 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 { class MITKPHOTOACOUSTICSLIB_EXPORT LinearSpectralUnmixingFilter : public SpectralUnmixingFilterBase { public: mitkClassMacro(LinearSpectralUnmixingFilter, SpectralUnmixingFilterBase) itkFactorylessNewMacro(Self) enum AlgortihmType { householderQr, ldlt, llt, colPivHouseholderQr, jacobiSvd, fullPivLu, fullPivHouseholderQr, test }; void mitk::pa::LinearSpectralUnmixingFilter::SetAlgorithm(AlgortihmType SetAlgorithmIndex); protected: LinearSpectralUnmixingFilter(); virtual ~LinearSpectralUnmixingFilter(); virtual Eigen::VectorXf SpectralUnmixingAlgorithm(Eigen::Matrix EndmemberMatrix, Eigen::VectorXf inputVector) override; private: mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType algorithmIndex; - - int factorial(int n); - virtual Eigen::Matrix GenerateA(Eigen::Matrix EndmemberMatrix, - Eigen::VectorXf inputVector, int i); - Eigen::Matrix GenerateD2(Eigen::Matrix A); - float simplexVolume(Eigen::Matrix Matrix); - }; } } #endif // MITKLINEARPHOTOACOUSTICSPECTRALUNMIXINGFILTER_H diff --git a/Modules/PhotoacousticsLib/include/mitkPASpectralUnmixingFilterSimplex.h b/Modules/PhotoacousticsLib/include/mitkPASpectralUnmixingFilterSimplex.h index fab9a39f54..4bfbc18ef9 100644 --- a/Modules/PhotoacousticsLib/include/mitkPASpectralUnmixingFilterSimplex.h +++ b/Modules/PhotoacousticsLib/include/mitkPASpectralUnmixingFilterSimplex.h @@ -1,53 +1,50 @@ /*=================================================================== 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 MITKPHOTOACOUSTICSPECTRALUNMIXINGFILTERSIMPLEX_H #define MITKPHOTOACOUSTICSPECTRALUNMIXINGFILTERSIMPLEX_H #include #include namespace mitk { namespace pa { class MITKPHOTOACOUSTICSLIB_EXPORT SpectralUnmixingFilterSimplex : public SpectralUnmixingFilterBase { public: mitkClassMacro(SpectralUnmixingFilterSimplex, SpectralUnmixingFilterBase) itkFactorylessNewMacro(Self) protected: SpectralUnmixingFilterSimplex(); virtual ~SpectralUnmixingFilterSimplex(); private: virtual Eigen::VectorXf SpectralUnmixingAlgorithm(Eigen::Matrix EndmemberMatrix, Eigen::VectorXf inputVector) override; - /* int factorial(int n); - + int factorial(int n); virtual Eigen::Matrix GenerateA(Eigen::Matrix EndmemberMatrix, Eigen::VectorXf inputVector, int i); - - Eigen::Matrix GenerateD2(Eigen::Matrix A); - float simplexVolume(Eigen::Matrix Matrix);*/ + float simplexVolume(Eigen::Matrix Matrix); }; } } #endif // MITKPHOTOACOUSTICSPECTRALUNMIXINGFILTERSIMPLEX_H diff --git a/Modules/PhotoacousticsLib/src/SUFilter/mitkPALinearSpectralUnmixingFilter.cpp b/Modules/PhotoacousticsLib/src/SUFilter/mitkPALinearSpectralUnmixingFilter.cpp index e560dc7946..474a05e203 100644 --- a/Modules/PhotoacousticsLib/src/SUFilter/mitkPALinearSpectralUnmixingFilter.cpp +++ b/Modules/PhotoacousticsLib/src/SUFilter/mitkPALinearSpectralUnmixingFilter.cpp @@ -1,193 +1,99 @@ /*=================================================================== 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" // Includes for AddEnmemberMatrix #include "mitkPAPropertyCalculator.h" #include // Testing algorithms #include // ImageAccessor #include #include mitk::pa::LinearSpectralUnmixingFilter::LinearSpectralUnmixingFilter() { } mitk::pa::LinearSpectralUnmixingFilter::~LinearSpectralUnmixingFilter() { } void mitk::pa::LinearSpectralUnmixingFilter::SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType SetAlgorithmIndex) { algorithmIndex = SetAlgorithmIndex; } Eigen::VectorXf mitk::pa::LinearSpectralUnmixingFilter::SpectralUnmixingAlgorithm( Eigen::Matrix EndmemberMatrix, Eigen::VectorXf inputVector) { Eigen::Vector2f resultVector; if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::colPivHouseholderQr == algorithmIndex) resultVector = EndmemberMatrix.colPivHouseholderQr().solve(inputVector); if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::llt == algorithmIndex) resultVector = EndmemberMatrix.llt().solve(inputVector); if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::householderQr == algorithmIndex) resultVector = EndmemberMatrix.householderQr().solve(inputVector); if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::ldlt == algorithmIndex) { mitkThrow() << "algorithm not working"; resultVector = EndmemberMatrix.ldlt().solve(inputVector); //not working because matrix not quadratic(?) } if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::jacobiSvd == algorithmIndex) resultVector = EndmemberMatrix.jacobiSvd(Eigen::ComputeFullU | Eigen::ComputeFullV).solve(inputVector); if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::fullPivLu == algorithmIndex) resultVector = EndmemberMatrix.fullPivLu().solve(inputVector); if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::householderQr == algorithmIndex) resultVector = EndmemberMatrix.householderQr().solve(inputVector); if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::fullPivHouseholderQr == algorithmIndex) resultVector = EndmemberMatrix.fullPivHouseholderQr().solve(inputVector); if (mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::test == algorithmIndex) { - int numberOfChromophores = EndmemberMatrix.cols(); - - float VolumeMax = simplexVolume(EndmemberMatrix); - for (int i = 0; i < numberOfChromophores; ++i) - { - Eigen::Matrix A = GenerateA(EndmemberMatrix, inputVector, i); - float Volume = simplexVolume(A); - //MITK_INFO << "VolumeMax: " << VolumeMax; - //MITK_INFO << "Volume: " << Volume; - //MITK_INFO << "Result vector[i]: " << Volume / VolumeMax; - resultVector[i] = Volume / VolumeMax; - } - //mitkThrow() << "404"; + mitkThrow() << "404"; } /*double relativeError = (EndmemberMatrix*resultVector - inputVector).norm() / inputVector.norm(); // norm() is L2 norm MITK_INFO << "relativ error: " << relativeError; float accuracyLevel = .1; bool resultIsApprox = inputVector.isApprox(EndmemberMatrix*resultVector, accuracyLevel); MITK_INFO << "IS APPROX RESULT: " << resultIsApprox;*/ //MITK_INFO << "Result vector: " << resultVector; return resultVector; } /* look at: https://eigen.tuxfamily.org/dox/classEigen_1_1FullPivLU.html#af563471f6f3283fd10779ef02dd0b748 This method just tries to find as good a solution as possible. If you want to check whether a solution exists or if it is accurate, just call this function to get a result and then compute the error of this result, or use MatrixBase::isApprox() directly, for instance like this: bool a_solution_exists = (A*result).isApprox(b, precision); This method avoids dividing by zero, so that the non-existence of a solution doesn't by itself mean that you'll get inf or nan values. If there exists more than one solution, this method will arbitrarily choose one. If you need a complete analysis of the space of solutions, take the one solution obtained by this method and add to it elements of the kernel, as determined by kernel().*/ - - -Eigen::Matrix mitk::pa::LinearSpectralUnmixingFilter::GenerateA -(Eigen::Matrix EndmemberMatrix, Eigen::VectorXf inputVector, int i) -{ - Eigen::Matrix A = EndmemberMatrix; - int numberOfChromophores = EndmemberMatrix.cols(); - - for (int j = 0; j < numberOfChromophores; ++j) - { - A(i, j) = inputVector(j); - } - - return A; -} - -Eigen::Matrix mitk::pa::LinearSpectralUnmixingFilter::GenerateD2 -(Eigen::Matrix A) -{ - int numberOfChromophores = A.cols(); - - Eigen::Matrix D2(numberOfChromophores, numberOfChromophores); - - for (int i = 0; i < numberOfChromophores; ++i) - { - for (int j = 0; j < numberOfChromophores; ++j) - { - Eigen::VectorXf x = A.col(i) - A.col(j); - //MITK_INFO << "a_col_i: " < Matrix) -{ - float Volume; - int numberOfChromophores = Matrix.cols(); - Eigen::Matrix C(numberOfChromophores + 1, numberOfChromophores + 1); - Eigen::Matrix D2 = GenerateD2(Matrix); - - for (int i = 0; i < numberOfChromophores; ++i) - { - for (int j = 0; j < numberOfChromophores; ++j) - { - C(i, j) = D2(i, j); - } - C(i, numberOfChromophores) = 1; - for (int k = 0; k < numberOfChromophores; ++k) - { - C(numberOfChromophores, k) = 1; - } - C(numberOfChromophores, numberOfChromophores) = 0; - } - - float detC = -C.determinant();// determinate von C - float denominator = (factorial(numberOfChromophores - 1)) ^ 2 * 2 ^ (numberOfChromophores - 1)*(-1) ^ numberOfChromophores; - Volume = std::sqrt(detC / denominator); - //MITK_INFO << "detC: " << detC; - - //MITK_INFO << "denominator: " << denominator; - - //MITK_INFO << "Volume: " << Volume; - - return Volume; -} - -int mitk::pa::LinearSpectralUnmixingFilter::factorial(int n) -{ - if (n == 1) - return 1; - else - return n * factorial(n - 1); -} diff --git a/Modules/PhotoacousticsLib/src/SUFilter/mitkPASpectralUnmixingFilterSimplex.cpp b/Modules/PhotoacousticsLib/src/SUFilter/mitkPASpectralUnmixingFilterSimplex.cpp index 584d29ff22..26781d4b57 100644 --- a/Modules/PhotoacousticsLib/src/SUFilter/mitkPASpectralUnmixingFilterSimplex.cpp +++ b/Modules/PhotoacousticsLib/src/SUFilter/mitkPASpectralUnmixingFilterSimplex.cpp @@ -1,41 +1,138 @@ /*=================================================================== 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 // Includes for AddEnmemberMatrix #include #include mitk::pa::SpectralUnmixingFilterSimplex::SpectralUnmixingFilterSimplex() { } mitk::pa::SpectralUnmixingFilterSimplex::~SpectralUnmixingFilterSimplex() { } Eigen::VectorXf mitk::pa::SpectralUnmixingFilterSimplex::SpectralUnmixingAlgorithm( Eigen::Matrix EndmemberMatrix, Eigen::VectorXf inputVector) { int numberOfChromophores = EndmemberMatrix.cols(); + Eigen::VectorXf resultVector(numberOfChromophores); + + + float VolumeMax = simplexVolume(EndmemberMatrix); + for (int i = 0; i < numberOfChromophores; ++i) + { + Eigen::Matrix A = GenerateA(EndmemberMatrix, inputVector, i); + float Volume = simplexVolume(A); + //MITK_INFO << "VolumeMax: " << VolumeMax; + //MITK_INFO << "Volume: " << Volume; + //MITK_INFO << "Result vector[i]: " << Volume / VolumeMax; + resultVector[i] = Volume / VolumeMax; + } + // + return resultVector; // see code @ linearSUFilter } + + +Eigen::Matrix mitk::pa::SpectralUnmixingFilterSimplex::GenerateA +(Eigen::Matrix EndmemberMatrix, Eigen::VectorXf inputVector, int i) +{ + Eigen::Matrix A = EndmemberMatrix; + int numberOfChromophores = EndmemberMatrix.cols(); + + for (int j = 0; j < numberOfChromophores; ++j) + { + A(i, j) = inputVector(j); + } + + return A; +} + +Eigen::Matrix mitk::pa::SpectralUnmixingFilterSimplex::GenerateD2 +(Eigen::Matrix A) +{ + int numberOfChromophores = A.cols(); + + Eigen::Matrix D2(numberOfChromophores, numberOfChromophores); + + for (int i = 0; i < numberOfChromophores; ++i) + { + for (int j = 0; j < numberOfChromophores; ++j) + { + Eigen::VectorXf x = A.col(i) - A.col(j); + //MITK_INFO << "a_col_i: " < Matrix) +{ + float Volume; + int numberOfChromophores = Matrix.cols(); + Eigen::Matrix C(numberOfChromophores + 1, numberOfChromophores + 1); + Eigen::Matrix D2 = GenerateD2(Matrix); + + for (int i = 0; i < numberOfChromophores; ++i) + { + for (int j = 0; j < numberOfChromophores; ++j) + { + C(i, j) = D2(i, j); + } + C(i, numberOfChromophores) = 1; + for (int k = 0; k < numberOfChromophores; ++k) + { + C(numberOfChromophores, k) = 1; + } + C(numberOfChromophores, numberOfChromophores) = 0; + } + + float detC = -C.determinant();// determinate von C + float denominator = (factorial(numberOfChromophores - 1)) ^ 2 * 2 ^ (numberOfChromophores - 1)*(-1) ^ numberOfChromophores; + Volume = std::sqrt(detC / denominator); + //MITK_INFO << "detC: " << detC; + + //MITK_INFO << "denominator: " << denominator; + + //MITK_INFO << "Volume: " << Volume; + + return Volume; +} + +int mitk::pa::SpectralUnmixingFilterSimplex::factorial(int n) +{ + if (n == 1) + return 1; + else + return n * factorial(n - 1); +}