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
mitkFileSeriesReader.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 "mitkFileSeriesReader.h"
18 #include <itkImageFileReader.h>
19 #include <itksys/Directory.hxx>
20 #include <itksys/SystemTools.hxx>
21 #include <map>
22 
24 {
25  typedef std::vector<std::string> StringContainer;
26  typedef std::map<unsigned int, std::string> SortedStringContainer;
27 
28  if (m_FileName == "")
29  {
30  throw itk::ImageFileReaderException(__FILE__, __LINE__, "FileName must be non-empty");
31  }
32  // MITK_INFO << "FileName: "<< m_FileName <<", FilePrefix: "<< m_FilePrefix << ", FilePattern: "<< m_FilePattern <<
33  // std::endl;
34 
35  // determine begin and end idexes of the last digit sequence in the
36  // filename from the sample file name
37  // Therefore, walk backwards from the end of the filename until
38  // a number is found. The string in front of the number is the prefix,
39  // the string after the number is the extension.
40  std::string basename, path;
41  path = itksys::SystemTools::GetFilenamePath(m_FileName);
42  basename = itksys::SystemTools::GetFilenameName(m_FileName);
43 
44  unsigned int digitBegin = 0;
45  unsigned int digitEnd = 0;
46  bool digitFound = false;
47  for (unsigned int i = basename.length() - 1;; --i)
48  {
49  char character = basename[i];
50  if (character >= '0' && character <= '9')
51  {
52  if (!digitFound)
53  {
54  digitEnd = i;
55  digitBegin = i;
56  digitFound = true;
57  }
58  else
59  digitBegin = i;
60  }
61  else
62  {
63  // end of digit series found, jump out of loop!
64  if (digitFound)
65  break;
66  }
67  if (i == 0)
68  break;
69  }
70 
71  //
72  // if there is no digit in the filename, then we have a problem
73  // no matching filenames can be identified!
74  //
75  if (!digitFound)
76  {
77  itkWarningMacro("Filename contains no digit!");
78  return false;
79  }
80 
81  //
82  // determine prefix and extension start and length
83  //
84  unsigned int prefixBegin = 0;
85  unsigned int prefixLength = digitBegin;
86  unsigned int extensionBegin = digitEnd + 1;
87  unsigned int extensionLength = (digitEnd == basename.length() - 1 ? 0 : basename.length() - 1 - digitEnd);
88  unsigned int numberLength = digitEnd - digitBegin + 1;
89 
90  //
91  // extract prefix and extension
92  //
93  std::string prefix = "";
94  if (prefixLength != 0)
95  prefix = basename.substr(prefixBegin, prefixLength);
96  std::string extension = "";
97  if (extensionLength != 0)
98  extension = basename.substr(extensionBegin, extensionLength);
99 
100  //
101  // print debug information
102  //
103  /*
104  MITK_INFO << "digitBegin : " << digitBegin << std::endl;
105  MITK_INFO << "digitEnd : " << digitEnd << std::endl;
106  MITK_INFO << "number of digits: " << numberLength << std::endl;
107  MITK_INFO << "prefixBegin : " << prefixBegin << std::endl;
108  MITK_INFO << "prefixLength : " << prefixLength << std::endl;
109  MITK_INFO << "prefix : " << prefix << std::endl;
110  MITK_INFO << "extensionBegin : " << extensionBegin << std::endl;
111  MITK_INFO << "extensionLength : " << extensionLength << std::endl;
112  MITK_INFO << "extension : " << extension << std::endl;
113  */
114  if ((prefixLength + extensionLength + numberLength) != basename.length())
115  {
116  throw itk::ImageFileReaderException(
117  __FILE__, __LINE__, "prefixLength + extensionLength + numberLength != basenameLength");
118  }
119 
120  //
121  // Load Directory
122  //
123  std::string directory = itksys::SystemTools::GetFilenamePath(m_FileName);
124  itksys::Directory itkDir;
125  if (!itkDir.Load(directory.c_str()))
126  {
127  itkWarningMacro(<< "Directory " << directory << " cannot be read!");
128  return false;
129  }
130 
131  //
132  // Get a list of all files in the directory
133  //
134  StringContainer unmatchedFiles;
135  // unsigned long i;
136  for (unsigned long i = 0; i < itkDir.GetNumberOfFiles(); i++)
137  {
138  // Only read files
139  std::string filename = directory + "/" + itkDir.GetFile(i);
140  if (itksys::SystemTools::FileIsDirectory(filename.c_str()))
141  continue;
142 
143  // store the filenames without path
144  unmatchedFiles.push_back(itkDir.GetFile(i));
145  }
146 
147  //
148  // Match the file list against the file prefix and extension,
149  // the result should be only the files that should be read
150  //
151  StringContainer matchedFiles;
152  for (auto it = unmatchedFiles.begin(); it != unmatchedFiles.end(); ++it)
153  {
154  bool prefixMatch = false;
155  bool extensionMatch = false;
156 
157  // check if the file prefix matches the current file
158  if (prefixLength != 0)
159  prefixMatch = (it->find(prefix) == prefixBegin); // check if prefix is found
160  else
161  prefixMatch = (((*it)[0] >= '0') && ((*it)[0] <= '9')); // check if filename begins with digit
162 
163  // check if the file extension matches the current file
164  if (extensionLength != 0)
165  extensionMatch = (it->find(extension) == it->length() - extensionLength); // check if prefix is found
166  else
167  extensionMatch =
168  (((*it)[it->length() - 1] >= '0') && ((*it)[it->length() - 1] <= '9')); // check if filename ends with digit
169 
170  if (prefixMatch && extensionMatch)
171  {
172  matchedFiles.push_back(*it);
173  }
174  }
175  if (matchedFiles.size() == 0)
176  {
177  itkWarningMacro(<< "Sorry, none of the files matched the prefix!");
178  return false;
179  }
180 
181  //
182  // parse the file names from back to front for digits
183  // and convert them to a number. Store the filename and number
184  // in a SortedStringContainer
185  //
186  SortedStringContainer sortedFiles;
187  for (auto it = matchedFiles.begin(); it != matchedFiles.end(); ++it)
188  {
189  // parse the filename starting from pos digitBegin until we reach a non-digit
190  // or the end of filename
191  std::string number = "";
192  std::string currentFilename(*it);
193  for (unsigned int i = digitBegin; i < currentFilename.length(); ++i)
194  {
195  char character = currentFilename[i];
196  // do we have a digit?
197  if (character >= '0' && character <= '9')
198  number += character;
199  else
200  break; // end of digit series found, jump out of loop!
201  }
202  if (number.length() == 0)
203  {
204  // The file is not numbered, this is an error!
205  // Nevertheless, we try the next files.
206  itkWarningMacro(<< "The filename " << *it
207  << "does not contain a valid digit sequence but matches prefix and extension. Skipping file!");
208  }
209  else
210  {
211  if ((number.length() + prefix.length() + extension.length()) != it->length())
212  {
213  itkWarningMacro(
214  "The file "
215  << *it
216  << " matches prefix and extension, but the string in beteen is not a single digit-sequence. Skipping file!");
217  }
218  else
219  {
220  // convert the number string into an integer and
221  // insert the filname (including directory) into the SortedStringContainer
222  unsigned int num = atoi(number.c_str());
223  sortedFiles.insert(std::make_pair(num, directory + "/" + *it));
224  }
225  }
226  }
227  if (sortedFiles.size() == 0)
228  {
229  itkWarningMacro(<< "Sorry, no numbered files found, I can't load anything...");
230  return false;
231  }
232 
233  //
234  // Convert the sorted string container in a plain sorted vector of strings;
235  //
236  m_MatchedFileNames.clear();
237  m_MatchedFileNames.resize(sortedFiles.size());
238  unsigned long index = 0;
239  for (auto it = sortedFiles.begin(); it != sortedFiles.end(); ++it, ++index)
240  {
241  m_MatchedFileNames[index] = it->second;
242  MITK_INFO << "Added " << it->second << " to the set of matched files!" << std::endl;
243  }
244  return true;
245 }
246 
247 mitk::FileSeriesReader::MatchedFileNames mitk::FileSeriesReader::GetMatchedFileNames()
248 {
249  return m_MatchedFileNames;
250 }
251 
252 mitk::FileSeriesReader::FileSeriesReader() : m_FileName(""), m_FilePrefix(""), m_FilePattern("")
253 {
254 }
255 
257 {
258 }
virtual mitkClassMacro(FileSeriesReader, FileReader) typedef std MatchedFileNames GetMatchedFileNames()
#define MITK_INFO
Definition: mitkLogMacros.h:22
static const std::string filename
MatchedFileNames m_MatchedFileNames