Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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.