Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
SpectralUnmixingApp.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include <chrono>
14 #include <mitkCommon.h>
19 #include <mitkCommandLineParser.h>
20 #include <mitkException.h>
21 #include <mitkIOUtil.h>
22 #include <mitkUIDGenerator.h>
23 #include <itksys/SystemTools.hxx>
25 
26 
27 /* \brief The spectral unmixing mini app (SUMA) is designed to enable batch processing
28  for spectral unmixing. For detailed documentation look into the header files of the
29  included spectral unmixing filters.*/
30 
31 struct InputParameters
32 {
33  std::string inputFilename;
34  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";
35  std::string inputAlg;
36  std::string outputFileNumber;
39 };
40 
41 InputParameters parseInput(int argc, char *argv[])
42 {
43  //MITK_INFO << "Parsing arguments...";
44  mitkCommandLineParser parser;
45 
46  parser.setCategory("MITK-Photoacoustics");
47  parser.setTitle("Mitk Spectral Unmixing App");
48  parser.setDescription("Batch processing for spectral unmixing.");
49  parser.setContributor("Computer Assisted Medical Interventions, DKFZ");
50 
51  parser.setArgumentPrefix("--", "-");
52 
53  parser.beginGroup("Required parameters");
54  parser.addArgument("inputFilename",
55  "i",
57  "Input Filename (NAME.nrrd)",
58  "input filename",
59  us::Any(),
60  false);
61  parser.addArgument("outputFileStruct",
62  "o",
64  "Output save name (name without ending!)",
65  "Output save name",
66  us::Any(),
67  false);
68  parser.addArgument("outputFileNumber",
69  "n",
71  "Output file number",
72  "Output save number",
73  us::Any(),
74  false);
75  parser.addArgument("inputWavelengths",
76  "l",
78  "Input wavelengths (123 124 125 ... int blank int blank)",
79  "input wavelengths",
80  us::Any(),
81  false);
82  parser.addArgument("inputAlg",
83  "a",
85  "Input algorithm (string)",
86  "input algorithm",
87  us::Any(),
88  false);
89  parser.addArgument("inputWeights",
90  "w",
92  "Input weights (123 124 125 ... int in % blank int in % blank)",
93  "input weights",
94  us::Any(),
95  true);
96  parser.endGroup();
97 
98  InputParameters input;
99 
100  std::map<std::string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
101  if (argc == 0)
102  exit(-1);
103 
104  //for (int i = 0; i < argc; ++i)
105  //{
106  // MITK_INFO << argv[i];
107  //}
108 
109 
110  if (parsedArgs.count("inputFilename"))
111  {
112 
113  input.inputFilename = us::any_cast<std::string>(parsedArgs["inputFilename"]);
114  }
115  else
116  {
117  MITK_ERROR << "Error: No input file";
118  mitkThrow() << "Error: No input file";
119  }
120 
121  if (parsedArgs.count("outputFileStruct"))
122  {
123  input.outputFileStruct = us::any_cast<std::string>(parsedArgs["outputFileStruct"]);
124  }
125  else
126  {
127  MITK_ERROR << "Error: No output";
128  mitkThrow() << "Error: No output";
129  }
130 
131  if (parsedArgs.count("outputFileNumber"))
132  {
133  input.outputFileNumber = us::any_cast<std::string>(parsedArgs["outputFileNumber"]);
134  }
135  else
136  {
137  MITK_ERROR << "Error: No output number";
138  mitkThrow() << "Error: No output number";
139  }
140 
141  if (parsedArgs.count("inputWavelengths"))
142  {
143  input.inputWavelengths = us::any_cast<mitkCommandLineParser::StringContainerType>(parsedArgs["inputWavelengths"]);
144  }
145  else
146  {
147  MITK_ERROR << "Error: No wavelengths";
148  mitkThrow() << "Error: No wavelengths";
149  }
150  if (parsedArgs.count("inputAlg"))
151  {
152  input.inputAlg = us::any_cast<std::string>(parsedArgs["inputAlg"]);
153  }
154  else
155  {
156  MITK_ERROR << "Error: No algorithm";
157  mitkThrow() << "Error: No algorithm";
158  }
159 
160  if (parsedArgs.count("inputWeights"))
161  {
162  input.inputWeights = us::any_cast<mitkCommandLineParser::StringContainerType>(parsedArgs["inputWeights"]);
163  }
164 
165  //MITK_INFO << "Parsing arguments...[Done]";
166  return input;
167 }
168 
169 // Class takes string and sets algorithm for spectral unmixing in the corresponding filter class
170 mitk::pa::SpectralUnmixingFilterBase::Pointer GetFilterInstance(std::string algorithm, std::vector<int> weights = std::vector<int>())
171 {
172  mitk::pa::SpectralUnmixingFilterBase::Pointer spectralUnmixingFilter;
173 
174  if (algorithm == "QR")
175  {
176  spectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New();
177  dynamic_cast<mitk::pa::LinearSpectralUnmixingFilter *>(spectralUnmixingFilter.GetPointer())
178  ->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::HOUSEHOLDERQR);
179  }
180 
181  else if (algorithm == "SVD")
182  {
183  spectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New();
184  dynamic_cast<mitk::pa::LinearSpectralUnmixingFilter *>(spectralUnmixingFilter.GetPointer())
185  ->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::JACOBISVD);
186  }
187 
188  else if (algorithm == "LU")
189  {
190  spectralUnmixingFilter = mitk::pa::LinearSpectralUnmixingFilter::New();
191  dynamic_cast<mitk::pa::LinearSpectralUnmixingFilter *>(spectralUnmixingFilter.GetPointer())
192  ->SetAlgorithm(mitk::pa::LinearSpectralUnmixingFilter::AlgortihmType::FULLPIVLU);
193  }
194 
195  else if (algorithm == "NNLS")
196  {
197  spectralUnmixingFilter = mitk::pa::SpectralUnmixingFilterVigra::New();
198  dynamic_cast<mitk::pa::SpectralUnmixingFilterVigra *>(spectralUnmixingFilter.GetPointer())
199  ->SetAlgorithm(mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType::LARS);
200  }
201 
202  else if (algorithm == "WLS")
203  {
204  spectralUnmixingFilter = mitk::pa::SpectralUnmixingFilterVigra::New();
205  dynamic_cast<mitk::pa::SpectralUnmixingFilterVigra *>(spectralUnmixingFilter.GetPointer())
206  ->SetAlgorithm(mitk::pa::SpectralUnmixingFilterVigra::VigraAlgortihmType::WEIGHTED);
207 
208  std::vector<int> weightVec = weights;
209 
210  for (unsigned int i = 0; i < weightVec.size(); ++i)
211  {
212  dynamic_cast<mitk::pa::SpectralUnmixingFilterVigra *>(spectralUnmixingFilter.GetPointer())
213  ->AddWeight(weightVec[i]);
214  }
215  }
216  return spectralUnmixingFilter;
217 }
218 
219 int main(int argc, char *argv[])
220 {
221  auto input = parseInput(argc, argv);
222 
223  std::string algo = input.inputAlg;
224  std::string outputDir = input.outputFileStruct;
225  std::string outputNumber = input.outputFileNumber;
226 
227  auto inputWls = input.inputWavelengths;
228 
229  std::vector<int> wavelengths;
230  for (unsigned int s = 0; s < inputWls.size(); ++s)
231  {
232  int wl = std::stoi(inputWls[s]);
233  wavelengths.push_back(wl);
234  //MITK_INFO << "Wavelength: " << wl << "\n";
235  }
236 
237  mitk::pa::SpectralUnmixingFilterBase::Pointer m_SpectralUnmixingFilter;
238 
239  if (algo == "WLS")
240  {
241  auto inputW = input.inputWeights;
242 
243  std::vector<int> Weights;
244  for (unsigned int s = 0; s < inputW.size(); ++s)
245  {
246  int w = std::stoi(inputW[s]);
247  Weights.push_back(w);
248  //MITK_INFO << "Weights: " << w << "\n";
249  }
250 
251  m_SpectralUnmixingFilter = GetFilterInstance(algo, Weights);
252  }
253  else
254  {
255  m_SpectralUnmixingFilter = GetFilterInstance(algo);
256  }
257 
258  m_SpectralUnmixingFilter->Verbose(false);
259  m_SpectralUnmixingFilter->RelativeError(false);
260  m_SpectralUnmixingFilter->AddChromophore(mitk::pa::PropertyCalculator::ChromophoreType::OXYGENATED);
261  m_SpectralUnmixingFilter->AddChromophore(mitk::pa::PropertyCalculator::ChromophoreType::DEOXYGENATED);
262  m_SpectralUnmixingFilter->AddOutputs(2);
263 
264  for (unsigned int wIdx = 0; wIdx < wavelengths.size(); ++wIdx)
265  {
266  m_SpectralUnmixingFilter->AddWavelength(wavelengths[wIdx]);
267  //MITK_INFO << wavelengths[wIdx];
268  }
269 
270  //to add a batch processing: loop for a dir start here; don't forget to set a counter to the three output savenames!!!
271  std::string inputImage = input.inputFilename;
272  auto m_inputImage = mitk::IOUtil::Load<mitk::Image>(inputImage);
273 
274  m_SpectralUnmixingFilter->SetInput(m_inputImage);
275 
276  m_SpectralUnmixingFilter->Update();
277 
278  auto output1 = m_SpectralUnmixingFilter->GetOutput(0);
279  auto output2 = m_SpectralUnmixingFilter->GetOutput(1);
280  output1->SetSpacing(m_inputImage->GetGeometry()->GetSpacing());
281  output2->SetSpacing(m_inputImage->GetGeometry()->GetSpacing());
282 
283  std::string unmixingOutputHbO2 = outputDir + "HbO2." + outputNumber + ".nrrd";
284  std::string unmixingOutputHb = outputDir + "Hb." + outputNumber + ".nrrd";
285  //mitk::IOUtil::Save(output1, unmixingOutputHbO2);
286  //mitk::IOUtil::Save(output2, unmixingOutputHb);
287 
288  auto m_sO2 = mitk::pa::SpectralUnmixingSO2::New();
289  m_sO2->Verbose(false);
290 
291  m_sO2->SetInput(0, output1);
292  m_sO2->SetInput(1, output2);
293 
294  m_sO2->Update();
295 
296  mitk::Image::Pointer sO2 = m_sO2->GetOutput(0);
297  mitk::Image::Pointer tHb = m_sO2->GetOutput(1);
298  sO2->SetSpacing(m_inputImage->GetGeometry()->GetSpacing());
299  tHb->SetSpacing(m_inputImage->GetGeometry()->GetSpacing());
300 
301  std::string outputSo2 = outputDir + "sO2." + outputNumber + ".nrrd";
302  mitk::IOUtil::Save(sO2, outputSo2);
303 
304  std::string outputTHb = outputDir + "tHb." + outputNumber + ".nrrd";
305  mitk::IOUtil::Save(tHb, outputTHb);
306 
307  m_sO2 = nullptr;
308  m_SpectralUnmixingFilter = nullptr;
309  //to add a batch processing: loop for a dir end here
310  MITK_INFO << "Spectral Unmixing DONE";
311 }
This filter is subclass of the spectral unmixing filter base. All algorithms in this class are based ...
#define MITK_INFO
Definition: mitkLogMacros.h:18
#define MITK_ERROR
Definition: mitkLogMacros.h:20
InputParameters parseInput(int argc, char *argv[])
std::string inputFilename
Definition: MitkMCxyz.cpp:625
void setContributor(std::string contributor)
ValueType * any_cast(Any *operand)
Definition: usAny.h:377
int main(int argc, char *argv[])
void addArgument(const std::string &longarg, const std::string &shortarg, Type type, const std::string &argLabel, const std::string &argHelp=std::string(), const us::Any &defaultValue=us::Any(), bool optional=true, bool ignoreRest=false, bool deprecated=false, mitkCommandLineParser::Channel channel=mitkCommandLineParser::Channel::None)
std::map< std::string, us::Any > parseArguments(const StringContainerType &arguments, bool *ok=nullptr)
This filter is subclass of the spectral unmixing filter base. All algorithms in this class are based ...
#define mitkThrow()
Definition: usAny.h:163
mitk::pa::SpectralUnmixingFilterBase::Pointer GetFilterInstance(std::string algorithm, std::vector< int > weights=std::vector< int >())
void setCategory(std::string category)
void setArgumentPrefix(const std::string &longPrefix, const std::string &shortPrefix)
static void Save(const mitk::BaseData *data, const std::string &path, bool setPathProperty=false)
Save a mitk::BaseData instance.
Definition: mitkIOUtil.cpp:774
std::vector< std::string > StringContainerType
void setTitle(std::string title)
void setDescription(std::string description)
void beginGroup(const std::string &description)