diff --git a/Modules/PhotoacousticsLib/CMakeLists.txt b/Modules/PhotoacousticsLib/CMakeLists.txt index 4e5d764695..83269bc48d 100644 --- a/Modules/PhotoacousticsLib/CMakeLists.txt +++ b/Modules/PhotoacousticsLib/CMakeLists.txt @@ -1,15 +1,16 @@ MITK_CREATE_MODULE( INCLUDE_DIRS PUBLIC include INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} DEPENDS PUBLIC MitkAlgorithmsExt tinyxml PACKAGE_DEPENDS tinyxml Vigra PUBLIC ITK ) add_subdirectory(MitkMCxyz) add_subdirectory(MitkTissueBatchGenerator) add_subdirectory(MitkPAPhantomGenerator) +add_subdirectory(MitkSpectralUnmixing) add_subdirectory(test) diff --git a/Modules/PhotoacousticsLib/MitkSpectralUnmixing/CMakeLists.txt b/Modules/PhotoacousticsLib/MitkSpectralUnmixing/CMakeLists.txt new file mode 100644 index 0000000000..f2faf72a92 --- /dev/null +++ b/Modules/PhotoacousticsLib/MitkSpectralUnmixing/CMakeLists.txt @@ -0,0 +1,11 @@ +OPTION(BUILD_PhotoacousticSpectralUnmixing "Build MiniApp for batch generating of photoacoustic spectral unmixing" OFF) + +IF(BUILD_PhotoacousticSpectralUnmixing) + PROJECT( MitkSpectralUnmxing ) + mitk_create_executable(SpectralUnmxingApp + DEPENDS MitkCommandLine MitkCore MitkPhotoacousticsLib + PACKAGE_DEPENDS + CPP_FILES SpectralUnmixingApp.cpp) + + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) + ENDIF() diff --git a/Modules/PhotoacousticsLib/MitkSpectralUnmixing/ReadMe.txt b/Modules/PhotoacousticsLib/MitkSpectralUnmixing/ReadMe.txt new file mode 100644 index 0000000000..5c2e7e3d2b --- /dev/null +++ b/Modules/PhotoacousticsLib/MitkSpectralUnmixing/ReadMe.txt @@ -0,0 +1,15 @@ +/** + \spectral unmixing mini App (SUMA) + + \brief The SUMA is designed to enable batch processing for spectral unmixing. To use the SUMA one has to build the MitkSpectralUnmixingApp located in the PAlib. Afterwards a .bat script is available int the suberbuild/MITK-build/bin. This script takes 4 required and one optional parameter: + +Required parameters + -i, --inputFilename, input filename // "E:/mydata/awesome_exp/first_image.nrrd" image has to be an integer multiple of the number of wavelengths + -o, --outputFileStruct, input save name // "E:/mydata/awesome_exp_unmixed/first_image_ctr" will be saved as "_HbO2_SU_.nrrd", "_Hb_SU_.nrrd" and "_sO2_.nrrd"; it is recommended to add an counter (ctr) to the savenames otherwise they will be overwritten. + -l, --inputWavelengths, input wavelengths // (int) 299 < wavelength < 1001 with format: int blank int blank int blank ... + -a, --inputAlg, input algorithm // insert alg: "QR", "NNLS", "WLS", "SVD", "LU" + -w, --inputWeights, input weights (optional) // int weights in % format and order corresponding to the wavelength: int blank int blank ... + +To costumize the SUMA for batch processing of a whole directory, you can either write a script which calls the SUMA for every image again oR insert a loop arround the actual unmixing in the code entering your file structure (see comments inside the code). + +For further questions please contact Niklas Holzwarth (n.holzwarth@dkfz-heidelberg.de or niklas.holzwarth@gmail.com) \ No newline at end of file diff --git a/Modules/PhotoacousticsLib/MitkSpectralUnmixing/SpectralUnmixingApp.cpp b/Modules/PhotoacousticsLib/MitkSpectralUnmixing/SpectralUnmixingApp.cpp new file mode 100644 index 0000000000..e2f5cc4a48 --- /dev/null +++ b/Modules/PhotoacousticsLib/MitkSpectralUnmixing/SpectralUnmixingApp.cpp @@ -0,0 +1,289 @@ +/*=================================================================== + +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 "mitkPALinearSpectralUnmixingFilter.h" +#include "mitkPASpectralUnmixingFilterBase.h" +#include "mitkPASpectralUnmixingFilterVigra.h" +#include "mitkPASpectralUnmixingSO2.h" +#include +#include +#include +#include +#include +#include "mitkPreferenceListReaderOptionsFunctor.h" + + +/* \brief The spectral unmixing mini app (SUMA) is designed to enable batch processing + for spectral unmixing. For detailed documentation look into the header files of the + included spectral unmixing filters.*/ + +struct InputParameters +{ + std::string inputFilename; + std::string outputFileStruct; // "E:/mydata/awesome_exp_unmixed/a" will be saved as "a_HbO2_SU_.nrrd", "a_Hb_SU_.nrrd" and "a_sO2_.nrrd"; + std::string inputAlg; + mitkCommandLineParser::StringContainerType inputWavelengths; + mitkCommandLineParser::StringContainerType inputWeights; +}; + +InputParameters parseInput(int argc, char *argv[]) +{ + MITK_INFO << "Parsing arguments..."; + mitkCommandLineParser parser; + + parser.setCategory("MITK-Photoacoustics"); + parser.setTitle("Mitk Spectral Unmixing App"); + parser.setDescription("Batch processing for spectral unmixing."); + parser.setContributor("Computer Assisted Medical Interventions, DKFZ"); + + parser.setArgumentPrefix("--", "-"); + + parser.beginGroup("Required parameters"); + parser.addArgument("inputFilename", + "i", + mitkCommandLineParser::InputDirectory, + "Input Filename (NAME.nrrd)", + "input filename", + us::Any(), + false); + parser.addArgument("outputFileStruct", + "o", + mitkCommandLineParser::OutputDirectory, + "Input save name (name without ending!)", + "input save name", + us::Any(), + false); + parser.addArgument("inputWavelengths", + "l", + mitkCommandLineParser::StringList, + "Input wavelengths (123 124 125 ... int blank int blank)", + "input wavelengths", + us::Any(), + false); + parser.addArgument("inputAlg", + "a", + mitkCommandLineParser::String, + "Input algorithm (string)", + "input algorithm", + us::Any(), + false); + parser.addArgument("inputWeights", + "w", + mitkCommandLineParser::StringList, + "Input weights (123 124 125 ... int in % blank int in % blank)", + "input weights", + us::Any(), + true); + parser.endGroup(); + + InputParameters input; + + std::map parsedArgs = parser.parseArguments(argc, argv); + if (argc == 0) + exit(-1); + + for (int i = 0; i < argc; ++i) + { + MITK_INFO << argv[i]; + } + + if (parsedArgs.count("inputFilename")) + { + + input.inputFilename = us::any_cast(parsedArgs["inputFilename"]); + } + else + { + MITK_ERROR << "Error: No input file"; + mitkThrow() << "Error: No input file"; + } + + if (parsedArgs.count("outputFileStruct")) + { + input.outputFileStruct = us::any_cast(parsedArgs["outputFileStruct"]); + } + else + { + MITK_ERROR << "Error: No output"; + mitkThrow() << "Error: No output"; + } + + if (parsedArgs.count("inputWavelengths")) + { + input.inputWavelengths = us::any_cast(parsedArgs["inputWavelengths"]); + } + else + { + MITK_ERROR << "Error: No wavelengths"; + mitkThrow() << "Error: No wavelengths"; + } + if (parsedArgs.count("inputAlg")) + { + input.inputAlg = us::any_cast(parsedArgs["inputAlg"]); + } + else + { + MITK_ERROR << "Error: No algorithm"; + mitkThrow() << "Error: No algorithm"; + } + + if (parsedArgs.count("inputWeights")) + { + input.inputWeights = us::any_cast(parsedArgs["inputWeights"]); + } + + MITK_INFO << "Parsing arguments...[Done]"; + return input; +} + +// Class takes string and sets algorithm for spectral unmixing in the corresponding filter class +mitk::pa::SpectralUnmixingFilterBase::Pointer GetFilterInstance(std::string algorithm, std::vector weights = std::vector()) +{ + mitk::pa::SpectralUnmixingFilterBase::Pointer spectralUnmixingFilter; + + if (algorithm == "QR") + { + spectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New(); + dynamic_cast(spectralUnmixingFilter.GetPointer()) + ->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::HOUSEHOLDERQR); + } + + else if (algorithm == "SVD") + { + spectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New(); + dynamic_cast(spectralUnmixingFilter.GetPointer()) + ->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::JACOBISVD); + } + + else if (algorithm == "LU") + { + spectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New(); + dynamic_cast(spectralUnmixingFilter.GetPointer()) + ->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::FULLPIVLU); + } + + else if (algorithm == "NNLS") + { + spectralUnmixingFilter = mitk::pa::SpectralUnmixingFilterVigra::New(); + dynamic_cast(spectralUnmixingFilter.GetPointer()) + ->SetAlgorithm(mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType::LARS); + } + + else if (algorithm == "WLS") + { + spectralUnmixingFilter = mitk::pa::SpectralUnmixingFilterVigra::New(); + dynamic_cast(spectralUnmixingFilter.GetPointer()) + ->SetAlgorithm(mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType::WEIGHTED); + + std::vector weightVec = weights; + + for (unsigned int i = 0; i < weightVec.size(); ++i) + { + dynamic_cast(spectralUnmixingFilter.GetPointer()) + ->AddWeight(weightVec[i]); + } + } + return spectralUnmixingFilter; +} + +int main(int argc, char *argv[]) +{ + auto input = parseInput(argc, argv); + + std::string algo = input.inputAlg; + std::string outputDir = input.outputFileStruct; + auto inputWls = input.inputWavelengths; + + std::vector wavelengths; + for (unsigned int s = 0; s < inputWls.size(); ++s) + { + int wl = std::stoi(inputWls[s]); + wavelengths.push_back(wl); + MITK_INFO << "Wavelength: " << wl << "\n"; + } + + mitk::pa::SpectralUnmixingFilterBase::Pointer m_SpectralUnmixingFilter; + + if (algo == "WLS") + { + auto inputW = input.inputWeights; + + std::vector Weights; + for (unsigned int s = 0; s < inputW.size(); ++s) + { + int w = std::stoi(inputW[s]); + Weights.push_back(w); + MITK_INFO << "Weights: " << w << "\n"; + } + + m_SpectralUnmixingFilter = GetFilterInstance(algo, Weights); + } + else + { + m_SpectralUnmixingFilter = GetFilterInstance(algo); + } + + m_SpectralUnmixingFilter->Verbose(false); + m_SpectralUnmixingFilter->RelativeError(false); + m_SpectralUnmixingFilter->AddChromophore(mitk::pa::PropertyCalculator::ChromophoreType::OXYGENATED); + m_SpectralUnmixingFilter->AddChromophore(mitk::pa::PropertyCalculator::ChromophoreType::DEOXYGENATED); + m_SpectralUnmixingFilter->AddOutputs(2); + + for (unsigned int wIdx = 0; wIdx < wavelengths.size(); ++wIdx) + { + m_SpectralUnmixingFilter->AddWavelength(wavelengths[wIdx]); + MITK_INFO << wavelengths[wIdx]; + } + + //to add a batch processing: loop for a dir start here; don't forget to set a counter to the three output savenames!!! + std::string inputImage = input.inputFilename; + auto m_inputImage = mitk::IOUtil::Load(inputImage); + + m_SpectralUnmixingFilter->SetInput(m_inputImage); + + m_SpectralUnmixingFilter->Update(); + + auto output1 = m_SpectralUnmixingFilter->GetOutput(0); + auto output2 = m_SpectralUnmixingFilter->GetOutput(1); + output1->SetSpacing(m_inputImage->GetGeometry()->GetSpacing()); + output2->SetSpacing(m_inputImage->GetGeometry()->GetSpacing()); + + std::string unmixingOutputHbO2 = outputDir + "_HbO2_SU_.nrrd"; + std::string unmixingOutputHb = outputDir + "_Hb_SU_.nrrd"; + mitk::IOUtil::Save(output1, unmixingOutputHbO2); + mitk::IOUtil::Save(output2, unmixingOutputHb); + + auto m_sO2 = mitk::pa::SpectralUnmixingSO2::New(); + m_sO2->Verbose(false); + + m_sO2->SetInput(0, output1); + m_sO2->SetInput(1, output2); + + m_sO2->Update(); + + mitk::Image::Pointer sO2 = m_sO2->GetOutput(0); + sO2->SetSpacing(m_inputImage->GetGeometry()->GetSpacing()); + + std::string outputSo2 = outputDir + "_sO2_.nrrd"; + mitk::IOUtil::Save(sO2, outputSo2); + + m_sO2 = nullptr; + m_SpectralUnmixingFilter = nullptr; + //to add a batch processing: loop for a dir end here + MITK_INFO << "Spectral Unmixing DONE"; +} diff --git a/Modules/PhotoacousticsLib/MitkSpectralUnmixing/SpectralUnmixingAppTimeEval.cpp b/Modules/PhotoacousticsLib/MitkSpectralUnmixing/SpectralUnmixingAppTimeEval.cpp new file mode 100644 index 0000000000..433a883b2b --- /dev/null +++ b/Modules/PhotoacousticsLib/MitkSpectralUnmixing/SpectralUnmixingAppTimeEval.cpp @@ -0,0 +1,329 @@ +/*=================================================================== + +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 "mitkPALinearSpectralUnmixingFilter.h" +#include "mitkPASpectralUnmixingFilterBase.h" +#include "mitkPASpectralUnmixingFilterVigra.h" +#include "mitkPASpectralUnmixingSO2.h" + +#include +#include +#include +#include + +#include + + +#include "mitkPreferenceListReaderOptionsFunctor.h" + + +struct InputParameters +{ + std::string inputPath; + std::string outputPath; + int numberOfInputs; +}; + +InputParameters parseInput(int argc, char *argv[]) +{ + MITK_INFO << "Parsing arguments..."; + mitkCommandLineParser parser; + + parser.setCategory("MITK-Photoacoustics"); + parser.setTitle("Mitk Spectral Unmixing App"); + parser.setDescription("Batch processing for spectral unmixing."); + parser.setContributor("Computer Assisted Medical Interventions, DKFZ"); + + parser.setArgumentPrefix("--", "-"); + + parser.beginGroup("Required parameters"); + parser.addArgument("inputPath", + "i", + mitkCommandLineParser::InputDirectory, + "Input folder (directory)", + "input folder", + us::Any(), + false); + parser.addArgument("outputPath", + "o", + mitkCommandLineParser::OutputDirectory, + "Input save folder (directory)", + "input save folder", + us::Any(), + false); + parser.addArgument("numberOfInputs", + "n", + mitkCommandLineParser::Int, + "Number of Input files", + "number of inputs", + us::Any(), + false); + parser.endGroup(); + + + InputParameters input; + + + std::map parsedArgs = parser.parseArguments(argc, argv); + if (argc == 0) + exit(-1); + + for (int i = 0; i < argc; ++i) + { + MITK_INFO << argv[i]; + } + + if (parsedArgs.count("inputPath")) + { + input.inputPath = us::any_cast(parsedArgs["inputPath"]); + } + else + { + MITK_ERROR << "Error: No inputPath"; + mitkThrow() << "Error: No inputPath"; + } + + if (parsedArgs.count("outputPath")) + { + input.outputPath = us::any_cast(parsedArgs["outputPath"]); + } + else + { + MITK_ERROR << "Error: No outputPath"; + mitkThrow() << "Error: No outputPath"; + } + if (parsedArgs.count("numberOfInputs")) + { + input.numberOfInputs = us::any_cast(parsedArgs["numberOfInputs"]); + } + else + { + MITK_ERROR << "Error: No number of Inputs"; + mitkThrow() << "Error: No number of Inputs"; + } + MITK_INFO << "Parsing arguments...[Done]"; + return input; +} + + +mitk::pa::SpectralUnmixingFilterBase::Pointer GetFilterInstance(std::string algorithm) +{ + mitk::pa::SpectralUnmixingFilterBase::Pointer spectralUnmixingFilter; + + if (algorithm == "QR") + { + spectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New(); + dynamic_cast(spectralUnmixingFilter.GetPointer()) + ->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::HOUSEHOLDERQR); + } + + else if (algorithm == "SVD") + { + spectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New(); + dynamic_cast(spectralUnmixingFilter.GetPointer()) + ->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::JACOBISVD); + } + + else if (algorithm == "LU") + { + spectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New(); + dynamic_cast(spectralUnmixingFilter.GetPointer()) + ->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::FULLPIVLU); + } + + else if (algorithm == "NNLS") + { + spectralUnmixingFilter = mitk::pa::SpectralUnmixingFilterVigra::New(); + dynamic_cast(spectralUnmixingFilter.GetPointer()) + ->SetAlgorithm(mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType::LARS); + } + + else if (algorithm == "WLS") + { + spectralUnmixingFilter = mitk::pa::SpectralUnmixingFilterVigra::New(); + dynamic_cast(spectralUnmixingFilter.GetPointer()) + ->SetAlgorithm(mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType::WEIGHTED); + + /*std::vector weigthVec = {39, 45, 47}; + + for (int i = 0; i < 3; ++i) + { + dynamic_cast(spectralUnmixingFilter.GetPointer()) + ->AddWeight(weigthVec[i]); + }*/ + } + return spectralUnmixingFilter; +} + +void add_weight(int weights, mitk::pa::SpectralUnmixingFilterBase::Pointer m_SpectralUnmixingFilter) +{ + std::vector weigthVec = { 30, 32, 33, 35, 37, 38, 40, 41, 43, 44, 45, 46, 47, 47, + 47, 47, 47, 46, 46, 45, 44, 44, 43, 42, 42, 41 }; + + for (int i = 0; i < weights; ++i) + { + dynamic_cast(m_SpectralUnmixingFilter.GetPointer()) + ->AddWeight(weigthVec[i]); + } +} + + + +int main(int argc, char *argv[]) +{ + auto input = parseInput(argc, argv); + + std::string inputDir = input.inputPath; + std::string outputDir = input.outputPath; + unsigned int N = input.numberOfInputs; + +/* + //maybee try with "itk system tools" + + //auto test = itksys::SystemTools::GetFilenameName(argv[0]).c_str(); + + //MITK_INFO << "test: " << test; + + + / +++ temporary solution BEGIN +++ + std::vector files; + std::string file; + for (int i = 1; i < 34; ++i) + { + + if (i < 10) + { + file = "E:/NHDATA/sdmas_beamformed/merged/static-oxy_sdmas_00" + std::to_string(i) + "_merged.nrrd"; + } + else + { + file = "E:/NHDATA/sdmas_beamformed/merged/static-oxy_sdmas_0" + std::to_string(i) + "_merged.nrrd"; + } + files.push_back(file); + } + / +++ temporary solution END +++ + + std::vector files; + std::string file; + for (int i = 0; i < 7; ++i) + { + file = "E:/NHCAMI/cami-experimental/PAI/spectralUnmixing/inSilico/paImages/selection/noiselevel1_rep1000_wavelength_selction_data_" + + std::to_string(i) + ".nrrd"; + files.push_back(file); + } + std::vector files; + std::string file; + file = "E:/NHCAMI/cami-experimental/PAI/spectralUnmixing/inSilico/paImages/selection/noiselevel1_rep1000_wavelength_selction_data.nrrd"; + files.push_back(file);*/ + + std::vector algorithms = { "QR", "LU", "SVD", "NNLS", "WLS" }; + int repetition = 6000; + + for (unsigned alg = 0; alg < 5; ++alg) + { + ofstream myerrorfile; + myerrorfile.open("E:/NHDATA/time/time_evaluation_" + std::to_string(repetition)+"_" + algorithms[alg] + "_new02.txt"); + + int ctr = 0; + for(int i = 2; i < 27; ++i) + { + myerrorfile << std::to_string(i) + "\t"; + std::string file; + if (i < 10) + file = "E:/NHDATA/time/input/time_0" + std::to_string(i) + ".nrrd"; + else + file = "E:/NHDATA/time/input/time_" + std::to_string(i) + ".nrrd"; + + auto m_inputImage = mitk::IOUtil::Load(file); + + MITK_INFO << "File: " << i; + + for (int j = 0; j < repetition; ++j) + { + std::chrono::steady_clock::time_point _start; + _start = std::chrono::steady_clock::now(); + + mitk::pa::SpectralUnmixingFilterBase::Pointer m_SpectralUnmixingFilter = GetFilterInstance(algorithms[alg]); + m_SpectralUnmixingFilter->SetInput(m_inputImage); + m_SpectralUnmixingFilter->AddOutputs(2); + m_SpectralUnmixingFilter->Verbose(false); + m_SpectralUnmixingFilter->RelativeError(false); + m_SpectralUnmixingFilter->AddChromophore(mitk::pa::PropertyCalculator::ChromophoreType::OXYGENATED); + m_SpectralUnmixingFilter->AddChromophore(mitk::pa::PropertyCalculator::ChromophoreType::DEOXYGENATED); + + for (int wl = 0; wl < i; ++wl) + { + m_SpectralUnmixingFilter->AddWavelength(700 + wl * 10); + } + + if (alg == 4) + { + add_weight(i, m_SpectralUnmixingFilter); + } + + + m_SpectralUnmixingFilter->Update(); + + auto output1 = m_SpectralUnmixingFilter->GetOutput(0); + auto output2 = m_SpectralUnmixingFilter->GetOutput(1); + + m_SpectralUnmixingFilter = nullptr; + + std::chrono::steady_clock::time_point _end(std::chrono::steady_clock::now()); + myerrorfile << std::chrono::duration_cast>(_end - _start).count() << "\t"; + + /*std::string unmixingOutputHbO2 = "E:/NHDATA/time/output/time_" + std::to_string(i) + ".nrrd"; + std::string unmixingOutputHb = "E:/NHDATA/time/output/time_" + std::to_string(i) + ".nrrd"; + mitk::IOUtil::Save(output1, unmixingOutputHbO2); + mitk::IOUtil::Save(output2, unmixingOutputHb);/* +/* + //auto m_sO2 = mitk::pa::SpectralUnmixingSO2::New(); + //m_sO2->Verbose(false); + //auto output1 = m_SpectralUnmixingFilter->GetOutput(0); + //auto output2 = m_SpectralUnmixingFilter->GetOutput(1); + + + //std::string unmixingOutputHbO2 ="E:/NHDATA/time/input/time_" + std::to_string(i) + ".nrrd"; + //std::string unmixingOutputHb = outputDir + "/SUOutput/" + "Hb_" + algorithms[alg] + "_" + str_ctr + ".nrrd"; + //mitk::IOUtil::Save(output1, unmixingOutputHbO2); + //mitk::IOUtil::Save(output2, unmixingOutputHb); + + //m_sO2->SetInput(0, output1); + //m_sO2->SetInput(1, output2); + + //m_sO2->Update(); + + //mitk::Image::Pointer sO2 = m_sO2->GetOutput(0); + //sO2->SetSpacing(output1->GetGeometry()->GetSpacing()); + + //std::string outputSo2 = outputDir + "/So2/" + algorithms[alg] + "/So2_" + algorithms[alg] + "_" + str_ctr + ".nrrd"; + //std::string outputSo2 = outputDir + "/" + algorithms[alg] + "_sel_" + str_ctr + ".nrrd"; + //std::string outputSo2 = outputDir + "/" + algorithms[alg] + "_sel.nrrd"; + //mitk::IOUtil::Save(sO2, outputSo2); + + //std::string outputSo2 = "E:/NHDATA/time/output/time_" + std::to_string(i) + algorithms[alg] + ".nrrd"; + //mitk::IOUtil::Save(sO2, outputSo2);*/ + } + myerrorfile << "\n"; + } + myerrorfile.close(); + } + MITK_INFO << "Spectral Unmixing DONE"; +} diff --git a/Modules/PhotoacousticsLib/MitkSpectralUnmixing/files.cmake b/Modules/PhotoacousticsLib/MitkSpectralUnmixing/files.cmake new file mode 100644 index 0000000000..a0a3a5cdb3 --- /dev/null +++ b/Modules/PhotoacousticsLib/MitkSpectralUnmixing/files.cmake @@ -0,0 +1,3 @@ +set(CPP_FILES + SpectralUnmixingApp.cpp +) diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.spectralunmixing/src/internal/SpectralUnmixingControls.ui b/Plugins/org.mitk.gui.qt.photoacoustics.spectralunmixing/src/internal/SpectralUnmixingControls.ui index 16095add30..aa90868457 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.spectralunmixing/src/internal/SpectralUnmixingControls.ui +++ b/Plugins/org.mitk.gui.qt.photoacoustics.spectralunmixing/src/internal/SpectralUnmixingControls.ui @@ -1,1232 +1,1232 @@ SpectralUnmixingControls 0 0 325 742 0 0 QmitkTemplate QLabel { color: rgb(255, 0, 0) } Please select an image! Qt::Horizontal 75 true Wavelengths settings 0 75 16777215 75 10 <html><head/><body><p>* \brief All values have to be intergers. They need to have the same order than the wavelength at the image.</p></body></html> true Qt::SolidLine 42 50 30 30 λ [nm] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 - 700 + 760 - 710 + 798 - 720 + 858 - 730 + - 740 + - 750 + - 760 + - 770 + - 780 + 790 800 810 820 830 840 850 860 870 880 890 900 910 920 930 940 950 Qt::Horizontal 75 true <html><head/><body><p><span style=" font-weight:400;">* \brief Select as least one Absorber. It's not possible to select more absorbers then wavelengths.</span></p></body></html> Chromophore selection <html><head/><body><p>* \brief One of the main absorbers in near infrared spectrum.</p></body></html> Oxyhemoglobin true true <html><head/><body><p>* \brief One of the main absorbers in near infrared spectrum.</p></body></html> Deoxygenated hemoglobin true true false <html><head/><body><p>* \brief One of the main absorbers in near infrared spectrum.</p></body></html> Melanin <html><head/><body><p>* \brief This endmember will be unmixed with 1 at all wavelgnths.</p></body></html> Static Endmember Qt::Horizontal 75 true <html><head/><body><p><span style=" font-weight:400;">* \brief One needs to choose an spectral unmixing algorithm.</span></p></body></html> Unmixing algorithm true MS Shell Dlg 2 <html><head/><body><p>* \brief For detailed information about the algorithms please have a look at the documentation.</p></body></html> false 21 2147483647 ==CHOSE ALGORITHM== ==QR decomposition== householderQr colPivHouseholderQr fullPivHouseholderQr ==LU decompositon fullPivLu ==Cholesky decompostion== ldlt llt .. ==Least squares== LS jacobiSvd NNLARS NNGoldfarb weighted ==Others== SimplexMax true 0 75 380 81 <html><head/><body><p>* \brief the weights are at the same order as the wavelength</p></body></html> false false Weights [%] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 11 10 9 8 7 7 6 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 Qt::Horizontal 75 true Oxygen saturation <html><head/><body><p>* \brief calculates HbO2/(HbO2+Hb) if De- and oxyhemoglobin are selected.</p></body></html> calculate sO2 false 380 82 <html><head/><body><p>* \brief below threshold calculated sO2 value will set to zero</p></body></html> Threshold HbO2 Hb Sum SO2 % Qt::Horizontal 75 true Additional Settings <html><head/><body><p>* \brief This mode will give additional console outputs for debugging.</p></body></html> Verbose Mode (additional console outputs) false <html><head/><body><p>* \brief This checkbox will start Chrono and takes the time between clicking of the &quot;Perform spectral unmixing&quot; button until the GUI enables again.</p></body></html> Chrono <html><head/><body><p>* \brief Calculates the realtive error between unmixing result and the input image in the L2 norm.</p></body></html> Relative error image 307 70 <html><head/><body><p>* \brief below the threshold calculated relative error will set to zero</p></body></html> Threshold HbO2 Hb Do image processing Perform spectral unmixing Qt::Horizontal Qt::Vertical 17 54