fw4spl
io/fwGdcmIO/src/fwGdcmIO/reader/Series.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2018.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "fwGdcmIO/reader/Series.hpp"
8 
9 #include "fwGdcmIO/helper/DicomDataReader.hxx"
10 #include "fwGdcmIO/reader/iod/ComprehensiveSRIOD.hpp"
11 #include "fwGdcmIO/reader/iod/CTMRImageIOD.hpp"
12 #include "fwGdcmIO/reader/iod/SpatialFiducialsIOD.hpp"
13 #include "fwGdcmIO/reader/iod/SurfaceSegmentationIOD.hpp"
14 
15 #include <fwData/Image.hpp>
16 
17 #include <fwDicomTools/Series.hpp>
18 
19 #include <fwMedData/ImageSeries.hpp>
20 #include <fwMedData/ModelSeries.hpp>
21 #include <fwMedData/SeriesDB.hpp>
22 #include <fwMedData/Study.hpp>
23 
24 #include <boost/algorithm/string/classification.hpp>
25 #include <boost/algorithm/string/split.hpp>
26 #include <boost/make_shared.hpp>
27 
28 #include <gdcmImageReader.h>
29 #include <gdcmScanner.h>
30 
31 namespace fwGdcmIO
32 {
33 namespace reader
34 {
35 
36 //------------------------------------------------------------------------------
37 
39  m_enableBufferRotation(true)
40 {
41 
42 }
43 
44 //------------------------------------------------------------------------------
45 
47 {
49 }
50 
51 // ----------------------------------------------------------------------------
52 
53 ::fwMedData::Series::sptr Series::read(const ::fwMedData::DicomSeries::csptr& dicomSeries)
55 {
56  SLM_ASSERT("DicomSeries should not be null.", dicomSeries);
57  SLM_ASSERT("Logger should not be null.", m_logger);
58 
59  // Create instance
61  std::make_shared< ::fwGdcmIO::container::DicomInstance >(dicomSeries);
62 
63  // Create result
64  ::fwMedData::Series::sptr result;
65 
66  if(!dicomSeries->getDicomContainer().empty())
67  {
68  // Get SOPClassUID
69  ::fwMedData::DicomSeries::SOPClassUIDContainerType sopClassUIDContainer = dicomSeries->getSOPClassUIDs();
70  const std::string sopClassUID = *sopClassUIDContainer.begin();
71 
72  // If the DicomSeries contains an image (ImageSeries)
73  if (::gdcm::MediaStorage::IsImage(::gdcm::MediaStorage::GetMSType(sopClassUID.c_str())) &&
74  ::gdcm::MediaStorage::GetMSType(sopClassUID.c_str()) != ::gdcm::MediaStorage::SpacialFiducialsStorage)
75  {
76  // Read the image
77  ::fwMedData::ImageSeries::sptr imageSeries = ::fwDicomTools::Series::convertToImageSeries(dicomSeries);
78  imageSeries->setDicomReference(dicomSeries);
79  ::fwData::Image::sptr image = ::fwData::Image::New();
80  imageSeries->setImage(image);
81 
82  // Create IOD Reader
83  ::fwGdcmIO::reader::iod::CTMRImageIOD iod(dicomSeries, instance, m_logger,
86 
87  try
88  {
89  iod.read(imageSeries);
90  }
91  catch (const ::fwGdcmIO::exception::Failed& e)
92  {
93  // NOTE : if there is no image, reading is stopped.
94  m_logger->critical(e.what());
95  imageSeries = ::fwMedData::ImageSeries::sptr();
96  }
97 
98  // Set result
99  result = imageSeries;
100  }
101 
102  // Get the RT file names (ModelSeries)
103  else if (::gdcm::MediaStorage::GetMSType(sopClassUID.c_str()) ==
104  ::gdcm::MediaStorage::SurfaceSegmentationStorage)
105  {
106  ::fwMedData::ModelSeries::sptr modelSeries = ::fwDicomTools::Series::convertToModelSeries(dicomSeries);
107  modelSeries->setDicomReference(dicomSeries);
108  // Create IOD Reader
111 
112  try
113  {
114  iod.read(modelSeries);
115  }
116  catch (const ::fwGdcmIO::exception::Failed& e)
117  {
118  // NOTE : if there is no image, reading is stopped.
119  m_logger->critical(e.what());
120  modelSeries = ::fwMedData::ModelSeries::sptr();
121  }
122 
123  // Set result
124  result = modelSeries;
125  }
126  // If the DicomSeries contains a Spatial Fiducials
127  else if (::gdcm::MediaStorage::GetMSType(sopClassUID.c_str()) == ::gdcm::MediaStorage::SpacialFiducialsStorage)
128  {
129  // Retrieve referenced image instance
130  SPTR(::fwGdcmIO::container::DicomInstance) imageInstance =
132 
133  if(imageInstance)
134  {
135  ::fwMedData::ImageSeries::sptr imageSeries =
136  ::fwMedData::ImageSeries::dynamicCast(m_seriesContainerMap[imageInstance]);
137 
138  imageSeries->setDicomReference(dicomSeries);
139 
140  // Create IOD Reader
141  ::fwGdcmIO::reader::iod::SpatialFiducialsIOD iod(dicomSeries, instance, m_logger,
143 
144  try
145  {
146  iod.read(imageSeries);
147  }
148  catch (const ::fwGdcmIO::exception::Failed& e)
149  {
150  //NOTE: no throw for reading error for SR and RT doc
151  m_logger->critical("Spatial Fiducials reading failed: " + std::string(e.what()));
152  }
153  }
154  else
155  {
156  m_logger->critical("The spatial fiducials series \"" + dicomSeries->getInstanceUID() +
157  "\" could not be read as it refers to an unknown series UID.");
158  }
159  }
160  // If the DicomSeries contains a SR
161  else if (::gdcm::MediaStorage::GetMSType(sopClassUID.c_str()) == ::gdcm::MediaStorage::EnhancedSR ||
162  ::gdcm::MediaStorage::GetMSType(sopClassUID.c_str()) == ::gdcm::MediaStorage::ComprehensiveSR ||
163  sopClassUID == "1.2.840.10008.5.1.4.1.1.88.34") // FIXME Replace hard coded string by
164  // "::gdcm::MediaStorage::GetMSType(sopClassUID.c_str())
165  // == ::gdcm::MediaStorage::Comprehensive3DSR"
166  {
167  // Retrieve referenced image instance
168  SPTR(::fwGdcmIO::container::DicomInstance) referencedInstance =
170 
171  ::fwMedData::ImageSeries::sptr imageSeries;
172  const auto& iter = m_seriesContainerMap.find(referencedInstance);
173  if(iter != m_seriesContainerMap.end())
174  {
175  imageSeries = ::fwMedData::ImageSeries::dynamicCast(iter->second);
176  }
177 
178  if(referencedInstance && imageSeries)
179  {
180  imageSeries->setDicomReference(dicomSeries);
181 
182  // Create readers
183  ::fwGdcmIO::reader::iod::ComprehensiveSRIOD iod(dicomSeries, referencedInstance, m_logger,
185 
186  try
187  {
188  iod.read(imageSeries);
189  }
190  catch (const ::fwGdcmIO::exception::Failed& e)
191  {
192  //NOTE: no throw for reading error for SR and RT doc
193  m_logger->critical("Structured Report reading failed: " + std::string(e.what()));
194  }
195  }
196  else
197  {
198  m_logger->critical("The structured report series \"" + dicomSeries->getInstanceUID() +
199  "\" could not be read as it refers to an unknown series UID.");
200  }
201 
202  }
203  else
204  {
205  m_logger->critical("DICOM SOP Class UID \"" + sopClassUID +"\" is not supported by the selected reader.");
206  }
207 
208  }
209 
210  // Store series in instance map
211  if(result)
212  {
213  m_seriesContainerMap[instance] = result;
214  }
215  return result;
216 }
217 
218 //------------------------------------------------------------------------------
219 
221  const ::fwMedData::DicomSeries::csptr& dicomSeries)
222 {
224 
225  // Dicom container
226  ::fwMedData::DicomSeries::DicomContainerType dicomContainer = dicomSeries->getDicomContainer();
227 
228  // Create Reader
229  ::boost::shared_ptr< ::gdcm::Reader > reader =
230  ::boost::shared_ptr< ::gdcm::Reader >( new ::gdcm::Reader );
231  const ::fwMemory::BufferObject::sptr bufferObj = dicomContainer.begin()->second;
232  const ::fwMemory::BufferManager::StreamInfo streamInfo = bufferObj->getStreamInfo();
233  SPTR(std::istream) is = streamInfo.stream;
234  reader->SetStream(*is);
235 
236  // Series Instance UID of the referenced Series
237  std::string seriesInstanceUID = "";
238 
239  if(reader->Read())
240  {
241  // Retrieve dataset
242  const ::gdcm::DataSet& datasetRoot = reader->GetFile().GetDataSet();
243 
244  if(datasetRoot.FindDataElement(::gdcm::Tag(0x0008, 0x1115)))
245  {
246  // Get the content sequence
247  ::gdcm::SmartPointer< ::gdcm::SequenceOfItems > sequence =
248  datasetRoot.GetDataElement(::gdcm::Tag(0x0008, 0x1115)).GetValueAsSQ();
249 
250  if(sequence->GetNumberOfItems() > 0)
251  {
252  ::gdcm::Item referencedSeriesItem = sequence->GetItem(1);
253  const ::gdcm::DataSet& referencedSeriesItemDataset = referencedSeriesItem.GetNestedDataSet();
254 
255  // Series Instance UID - Type 1
256  seriesInstanceUID =
257  ::fwGdcmIO::helper::DicomDataReader::getTagValue< 0x0020, 0x000E >(referencedSeriesItemDataset);
258  }
259  }
260  }
261 
262  if(!seriesInstanceUID.empty())
263  {
264  for(SeriesContainerMapType::value_type v : m_seriesContainerMap)
265  {
266  if(v.first->getSeriesInstanceUID() == seriesInstanceUID)
267  {
268  result = v.first;
269  break;
270  }
271  }
272  }
273 
274  return result;
275 }
276 
277 //------------------------------------------------------------------------------
278 
280  const ::fwMedData::DicomSeries::csptr& dicomSeries)
281 {
282 
284 
285  // Dicom container
286  ::fwMedData::DicomSeries::DicomContainerType dicomContainer = dicomSeries->getDicomContainer();
287 
288  // Create Reader
289  ::boost::shared_ptr< ::gdcm::Reader > reader =
290  ::boost::shared_ptr< ::gdcm::Reader >( new ::gdcm::Reader );
291  const ::fwMemory::BufferObject::sptr bufferObj = dicomContainer.begin()->second;
292  const ::fwMemory::BufferManager::StreamInfo streamInfo = bufferObj->getStreamInfo();
293  SPTR(std::istream) is = streamInfo.stream;
294  reader->SetStream(*is);
295 
296  // Series Instance UID of the referenced Series
297  std::string seriesInstanceUID = "";
298 
299  if(reader->Read())
300  {
301  // Retrieve dataset
302  const ::gdcm::DataSet& datasetRoot = reader->GetFile().GetDataSet();
303 
304  // Pertinent Other Evidence Sequence - Type 1C
305  if(datasetRoot.FindDataElement(::gdcm::Tag(0x0040, 0xa385)))
306  {
307  // Get the content sequence
308  ::gdcm::SmartPointer< ::gdcm::SequenceOfItems > sequence =
309  datasetRoot.GetDataElement(::gdcm::Tag(0x0040, 0xa385)).GetValueAsSQ();
310 
311  if(sequence->GetNumberOfItems() > 0)
312  {
313  ::gdcm::Item studyItem = sequence->GetItem(1);
314  const ::gdcm::DataSet& studyItemDataset = studyItem.GetNestedDataSet();
315 
316  if(studyItemDataset.FindDataElement(::gdcm::Tag(0x0008, 0x1115)))
317  {
318  // Get the series sequence
319  ::gdcm::SmartPointer< ::gdcm::SequenceOfItems > seriesSequence =
320  studyItemDataset.GetDataElement(::gdcm::Tag(0x0008, 0x1115)).GetValueAsSQ();
321 
322  if(seriesSequence->GetNumberOfItems() > 0)
323  {
324  ::gdcm::Item seriesItem = seriesSequence->GetItem(1);
325  const ::gdcm::DataSet& seriesItemDataset = seriesItem.GetNestedDataSet();
326  seriesInstanceUID = ::fwGdcmIO::helper::DicomDataReader::getTagValue< 0x0020, 0x000E >(
327  seriesItemDataset);
328  }
329  }
330 
331  }
332  }
333  }
334 
335  if(!seriesInstanceUID.empty())
336  {
337  for(SeriesContainerMapType::value_type v : m_seriesContainerMap)
338  {
339  if(v.first->getSeriesInstanceUID() == seriesInstanceUID)
340  {
341  result = v.first;
342  break;
343  }
344  }
345  }
346 
347  return result;
348 }
349 //------------------------------------------------------------------------------
350 
351 } // namespace reader
352 } // namespace fwGdcmIO
#define SPTR(_cls_)
static FWDICOMTOOLS_API std::shared_ptr< ::fwMedData::ImageSeries > convertToImageSeries(const std::shared_ptr< const ::fwMedData::DicomSeries > &series)
Convert a DicomSeries to an ImageSeries.
std::shared_ptr< ::fwGdcmIO::container::DicomInstance > getSpatialFiducialsReferencedSeriesInstance(const ::fwMedData::DicomSeries::csptr &dicomSeries)
Get referenced series when dealing with Spatial Fiducials.
#define SLM_TRACE_FUNC()
Trace contextual function signature.
Definition: spyLog.hpp:329
Namespace containing medical data.
This class defines a DICOM SOP instance. It is useful during the whole writing process. This class allows to share data between module writers.
The namespace fwGdcmIO contains reader, writer and helper for dicom data.
std::shared_ptr< ::fwGdcmIO::container::DicomInstance > getStructuredReportReferencedSeriesInstance(const ::fwMedData::DicomSeries::csptr &dicomSeries)
Get referenced series when dealing with Structured Report.
SpatialFiducialsIOD class used to read Spatial Fiducials IODs.
ProgressCallback m_progressCallback
Progress callback for jobs.
Implements a failed exception class for fwGdcmIO.
static FWDICOMTOOLS_API std::shared_ptr< ::fwMedData::ModelSeries > convertToModelSeries(const std::shared_ptr< const ::fwMedData::DicomSeries > &series)
Convert a DicomSeries to a ModelSeries.
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
FWGDCMIO_API void read(::fwMedData::Series::sptr series)
Read a DICOM File.
SurfaceSegmentationIOD class used to read Surface Segmentation IODs.
ComprehensiveSRIOD class used to read landmarks and distances stored in Enhanced Structured Report IO...
FWGDCMIO_API void read(::fwMedData::Series::sptr series)
Read a DICOM File.
FWGDCMIO_API void read(::fwMedData::Series::sptr series)
Read a DICOM File.
FWGDCMIO_API::fwMedData::Series::sptr read(const ::fwMedData::DicomSeries::csptr &dicomSeries)
Read DICOM series.
CTMRImageIOD class used to read CT & MR Image IODs.
FWGDCMIO_API void read(::fwMedData::Series::sptr series)
Read DICOM file.
CancelRequestedCallback m_cancelRequestedCallback
Cancel information for jobs.
SeriesContainerMapType m_seriesContainerMap
Series Container Map.
void setBufferRotationEnabled(bool enabled)
Enable buffer rotation.