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
mitkCollectionReader.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 #pragma warning (disable : 4996)
17 
18 #include "mitkCollectionReader.h"
19 #include <vtkXMLDataElement.h>
20 
21 #include <mitkIOUtil.h>
22 #include <mitkBaseDataIOFactory.h>
23 #include <mitkFiberBundle.h>
25 
26 #include <QDir>
27 
28 //XML StateMachine Tags
29 // Objects
30 const std::string COLLECTION = "col";
31 const std::string SUBCOLLECTION = "subcol";
32 const std::string DATA = "data";
33 const std::string ITEM = "item";
34 // Properties
35 const std::string NAME = "name";
36 const std::string ID = "id";
37 const std::string FILEPATH = "description";
38 const std::string LINK = "link";
39 
40 
41 static std::string GetName(std::string fileName,std::string suffix)
42 {
43  fileName = QFileInfo(QString::fromStdString(fileName)).fileName().toStdString();
44  return fileName.substr(0,fileName.length() -suffix.length()-9); // 8 = date length
45 }
46 
47 static std::string GetDate(std::string fileName,std::string suffix)
48 {
49  fileName = QFileInfo(QString::fromStdString(fileName)).fileName().toStdString();
50  fileName = fileName.substr(fileName.length() - suffix.length()-8,8); // 8 = date length
51  fileName.insert(6,"-");
52  fileName.insert(4,"-");
53  return fileName;
54 }
55 
56 
58  : m_Collection(NULL),
59  m_SubCollection(NULL),
60  m_DataItemCollection(NULL),
61  m_ColIgnore(false), m_ItemIgnore(false)
62 {
63 }
64 
66 {
67  this->Clear();
68 }
69 
70 
75 {
76  QDir fileName = QFileInfo(xmlFileName.c_str()).absoluteDir();
77  m_BaseDir = fileName.path().toStdString() + QDir::separator().toLatin1();
78  this->SetFileName(xmlFileName.c_str());
79  this->Parse();
80  if (m_Collection.IsNotNull())
81  m_Collection->SetXMLFile(xmlFileName);
82  return m_Collection;
83 }
84 
85 void mitk::CollectionReader::AddDataElementIds(std::vector<std::string> dataElemetIds)
86 {
87  m_SelectedDataItemIds.insert( m_SelectedDataItemIds.end(), dataElemetIds.begin(), dataElemetIds.end() );
88 }
89 
90 void mitk::CollectionReader::AddSubColIds(std::vector<std::string> subColIds)
91 {
92  m_SelectedSubColIds.insert( m_SelectedSubColIds.end(), subColIds.begin(), subColIds.end() );
93 }
94 
95 void mitk::CollectionReader::SetDataItemNames(std::vector<std::string> itemNames)
96 {
97  m_SelectedDataItemNames = itemNames;
98 }
99 
101 {
102  m_SelectedDataItemIds.clear();
103 }
104 
106 {
107  m_SelectedSubColIds.clear();
108 }
109 
111 {
112  m_DataItemCollection = NULL;
113  m_SubCollection = NULL;
114  m_Collection = NULL;
115 }
116 
117 mitk::DataCollection::Pointer mitk::CollectionReader::FolderToCollection(std::string folder, std::vector<std::string> suffixes,std::vector<std::string> seriesNames, bool allowGaps)
118 {
119  // Parse folder and look up all data,
120  // after sanitation only fully available groups are included (that is all suffixes are found)
121  FileListType fileList = SanitizeFileList(GenerateFileLists(folder, suffixes, allowGaps));
122 
123  if (fileList.size() <= 0)
124  return NULL;
125 
127  collection->SetName(GetName(fileList.at(0).at(0),suffixes.at(0)));
128 
129  for (unsigned int k=0; k < fileList.at(0).size(); ++k) // all groups have the same amount of items, so looking at 0 is ok.
130  {
132  for (unsigned int i=0; i< suffixes.size(); ++i)
133  {
134  std::string fileName = fileList.at(i).at(k);
135  if (fileName.find(".fib") >= fileName.length())
136  {
137  Image::Pointer image = IOUtil::LoadImage(fileList.at(i).at(k));
138  subCollection->AddData(image.GetPointer(),seriesNames.at(i), fileList.at(i).at(k));
139  }
140  else
141  {
142  const std::string s1="", s2="";
143 
144  std::vector<mitk::BaseData::Pointer> fiber_infile = mitk::BaseDataIO::LoadBaseDataFromFile( fileName, s1, s2, false );
145  if( fiber_infile.empty() )
146  {
147  MITK_INFO << "Fiber bundle could not be read " << fileName ;
148  }
149  mitk::BaseData* fiber_baseData = fiber_infile.at(0);
150  subCollection->AddData(fiber_baseData,seriesNames.at(i), fileList.at(i).at(k));
151  }
152  }
153  std::string sDate = GetDate(fileList.at(0).at(k),suffixes.at(0));
154  collection->AddData(subCollection.GetPointer(),sDate,"--");
155  }
156  return collection;
157 }
158 
159 void mitk::CollectionReader::StartElement(const char* elementName, const char **atts)
160 {
161  std::string name(elementName);
162 
163  if (name == COLLECTION)
164  {
165  m_Collection = DataCollection::New();
166  std::string colName = ReadXMLStringAttribut(NAME, atts);
167  m_Collection->SetName(colName);
168  }
169  else if (name == SUBCOLLECTION)
170  {
171  m_ColIgnore = false;
172  m_ItemIgnore = false;
173 
174  std::string subColName = ReadXMLStringAttribut(NAME, atts);
175  std::string subColId = ReadXMLStringAttribut(ID, atts);
176 
177  if (m_SelectedSubColIds.size() > 0 && std::find(m_SelectedSubColIds.begin(), m_SelectedSubColIds.end(), subColId) == m_SelectedSubColIds.end() )
178  { // a) a selection list is provided AND b) the item is not in the list
179  m_ColIgnore = true;
180  return;
181  }
182 
183  // Create subcollection
184  m_SubCollection = DataCollection::New();
185  m_SubCollection->Init(subColName);
186  }
187  else if (name == DATA)
188  {
189  if (m_ColIgnore)
190  return;
191 
192  std::string dataId = ReadXMLStringAttribut(ID, atts);
193  if (m_SelectedDataItemIds.size() > 0 && std::find(m_SelectedDataItemIds.begin(), m_SelectedDataItemIds.end(), dataId) == m_SelectedDataItemIds.end() )
194  { // a) a selection list is provided AND b) the item is not in the list
195  m_ItemIgnore = true;
196  return;
197  }
198  m_ItemIgnore = false;
199  std::string dataName = ReadXMLStringAttribut(NAME, atts);
200 
201  m_DataItemCollection = DataCollection::New();
202  m_DataItemCollection->Init(dataName);
203  }
204  else if (name == ITEM)
205  {
206  if (m_ColIgnore || m_ItemIgnore)
207  return;
208 
209 
210  std::string relativeItemLink = ReadXMLStringAttribut(LINK, atts);
211  std::string itemLink = m_BaseDir + relativeItemLink;
212  std::string itemName = ReadXMLStringAttribut(NAME, atts);
213 
214  // if item names are provided and name is not in list, do not load it
215  if (m_SelectedDataItemNames.size() != 0 && std::find(m_SelectedDataItemNames.begin(), m_SelectedDataItemNames.end(), itemName) == m_SelectedDataItemNames.end() )
216  return;
217 
218  // Populate Sub-Collection
219  if (itemLink.find(".fib") >= itemLink.length())
220  {
221  Image::Pointer image = IOUtil::LoadImage(itemLink);
222  if (image.IsNotNull())
223  m_DataItemCollection->AddData(image.GetPointer(),itemName,relativeItemLink);
224  else
225  MITK_ERROR << "File could not be loaded: " << itemLink << ". Wihtin Sub-Collection " << m_SubCollection->GetName() << ", within " << m_DataItemCollection->GetName() ;
226  }
227  else
228  {
229  const std::string s1="", s2="";
230 
231  std::vector<mitk::BaseData::Pointer> fiber_infile = mitk::BaseDataIO::LoadBaseDataFromFile( itemLink, s1, s2, false );
232  if( fiber_infile.empty() )
233  {
234  MITK_INFO << "Fiber bundle could not be read " << itemLink ;
235  }
236  mitk::BaseData* fiber_baseData = fiber_infile.at(0);
237  m_DataItemCollection->AddData(fiber_baseData,itemName, relativeItemLink);
238  }
239  }
240  else
241  MITK_WARN<< "Malformed description ? -- unknown tag: " << name;
242 }
243 
244 void mitk::CollectionReader::EndElement(const char* elementName)
245 {
246  std::string name(elementName);
247  if (name == SUBCOLLECTION)
248  {
249  if (m_SubCollection.IsNull())
250  return;
251  if (m_ColIgnore || m_SubCollection->Size() == 0)
252  return;
253 
254  m_Collection->AddData(m_SubCollection.GetPointer(),m_SubCollection->GetName());
255  m_SubCollection = DataCollection::New();
256  }
257  if (name == DATA)
258  {
259  if (m_DataItemCollection.IsNull())
260  return;
261  if (m_DataItemCollection->Size() == 0)
262  return;
263 
264  m_SubCollection->AddData(m_DataItemCollection.GetPointer(),m_DataItemCollection->GetName());
265  m_DataItemCollection = DataCollection::New();
266  }
267 }
268 
269 std::string mitk::CollectionReader::ReadXMLStringAttribut(std::string name, const char** atts)
270 {
271  if (atts)
272  {
273  const char** attsIter = atts;
274 
275  while (*attsIter)
276  {
277  if (name == *attsIter)
278  {
279  attsIter++;
280  return *attsIter;
281  }
282  attsIter++;
283  attsIter++;
284  }
285  }
286  return std::string();
287 }
288 
289 bool mitk::CollectionReader::ReadXMLBooleanAttribut(std::string name, const char** atts)
290 {
291  std::string s = ReadXMLStringAttribut(name, atts);
292  std::transform(s.begin(), s.end(), s.begin(), ::toupper);
293  if (s == "TRUE")
294  return true;
295  else
296  return false;
297 }
298 
299 
300 int mitk::CollectionReader::ReadXMLIntegerAttribut(std::string name, const char** atts)
301 {
302  std::string s = ReadXMLStringAttribut(name, atts);
303  return atoi(s.c_str());
304 }
305 
306 
307 
308 mitk::CollectionReader::FileListType mitk::CollectionReader::GenerateFileLists(std::string folder, std::vector<std::string> suffixes, bool allowGaps)
309 {
310  FileListType fileList;
311  QString qFolder = QString::fromStdString(folder);
312  if (!QFileInfo(qFolder).isDir())
313  {
314  MITK_ERROR << "Folder does not exist.";
315  return fileList;
316  }
317  // Add vector for each suffix
318  for (unsigned int i=0; i< suffixes.size(); ++i)
319  {
320  std::vector<std::string> list;
321  fileList.push_back(list);
322  }
323 
324  // if gaps are allowed, file names are build up from reference file (first suffix)
325  // else all lists a file, file by file with regular sorting of the files,
326  // if one suffix has more/less images than the others loading is aborted
327  if (allowGaps)
328  {
329  QDir parseDir;
330  parseDir.setFilter(QDir::Files);
331  parseDir.setPath(qFolder);
332  QStringList filterMorph;
333  filterMorph << "*" + QString::fromStdString( suffixes.at(0) );
334  parseDir.setNameFilters( filterMorph );
335 
336  QFileInfoList qFileList = parseDir.entryInfoList();
337 
338  // now populate lists with files names, non-existing files will be marked with an empty string
339  for (int i = 0; i < qFileList.size(); ++i)
340  {
341  std::string baseFileName = qFileList.at(i).absoluteFilePath().toStdString();
342  fileList.at(0).push_back( baseFileName );
343 
344  //check for different suffixes
345  for (unsigned int suffNo=1; suffNo < suffixes.size(); ++suffNo)
346  {
347  std::string derivedFileName = baseFileName.substr(0,baseFileName.length() -suffixes.at(0).length()) + suffixes.at(suffNo);
348 
349  // checking if file exists
350  if (QFileInfo(QString::fromStdString(derivedFileName)).isFile())
351  fileList.at(suffNo).push_back(derivedFileName);
352  else
353  fileList.at(suffNo).push_back("");
354  }
355  }
356  }
357  else
358  {
359  int numberOfFiles=-1;
360  for (unsigned int i=0; i< suffixes.size(); ++i)
361  {
362  QDir parseDir;
363  parseDir.setFilter(QDir::Files);
364  parseDir.setPath(qFolder);
365  QStringList filterMorph;
366  filterMorph << "*" + QString::fromStdString( suffixes.at(i) );
367  parseDir.setNameFilters( filterMorph );
368 
369  QFileInfoList qFileList = parseDir.entryInfoList();
370  if (numberOfFiles == -1)
371  numberOfFiles = qFileList.size();
372 
373  if (numberOfFiles != qFileList.size() )
374  {
375  MITK_ERROR << "Series contain different number of images. Loading aborting.";
376  fileList.clear();
377  break;
378  }
379 
380  for (int fileNo=0; fileNo<qFileList.size(); ++fileNo)
381  {
382  fileList.at(i).push_back(qFileList.at(fileNo).absoluteFilePath().toStdString());
383  }
384  }
385  }
386  return fileList;
387 }
388 
390 {
391  std::vector<int> indexRemoval;
392  // Parse through all items and check for empty strings, if one occurs mark this index
393  // for removal.
394  int modalities = list.size();
395  int timeSteps = list.at(0).size();
396  MITK_INFO << "Modalities " << modalities;
397  MITK_INFO << "TimeSteps " << timeSteps;
398  if (timeSteps == 0)
399  MITK_ERROR << "No files found. Fatal.";
400  for (int listIndex = 0 ; listIndex < timeSteps; listIndex++)
401  {
402  for (int modalityIndex = 0 ; modalityIndex < modalities; modalityIndex++)
403  {
404  if (list.at(modalityIndex).at(listIndex) == "")
405  {
406  MITK_INFO << "Marked Index " << listIndex << " for removal.";
407  indexRemoval.push_back(listIndex);
408  break;
409  }
410  }
411  }
412 
413 
414  for (int listIndex = indexRemoval.size()-1 ; listIndex >= 0; --listIndex)
415  {
416  for (int i = 0 ; i < modalities; i++)
417  {
418  list.at(i).erase(list.at(i).begin()+indexRemoval.at(listIndex)) ;
419  }
420  }
421  MITK_INFO << "Time Steps after sanitizing: " << list.at(0).size();
422  return list;
423 }
DataCollection::Pointer LoadCollection(const std::string &xmlFileName)
Build up a mitk::DataCollection from a XML resource.
#define MITK_INFO
Definition: mitkLogMacros.h:22
void SetDataItemNames(std::vector< std::string > itemNames)
const std::string COLLECTION
Base of all data objects.
Definition: mitkBaseData.h:39
static FileListType GenerateFileLists(std::string folder, std::vector< std::string > suffixes, bool allowGaps=false)
GenerateFileLists Returns a collection of lists with valid files names in a folder.
#define MITK_ERROR
Definition: mitkLogMacros.h:24
static FileListType SanitizeFileList(FileListType list)
SanitizeFileList Removes all entries that are lacking at least one modality.
const std::string SUBCOLLECTION
std::vector< std::vector< std::string > > FileListType
#define MITK_WARN
Definition: mitkLogMacros.h:23
void EndElement(const char *elementName)
Derived from XMLReader.
const std::string DATA
const std::string ITEM
const std::string ID
void StartElement(const char *elementName, const char **atts)
Derived from XMLReader.
void AddSubColIds(std::vector< std::string > subColIds)
void AddDataElementIds(std::vector< std::string > dataElemetIds)
static std::vector< mitk::BaseData::Pointer > LoadBaseDataFromFile(const std::string path, const std::string filePrefix, const std::string filePattern, bool series)
static std::string GetDate(std::string fileName, std::string suffix)
const std::string FILEPATH
const std::string NAME
static std::string GetName(std::string fileName, std::string suffix)
static DataCollection::Pointer FolderToCollection(std::string folder, std::vector< std::string > suffixes, std::vector< std::string > seriesNames, bool allowGaps)
Build up a mitk::DataCollection from a folder providing suffixes to group the files.
const std::string LINK
itk::SmartPointer< Self > Pointer
Definition: mitkBaseData.h:42
static mitk::Image::Pointer LoadImage(const std::string &path)
LoadImage Convenience method to load an arbitrary mitkImage.
Definition: mitkIOUtil.cpp:597
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.