Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
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