Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkDataNodeFactory.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,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 #include <mitkBaseDataIOFactory.h>
18 #include <mitkConfig.h>
19 #include <mitkCoreObjectFactory.h>
20 #include <mitkDataNodeFactory.h>
21 #include <mitkITKImageImport.h>
22 #include <mitkLocaleSwitch.h>
23 
24 // C-Standard library includes
25 #include <locale.h>
26 #include <stdlib.h>
27 
28 // STL-related includes
29 #include <cstdlib>
30 #include <istream>
31 #include <locale>
32 #include <map>
33 #include <vector>
34 
35 // VTK-related includes
36 #include <vtkOBJReader.h>
37 #include <vtkPolyData.h>
38 #include <vtkPolyDataNormals.h>
39 #include <vtkSTLReader.h>
40 
41 #include <vtkDataReader.h>
42 #include <vtkPolyDataReader.h>
43 #include <vtkStructuredPointsReader.h>
44 
45 #include <vtkLookupTable.h>
46 #include <vtkPointData.h>
47 #include <vtkStructuredPoints.h>
48 #include <vtkXMLImageDataReader.h>
49 
50 // ITK-related includes
51 
52 #include <itkGDCMImageIO.h>
53 #include <itkImage.h>
54 #include <itkImageFileReader.h>
55 #include <itkImageIOFactory.h>
56 #include <itkImageIORegion.h>
57 #include <itkImageSeriesReader.h>
58 #include <itkImageSeriesReader.h>
59 #include <itksys/Directory.hxx>
60 #include <itksys/SystemTools.hxx>
61 
62 #ifdef NOMINMAX
63 #define DEF_NOMINMAX
64 #undef NOMINMAX
65 #endif
66 
67 #include <itkGDCMSeriesFileNames.h>
68 
69 #ifdef DEF_NOMINMAX
70 #ifndef NOMINMAX
71 #define NOMINMAX
72 #endif
73 #undef DEF_NOMINMAX
74 #endif
75 
76 #include <itkCommand.h>
77 #include <itkNumericSeriesFileNames.h>
78 
79 // MITK-related includes
80 #include "mitkPointSet.h"
81 #include "mitkProperties.h"
82 #include "mitkStringProperty.h"
83 #include "mitkSurface.h"
84 //#include "mitkMaterialProperty.h"
85 #include "mitkCoreObjectFactory.h"
86 #include "mitkImage.h"
88 #include "mitkImageSliceSelector.h"
90 #include "mitkLookupTable.h"
92 #include "mitkProgressBar.h"
93 #include "mitkPropertyNameHelper.h"
99 #include <mitkDicomSeriesReader.h>
100 
102  false; // default value for texture interpolation if nothing is defined in global options (see QmitkMainTemplate.ui.h)
103 
105 {
106  m_Serie = false;
107  m_OldProgress = 0;
108  this->Modified();
109  // ensure that a CoreObjectFactory has been instantiated
111 }
112 
114 {
115 }
116 
118 {
119  m_Serie = serie;
120 }
121 
123 {
124  // IF filename is something.pic, and something.pic does not exist, try to read something.pic.gz
125  // if there are both, something.pic and something.pic.gz, only the requested file is read
126  // not only for images, but for all formats
127  std::ifstream exists(m_FileName.c_str());
128  if (!exists)
129  {
130  std::string testfilename = m_FileName + ".gz";
131 
132  std::ifstream exists(testfilename.c_str());
133  if (exists.good())
134  {
135  m_FileName += ".gz";
136  }
137  else
138  {
139  testfilename = m_FileName + ".GZ";
140  std::ifstream exists(testfilename.c_str());
141  if (exists.good())
142  {
143  m_FileName += ".GZ";
144  }
145  else
146  {
147  std::string message("File does not exist, or cannot be read. Filename = ");
148  message += m_FileName;
149  MITK_ERROR << message;
150  itkExceptionMacro(<< message.str());
151  }
152  }
153  }
154 
155  // part for DICOM
156  // const char *numbers = "0123456789.";
157  // std::string::size_type first_non_number;
158  // first_non_number = itksys::SystemTools::GetFilenameName(m_FileName).find_first_not_of ( numbers );
159 
160  if (DicomSeriesReader::IsDicom(this->m_FileName) /*|| first_non_number == std::string::npos*/)
161  {
162  this->ReadFileSeriesTypeDCM();
163  }
164  else
165  {
166  bool usedNewDTNF = false;
167 
168  // the mitkBaseDataIO class returns a pointer of a vector of BaseData objects
169  std::vector<mitk::BaseData::Pointer> baseDataVector =
170  mitk::BaseDataIO::LoadBaseDataFromFile(m_FileName, m_FilePrefix, m_FilePattern, m_Serie);
171 
172  if (!baseDataVector.empty())
173  this->ResizeOutputs((unsigned int)baseDataVector.size());
174 
175  for (int i = 0; i < (int)baseDataVector.size(); i++)
176  {
177  mitk::BaseData::Pointer baseData = baseDataVector.at(i);
178 
179  if (baseData.IsNotNull())
180  {
181  usedNewDTNF = true;
183  node->SetData(baseData);
184  this->SetDefaultCommonProperties(node);
185 
186  this->SetOutput(this->MakeNameFromOutputIndex(i), node);
187  }
188  }
189  if (!usedNewDTNF && (m_FileName != "") && !(m_Serie == false))
190  ReadFileSeriesTypeITKImageSeriesReader();
191  }
192 }
193 
194 void mitk::DataNodeFactory::ResizeOutputs(const unsigned int &num)
195 {
196  unsigned int prevNum = this->GetNumberOfOutputs();
197  this->SetNumberOfIndexedOutputs(num);
198  for (unsigned int i = prevNum; i < num; ++i)
199  {
200  this->SetNthOutput(i, this->MakeOutput(i).GetPointer());
201  }
202 }
203 
204 bool mitk::DataNodeFactory::FileNameEndsWith(const std::string &name)
205 {
206  if (m_FileName.size() < name.size())
207  return false;
208 
209  return m_FileName.substr(m_FileName.size() - name.size()) == name;
210 }
211 
212 bool mitk::DataNodeFactory::FilePatternEndsWith(const std::string &name)
213 {
214  return m_FilePattern.find(name) != std::string::npos;
215 }
216 
218 {
219  return itksys::SystemTools::GetFilenameName(m_FileName);
220 }
221 
223 {
224  return itksys::SystemTools::GetFilenameName(m_FilePrefix);
225 }
226 
228 {
229  if (!m_FileName.empty())
230  return itksys::SystemTools::GetFilenamePath(m_FileName);
231  if (!m_FilePrefix.empty())
232  return itksys::SystemTools::GetFilenamePath(m_FilePrefix);
233 
234  return std::string();
235 }
236 
238 {
239  mitk::LocaleSwitch localeSwitch("C");
240  std::locale previousCppLocale(std::cin.getloc());
241  std::locale l("C");
242  std::cin.imbue(l);
243 
244  if (DicomSeriesReader::IsPhilips3DDicom(this->GetFileName()))
245  {
246  MITK_INFO << "it is a Philips3D US Dicom file" << std::endl;
247  this->ResizeOutputs(1);
248  DataNode::Pointer node = this->GetOutput();
250  stringvec.push_back(this->GetFileName());
251  if (DicomSeriesReader::LoadDicomSeries(stringvec, *node))
252  {
253  node->SetName(this->GetBaseFileName());
254  }
255  std::cin.imbue(previousCppLocale);
256  return;
257  }
258 
260  this->GetDirectory(), true, this->m_SeriesRestrictions); // true = group gantry tilt images
261  const unsigned int size = imageBlocks.size();
262 
263  this->ResizeOutputs(size);
266 
267  unsigned int outputIndex = 0u;
268  const DicomSeriesReader::FileNamesGrouping::const_iterator n_end = imageBlocks.end();
269 
270  for (DicomSeriesReader::FileNamesGrouping::const_iterator n_it = imageBlocks.begin(); n_it != n_end; ++n_it)
271  {
272  const std::string &uid = n_it->first;
273  DataNode::Pointer node = this->GetOutput(outputIndex);
274 
275  const DicomSeriesReader::ImageBlockDescriptor &imageBlockDescriptor(n_it->second);
276 
277  MITK_INFO << "--------------------------------------------------------------------------------";
278  MITK_INFO << "DataNodeFactory: Loading DICOM series " << outputIndex << ": Series UID "
279  << imageBlockDescriptor.GetSeriesInstanceUID() << std::endl;
280  MITK_INFO << " " << imageBlockDescriptor.GetFilenames().size() << " '" << imageBlockDescriptor.GetModality()
281  << "' files (" << imageBlockDescriptor.GetSOPClassUIDAsString() << ") loaded into 1 mitk::Image";
282  MITK_INFO << " multi-frame: " << (imageBlockDescriptor.IsMultiFrameImage() ? "Yes" : "No");
284  imageBlockDescriptor.GetReaderImplementationLevel());
285  MITK_INFO << " pixel spacing type: "
287  MITK_INFO << " gantry tilt corrected: " << (imageBlockDescriptor.HasGantryTiltCorrected() ? "Yes" : "No");
288  MITK_INFO << " 3D+t: " << (imageBlockDescriptor.HasMultipleTimePoints() ? "Yes" : "No");
289  MITK_INFO << "--------------------------------------------------------------------------------";
290 
291  if (DicomSeriesReader::LoadDicomSeries(n_it->second.GetFilenames(), *node, true, true, true))
292  {
293  std::string nodeName(uid);
294  std::string studyDescription;
295 
297  0x0008, 0x1030, "dicom.study.StudyDescription", node->GetPropertyList(), studyDescription))
298  {
299  nodeName = studyDescription;
300  std::string seriesDescription;
301 
303  0x0008, 0x103e, "dicom.study.SeriesDescription", node->GetPropertyList(), seriesDescription))
304  {
305  nodeName += "/" + seriesDescription;
306  }
307  }
308 
309  node->SetName(nodeName);
310 
311  ++outputIndex;
312  }
313  else
314  {
315  MITK_ERROR << "DataNodeFactory: Skipping series " << outputIndex << " due to some unspecified error..."
316  << std::endl;
317  }
318 
320  }
321 
322  std::cin.imbue(previousCppLocale);
323 }
324 
326 {
327  typedef itk::Image<int, 3> ImageType;
328  typedef itk::ImageSeriesReader<ImageType> ReaderType;
329 
330  if (!this->GenerateFileList())
331  {
332  itkWarningMacro("Sorry, file list could not be generated!");
333  return;
334  }
335  if (m_MatchedFileNames.size() == 0)
336  {
337  itkWarningMacro("Sorry, no files matched the given filename (" << m_FileName << ")!");
338  return;
339  }
340 
341  //
342  // Finally, initialize the ITK-reader and load the files!
343  //
345  reader->SetFileNames(m_MatchedFileNames);
346  try
347  {
348  reader->Update();
349  ResizeOutputs(reader->GetNumberOfOutputs());
350  for (unsigned int i = 0; i < reader->GetNumberOfOutputs(); ++i)
351  {
352  // Initialize mitk image from itk
354  image->InitializeByItk(reader->GetOutput(i));
355  image->SetVolume(reader->GetOutput(i)->GetBufferPointer());
356 
357  // add the mitk image to the node
358  mitk::DataNode::Pointer node = this->GetOutput(i);
359  node->SetData(image);
360 
362  node->SetProperty("name", nameProp);
363  }
364  }
365  catch (const std::exception &e)
366  {
367  itkWarningMacro(<< e.what());
368  return;
369  }
370 }
371 
373 {
374  static bool initialized = false;
375  static std::map<std::string, std::string> s_ColorMap;
376 
377  if (!initialized)
378  {
379  // all lowercase here, please!
380 
381  s_ColorMap.insert(std::make_pair("ankle", "0xe38686"));
382  s_ColorMap.insert(std::make_pair("appendix", "0xe38686"));
383  s_ColorMap.insert(std::make_pair("blood vessels", "0xff3131"));
384  s_ColorMap.insert(std::make_pair("bronchial tree", "0x3168ff"));
385  s_ColorMap.insert(std::make_pair("bone", "0xd5d5d5"));
386  s_ColorMap.insert(std::make_pair("brain", "0xff9cca"));
387  s_ColorMap.insert(std::make_pair("coccyx", "0xe38686"));
388  s_ColorMap.insert(std::make_pair("colon", "0xe38686"));
389  s_ColorMap.insert(std::make_pair("cyst", "0xe38686"));
390  s_ColorMap.insert(std::make_pair("elbow", "0xe38686"));
391  s_ColorMap.insert(std::make_pair("eye", "0xe38686"));
392  s_ColorMap.insert(std::make_pair("fallopian tube", "0xe38686"));
393  s_ColorMap.insert(std::make_pair("fat", "0xff2bee"));
394  s_ColorMap.insert(std::make_pair("hand", "0xe38686"));
395  s_ColorMap.insert(std::make_pair("gall bladder", "0x567f18"));
396  s_ColorMap.insert(std::make_pair("heart", "0xeb1d32"));
397  s_ColorMap.insert(std::make_pair("hip", "0xe38686"));
398  s_ColorMap.insert(std::make_pair("kidney", "0xd33f00"));
399  s_ColorMap.insert(std::make_pair("knee", "0xe38686"));
400  s_ColorMap.insert(std::make_pair("larynx", "0xe38686"));
401  s_ColorMap.insert(std::make_pair("liver", "0xffcc3d"));
402  s_ColorMap.insert(std::make_pair("lung", "0x6bdcff"));
403  s_ColorMap.insert(std::make_pair("lymph node", "0xff0000"));
404  s_ColorMap.insert(std::make_pair("muscle", "0xff456a"));
405  s_ColorMap.insert(std::make_pair("nerve", "0xffea4f"));
406  s_ColorMap.insert(std::make_pair("nose", "0xe38686"));
407  s_ColorMap.insert(std::make_pair("oesophagus", "0xe38686"));
408  s_ColorMap.insert(std::make_pair("ovaries", "0xe38686"));
409  s_ColorMap.insert(std::make_pair("pancreas", "0xf9ab3d"));
410  s_ColorMap.insert(std::make_pair("pelvis", "0xe38686"));
411  s_ColorMap.insert(std::make_pair("penis", "0xe38686"));
412  s_ColorMap.insert(std::make_pair("pharynx", "0xe38686"));
413  s_ColorMap.insert(std::make_pair("prostate", "0xe38686"));
414  s_ColorMap.insert(std::make_pair("rectum", "0xe38686"));
415  s_ColorMap.insert(std::make_pair("sacrum", "0xe38686"));
416  s_ColorMap.insert(std::make_pair("seminal vesicle", "0xe38686"));
417  s_ColorMap.insert(std::make_pair("shoulder", "0xe38686"));
418  s_ColorMap.insert(std::make_pair("spinal cord", "0xf5f93d"));
419  s_ColorMap.insert(std::make_pair("spleen", "0xf96c3d"));
420  s_ColorMap.insert(std::make_pair("stomach", "0xf96c3d"));
421  s_ColorMap.insert(std::make_pair("teeth", "0xfffcd8"));
422  s_ColorMap.insert(std::make_pair("testicles", "0xe38686"));
423  s_ColorMap.insert(std::make_pair("thyroid", "0xfff694"));
424  s_ColorMap.insert(std::make_pair("tongue", "0xe38686"));
425  s_ColorMap.insert(std::make_pair("tumor", "0x937011"));
426  s_ColorMap.insert(std::make_pair("urethra", "0xf8ff32"));
427  s_ColorMap.insert(std::make_pair("urinary bladder", "0xf8ff32"));
428  s_ColorMap.insert(std::make_pair("uterus", "0xe38686"));
429  s_ColorMap.insert(std::make_pair("vagina", "0xe38686"));
430  s_ColorMap.insert(std::make_pair("vertebra", "0xe38686"));
431  s_ColorMap.insert(std::make_pair("wrist", "0xe38686"));
432  initialized = true;
433  }
434 
435  std::string lowercaseOrgan(organ);
436  for (unsigned int i = 0; i < organ.length(); i++)
437  {
438  lowercaseOrgan[i] = tolower(lowercaseOrgan[i]);
439  }
440 
441  std::map<std::string, std::string>::iterator iter = s_ColorMap.find(lowercaseOrgan);
442  if (iter != s_ColorMap.end())
443  {
444  std::string hexColor = iter->second;
445  std::string hexRed = std::string("0x") + hexColor.substr(2, 2);
446  std::string hexGreen = std::string("0x") + hexColor.substr(4, 2);
447  std::string hexBlue = std::string("0x") + hexColor.substr(6, 2);
448 
449  long int red = strtol(hexRed.c_str(), NULL, 16);
450  long int green = strtol(hexGreen.c_str(), NULL, 16);
451  long int blue = strtol(hexBlue.c_str(), NULL, 16);
452 
453  return ColorProperty::New((float)red / 255.0, (float)green / 255.0, (float)blue / 255.0);
454  }
455  else
456  {
457  // a default color (green)
458  return ColorProperty::New(0.0, 1.0, 0.0);
459  }
460 }
461 
463 {
464  // path
465  mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New(itksys::SystemTools::GetFilenamePath(m_FileName));
466  node->SetProperty(StringProperty::PATH, pathProp);
467 
468  // name already defined?
469  mitk::StringProperty::Pointer nameProp = dynamic_cast<mitk::StringProperty *>(node->GetProperty("name"));
470  if (nameProp.IsNull() || (strcmp(nameProp->GetValue(), "No Name!") == 0))
471  {
472  // name already defined in BaseData
473  mitk::StringProperty::Pointer baseDataNameProp =
474  dynamic_cast<mitk::StringProperty *>(node->GetData()->GetProperty("name").GetPointer());
475  if (baseDataNameProp.IsNull() || (strcmp(baseDataNameProp->GetValue(), "No Name!") == 0))
476  {
477  // name neither defined in node, nor in BaseData -> name = filename
478  if (FileNameEndsWith(".gz"))
479  m_FileName = m_FileName.substr(0, m_FileName.length() - 3);
480 
481  nameProp = mitk::StringProperty::New(itksys::SystemTools::GetFilenameWithoutLastExtension(m_FileName));
482 
483  node->SetProperty("name", nameProp);
484  }
485  else
486  {
487  // name defined in BaseData!
488  nameProp = mitk::StringProperty::New(baseDataNameProp->GetValue());
489  node->SetProperty("name", nameProp);
490  }
491  }
492 
493  // visibility
494  if (!node->GetProperty("visible"))
495  node->SetVisibility(true);
496 }
virtual std::string GetBaseFilePrefix()
void Progress(unsigned int steps=1)
Sets the current amount of progress to current progress + steps.
static ColorProperty::Pointer DefaultColorForOrgan(const std::string &)
itk::SmartPointer< Self > Pointer
StringContainer GetFilenames() const
List of files in this group.
Return type of GetSeries, describes a logical group of files.
bool HasGantryTiltCorrected() const
Whether or not the block contains a gantry tilt which will be "corrected" during loading.
#define MITK_INFO
Definition: mitkLogMacros.h:22
virtual void GenerateData() override
virtual bool FileNameEndsWith(const std::string &name)
#define MITK_ERROR
Definition: mitkLogMacros.h:24
virtual std::string GetBaseFileName()
static Pointer New()
std::vector< std::string > StringContainer
Lists of filenames.
static DataNode::Pointer LoadDicomSeries(const StringContainer &filenames, bool sort=true, bool load4D=true, bool correctGantryTilt=true, UpdateCallBackMethod callback=nullptr, itk::SmartPointer< Image > preLoadedImageBlock=nullptr)
std::string GetModality() const
Series Modality (CT, MR, etc.)
static bool m_TextureInterpolationActive
static std::string ReaderImplementationLevelToString(const ReaderImplementationLevel &enumValue)
static ProgressBar * GetInstance()
static method to get the GUI dependent ProgressBar-instance so the methods for steps to do and progre...
std::string GetSOPClassUIDAsString() const
SOP Class UID as readable string (Computed Tomography Image Storage, Secondary Capture Image Storage...
static std::string PixelSpacingInterpretationToString(const PixelSpacingInterpretation &enumValue)
map::core::discrete::Elements< 3 >::InternalImageType ImageType
void SetImageSerie(bool serie)
Convenience class to temporarily change the current locale.
static Pointer New()
static FileNamesGrouping GetSeries(const std::string &dir, bool groupImagesWithGantryTilt, const StringContainer &restrictions=StringContainer())
see other GetSeries().
virtual void ReadFileSeriesTypeITKImageSeriesReader()
std::string GetSeriesInstanceUID() const
The Series Instance UID.
void SetDefaultCommonProperties(mitk::DataNode::Pointer &node)
virtual void ResizeOutputs(const unsigned int &num)
static bool IsPhilips3DDicom(const std::string &filename)
Checks if a specific file is a Philips3D ultrasound DICOM file.
static const char * PATH
static bool IsDicom(const std::string &filename)
Checks if a specific file contains DICOM data.
static Pointer New()
bool IsMultiFrameImage() const
Multi-frame image(s) or not.
void AddStepsToDo(unsigned int steps)
Adds steps to totalSteps.
static std::vector< mitk::BaseData::Pointer > LoadBaseDataFromFile(const std::string path, const std::string filePrefix, const std::string filePattern, bool series)
ReaderImplementationLevel GetReaderImplementationLevel() const
Confidence of the reader that this block can be read successfully.
virtual bool FilePatternEndsWith(const std::string &name)
virtual std::string GetDirectory()
std::map< std::string, ImageBlockDescriptor > FileNamesGrouping
Property for strings.
PixelSpacingInterpretation GetPixelSpacingType() const
How the mitk::Image spacing can meaningfully be interpreted.
static Pointer New()
bool MITKCORE_EXPORT GetBackwardsCompatibleDICOMProperty(unsigned int group, unsigned int element, std::string const &backwardsCompatiblePropertyName, PropertyList const *propertyList, std::string &propertyValue)
virtual void ReadFileSeriesTypeDCM()
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.