DGtal  1.5.beta
ITKDicomReader.ih
1 /**
2  * This program is free software: you can redistribute it and/or modify
3  * it under the terms of the GNU Lesser General Public License as
4  * published by the Free Software Foundation, either version 3 of the
5  * License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program. If not, see <http://www.gnu.org/licenses/>.
14  *
15  **/
16 
17 /**
18  * @file ITKDicomReader.ih
19  * @author Boris Mansencal (\c boris.mansencal@labri.fr )
20  * LaBRI (CNRS, UMR 5800, University of Bordeaux, Bordeaux-INP, France
21  *
22  * @date 2019/02/05
23  *
24  * Header file for module ITKDicomReader.cpp
25  *
26  * This file is part of the DGtal library.
27  */
28 
29 #include "DGtal/images/ConstImageAdapter.h"
30 #include "DGtal/io/readers/ITKReader.h"
31 #if defined(__GNUG__)
32 #pragma GCC diagnostic push
33 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
34 #endif
35 #if defined(__clang__)
36 #pragma clang diagnostic push
37 #pragma clang diagnostic ignored "-Wdocumentation"
38 #endif
39 #include <itkImageSeriesReader.h>
40 #include <itkGDCMImageIO.h>
41 #if defined(__clang__)
42 #pragma clang diagnostic pop
43 #endif
44 #if defined(__GNUG__)
45 #pragma GCC diagnostic pop
46 #endif
47 
48 namespace DGtal {
49 
50  template <typename I>
51  template <typename TFunctor>
52  I ITKDicomReader<I>::importDICOM( const std::vector<std::string> & filenames,
53  const TFunctor & aFunctor )
54  {
55  (void)ITK_IO_IMAGE_EXT; //To avoid compiler "not used" warning
56  //when building only this reader.
57 
58  if ( filenames.empty() )
59  {
60  trace.error() << "[ITKDicomReader] empty filenames vector passed.";
61  throw IOException();
62  }
63 
64  typedef typename Image::Domain Domain;
65  typedef itk::ImageIOBase::IOComponentType IOComponentType;
66  BOOST_CONCEPT_ASSERT( (concepts::CUnaryFunctor<TFunctor, ValueOut, Value>));
67  const IOComponentType componentType =
68  ITKReader<I>::getITKComponentType( filenames[0] );
69  // We suppose all file have the same 'componentType'.
70 
71  switch ( componentType )
72  {
73 
74  default:
75  case itk::ImageIOBase::UNKNOWNCOMPONENTTYPE:
76  {
77  trace.error()
78  << "[ITKDicomReader] Unknown and unsupported component type!";
79  throw IOException();
80  }
81  case itk::ImageIOBase::UCHAR:
82  {
83  typedef ImageContainerByITKImage<Domain, unsigned char> DGtalITKImage;
84  return readDGtalImageFromITKtypes<DGtalITKImage>( filenames, aFunctor );
85  }
86  case itk::ImageIOBase::CHAR:
87  {
88  typedef ImageContainerByITKImage<Domain, char> DGtalITKImage;
89  return readDGtalImageFromITKtypes<DGtalITKImage>( filenames, aFunctor );
90  }
91  case itk::ImageIOBase::USHORT:
92  {
93  typedef ImageContainerByITKImage<Domain, unsigned short> DGtalITKImage;
94  return readDGtalImageFromITKtypes<DGtalITKImage>( filenames, aFunctor );
95  }
96  case itk::ImageIOBase::SHORT:
97  {
98  typedef ImageContainerByITKImage<Domain, short> DGtalITKImage;
99  return readDGtalImageFromITKtypes<DGtalITKImage>( filenames, aFunctor );
100  }
101  case itk::ImageIOBase::UINT:
102  {
103  typedef ImageContainerByITKImage<Domain, unsigned int> DGtalITKImage;
104  return readDGtalImageFromITKtypes<DGtalITKImage>( filenames, aFunctor );
105  }
106  case itk::ImageIOBase::INT:
107  {
108  typedef ImageContainerByITKImage<Domain, int> DGtalITKImage;
109  return readDGtalImageFromITKtypes<DGtalITKImage>( filenames, aFunctor );
110  }
111  case itk::ImageIOBase::ULONG:
112  {
113  typedef ImageContainerByITKImage<Domain, unsigned long> DGtalITKImage;
114  return readDGtalImageFromITKtypes<DGtalITKImage>( filenames, aFunctor );
115  }
116  case itk::ImageIOBase::LONG:
117  {
118  typedef ImageContainerByITKImage<Domain, long> DGtalITKImage;
119  return readDGtalImageFromITKtypes<DGtalITKImage>( filenames, aFunctor );
120  }
121 #if (ITK_VERSION_MAJOR > 4)\
122  || (ITK_VERSION_MAJOR == 4 && ITK_VERSION_MINOR >= 13)
123  case itk::ImageIOBase::ULONGLONG:
124  {
125  typedef ImageContainerByITKImage<Domain, unsigned long long>
126  DGtalITKImage;
127  return readDGtalImageFromITKtypes<DGtalITKImage>( filenames, aFunctor );
128  }
129  case itk::ImageIOBase::LONGLONG:
130  {
131  typedef ImageContainerByITKImage<Domain, long long> DGtalITKImage;
132  return readDGtalImageFromITKtypes<DGtalITKImage>( filenames, aFunctor );
133  }
134 #endif
135  case itk::ImageIOBase::FLOAT:
136  {
137  typedef ImageContainerByITKImage<Domain, float> DGtalITKImage;
138  return readDGtalImageFromITKtypes<DGtalITKImage>( filenames, aFunctor );
139  }
140  case itk::ImageIOBase::DOUBLE:
141  {
142  typedef ImageContainerByITKImage<Domain, double> DGtalITKImage;
143  return readDGtalImageFromITKtypes<DGtalITKImage>( filenames, aFunctor );
144  }
145  }
146  }
147 
148 
149  template <typename I>
150  template <typename Domain, typename PixelType>
151  inline
152  ImageContainerByITKImage<Domain, PixelType>
153  ITKDicomReader<I>::
154  importDicomFiles(const std::vector<std::string> & filenames)
155  {
156  typedef ImageContainerByITKImage<Domain, PixelType> ImageContainer;
157 
158  const unsigned int dimension = Domain::dimension;
159  typedef itk::Image<PixelType, dimension> ItkImage;
160  typedef itk::ImageSeriesReader<ItkImage> ItkReader;
161 
162  //typedef itk::GDCMImageIO ItkImageIO;
163 
164  typedef typename ImageContainer::ITKImagePointer ITKImagePointer;
165  ITKImagePointer itkImage = nullptr;
166 
167  try
168  {
169  typename ItkReader::Pointer reader = ItkReader::New();
170  //ItkImageIO::Pointer dicomIO = ItkImageIO::New();
171  //reader->SetImageIO( dicomIO );
172 
173  reader->SetFileNames( filenames );
174  reader->Update();
175 
176  itkImage = reader->GetOutput();
177  }
178  catch ( itk::ExceptionObject & e )
179  {
180  trace.error() << e;
181  throw IOException();
182  }
183  catch( ... )
184  {
185  trace.error() << "ITKDicomReader: can't read " << filenames.size()
186  << " files"<<std::endl;
187  throw IOException();
188  }
189 
190  const typename ItkImage::SizeType& inputSize =
191  itkImage->GetLargestPossibleRegion().GetSize();
192  const unsigned int width = inputSize[0];
193  const unsigned int height = inputSize[1];
194  const unsigned int depth = inputSize[2];
195  if ( !height || !width || !depth )
196  {
197  trace.error() << "ITKDicomReader: one dimension is null (w=" << width
198  << ", h=" << height << ", d=" << depth << ")" << std::endl;
199  throw IOException();
200  }
201 
202  const ImageContainer image( itkImage );
203 
204  return image;
205  }
206 
207 
208  template <typename I>
209  template <typename Image, typename Domain, typename OrigValue,
210  typename TFunctor, typename Value>
211  Image
212  ITKDicomReader<I>::Aux<Image, Domain, OrigValue, TFunctor, Value>::
213  readDGtalImageFromITKtypes( const std::vector<std::string> & filenames,
214  const TFunctor & aFunctor )
215  {
216  typedef ImageContainerByITKImage<Domain, OrigValue> TypeDGtalImage;
217  TypeDGtalImage dgtalItkImage =
218  importDicomFiles<Domain, OrigValue>( filenames );
219 
220  const Domain& domain = dgtalItkImage.domain();
221 
222  typedef ConstImageAdapter<TypeDGtalImage, Domain, functors::Identity,
223  Value, TFunctor>
224  AdaptedImage;
225  const functors::Identity identityFunctor{};
226  const AdaptedImage adapted( dgtalItkImage, domain, identityFunctor,
227  aFunctor);
228 
229  Image image( domain );
230  std::copy( adapted.constRange().begin(), adapted.constRange().end(),
231  image.range().outputIterator() );
232 
233  return image;
234  }
235 
236 
237 
238  //specialization
239  template <typename I>
240  template <typename Domain, typename OrigValue, typename TFunctor,
241  typename Value>
242  ImageContainerByITKImage<Domain, Value>
243  ITKDicomReader<I>::Aux<ImageContainerByITKImage<Domain, Value>, Domain,
244  OrigValue, TFunctor, Value>::
245  readDGtalImageFromITKtypes( const std::vector<std::string> & filenames,
246  const TFunctor & aFunctor )
247  {
248  typedef ImageContainerByITKImage<Domain, Value> Image;
249 
250  typedef ImageContainerByITKImage<Domain, OrigValue> TypeDGtalImage;
251  TypeDGtalImage dgtalItkImage =
252  importDicomFiles<Domain, OrigValue>( filenames );
253 
254  const Domain& domain = dgtalItkImage.domain();
255 
256  typedef ConstImageAdapter<TypeDGtalImage, Domain, functors::Identity,
257  Value, TFunctor>
258  AdaptedImage;
259  const functors::Identity identityFunctor{};
260  const AdaptedImage adapted( dgtalItkImage, domain, identityFunctor,
261  aFunctor);
262 
263  Image image( domain );
264  std::copy( adapted.constRange().begin(), adapted.constRange().end(),
265  image.range().outputIterator() );
266 
267  //copy ITKImage spatial parameters
268  image.getITKImagePointer()->SetOrigin(
269  dgtalItkImage.getITKImagePointer()->GetOrigin() );
270  image.getITKImagePointer()->SetSpacing(
271  dgtalItkImage.getITKImagePointer()->GetSpacing() );
272  image.getITKImagePointer()->SetDirection(
273  dgtalItkImage.getITKImagePointer()->GetDirection() );
274 
275  return image;
276  }
277 
278 
279  template <typename I>
280  template <typename TypeDGtalImage, typename TFunctor>
281  typename ITKDicomReader<I>::Image ITKDicomReader<I>::
282  readDGtalImageFromITKtypes( const std::vector<std::string> & filenames,
283  const TFunctor & aFunctor )
284  {
285  typedef typename Image::Domain Domain;
286  typedef typename TypeDGtalImage::Value OrigValue;
287 
288  return Aux<Image, Domain, OrigValue, TFunctor, Value>::
289  readDGtalImageFromITKtypes( filenames, aFunctor );
290  }
291 
292 }//namespace