fw4spl
DicomInstance.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/container/DicomInstance.hpp"
8 
9 #include "fwGdcmIO/helper/DicomDataReader.hxx"
10 
11 #include <fwData/Image.hpp>
12 
13 #include <fwMedData/DicomSeries.hpp>
14 #include <fwMedData/ImageSeries.hpp>
15 #include <fwMedData/ModelSeries.hpp>
16 #include <fwMedData/Series.hpp>
17 #include <fwMedData/Study.hpp>
18 
19 #include <gdcmReader.h>
20 #include <gdcmScanner.h>
21 #include <gdcmUIDGenerator.h>
22 
23 namespace fwGdcmIO
24 {
25 namespace container
26 {
27 
28 //------------------------------------------------------------------------------
29 
31  m_isMultiFiles(true),
32  m_SOPClassUID(""),
33  m_logger(nullptr)
34 {
36 }
37 
38 //------------------------------------------------------------------------------
39 
40 DicomInstance::DicomInstance(const ::fwMedData::Series::csptr& series,
41  const ::fwLog::Logger::sptr& logger,
42  bool isMultiFiles) :
43  m_isMultiFiles(isMultiFiles),
44  m_SOPClassUID(""),
45  m_studyInstanceUID(series->getStudy()->getInstanceUID()),
46  m_seriesInstanceUID(series->getInstanceUID()),
47  m_logger(logger)
48 {
49  // Compute SOPClassUID
50  this->computeSOPClassUID(series);
51 
52  // Generate SOPInstanceUIDs
53  this->generateSOPInstanceUIDs(series);
54 
55  // Generate Frame of Reference UID
56  ::gdcm::UIDGenerator uidGenerator;
57  m_frameOfReferenceUID = uidGenerator.Generate();
58 }
59 
60 //------------------------------------------------------------------------------
61 
62 DicomInstance::DicomInstance(const ::fwMedData::DicomSeries::csptr& dicomSeries,
63  const ::fwLog::Logger::sptr& logger) :
64  m_isMultiFiles(dicomSeries->getDicomContainer().size() > 1),
65  m_studyInstanceUID(dicomSeries->getStudy()->getInstanceUID()),
66  m_seriesInstanceUID(dicomSeries->getInstanceUID()),
67  m_logger(logger)
68 {
69  SLM_ASSERT("DicomSeries is not instantiated", dicomSeries);
70 
71  // Get SOPClassUID
72  ::fwMedData::DicomSeries::SOPClassUIDContainerType sopClassUIDContainer = dicomSeries->getSOPClassUIDs();
73  if(!sopClassUIDContainer.empty())
74  {
75  m_SOPClassUID = *(sopClassUIDContainer.begin());
76  }
77 
78  this->readUIDFromDicomSeries(dicomSeries);
79 }
80 
81 //------------------------------------------------------------------------------
82 
84 {
85  m_isMultiFiles = dicomInstance.m_isMultiFiles;
86  m_SOPClassUID = dicomInstance.m_SOPClassUID;
87  m_SOPInstanceUIDContainer = dicomInstance.m_SOPInstanceUIDContainer;
88  m_logger = dicomInstance.m_logger;
89 }
90 
91 //------------------------------------------------------------------------------
92 
94 {
95 }
96 
97 //------------------------------------------------------------------------------
98 
99 void DicomInstance::computeSOPClassUID(const ::fwMedData::Series::csptr& series)
100 {
101  // Retrieve series type
102  ::fwMedData::ImageSeries::csptr imageSeries = ::fwMedData::ImageSeries::dynamicCast(series);
103  ::fwMedData::ModelSeries::csptr modelSeries = ::fwMedData::ModelSeries::dynamicCast(series);
104 
105  // Create result
106  std::string sopClassUID = "";
107 
108  if(imageSeries)
109  {
110  // Retrieve image from series
111  ::fwData::Image::csptr image = imageSeries->getImage();
112 
113  // Compute instance dimension
114  unsigned int dimension =
115  (this->getIsMultiFiles()) ? 2 : static_cast<unsigned int>(image->getNumberOfDimensions());
116 
117  // Define SOP Class UID from the modality
118  ::gdcm::MediaStorage mediaStorage;
119  mediaStorage.GuessFromModality(series->getModality().c_str(), dimension);
120 
121  // Identify the SOPClassUID from a guess
122  if (mediaStorage != ::gdcm::MediaStorage::MS_END && mediaStorage.GetString() != 0)
123  {
124  sopClassUID = mediaStorage.GetString();
125  }
126  // Force SOPClassUID to be CTImageStorage
127  else
128  {
129  sopClassUID = ::gdcm::MediaStorage::GetMSString(::gdcm::MediaStorage::CTImageStorage);
130  }
131  }
132  else if(modelSeries)
133  {
134  sopClassUID = ::gdcm::MediaStorage::GetMSString(::gdcm::MediaStorage::SurfaceSegmentationStorage);
135  }
136 
137  // Update instance information
138  this->setSOPClassUID(sopClassUID);
139 }
140 
141 //------------------------------------------------------------------------------
142 
143 void DicomInstance::generateSOPInstanceUIDs(const ::fwMedData::Series::csptr& series)
144 {
145  // Retrieve ImageSeries
146  ::fwMedData::ImageSeries::csptr imageSeries = ::fwMedData::ImageSeries::dynamicConstCast(series);
147 
148  // Compute number of instances
149  const std::size_t nbInstances = (imageSeries && m_isMultiFiles) ? (imageSeries->getImage()->getSize()[2]) : (1);
150 
151  // Create generator
152  ::gdcm::UIDGenerator uidGenerator;
153 
154  // Generate UIDs
155  for(std::size_t i = 0; i < nbInstances; ++i)
156  {
157  m_SOPInstanceUIDContainer.push_back(uidGenerator.Generate());
158  }
159 }
160 
161 //------------------------------------------------------------------------------
162 
163 void DicomInstance::readUIDFromDicomSeries(const ::fwMedData::DicomSeries::csptr& dicomSeries)
164 {
165  const ::gdcm::Tag SOPInstanceUIDTag = ::gdcm::Tag(0x0008, 0x0018); // SOP Instance UID
166  const ::gdcm::Tag frameOfReferenceUIDTag = ::gdcm::Tag(0x0020, 0x0052); // Frame of Reference UID
167  std::set< ::gdcm::Tag > selectedtags;
168  selectedtags.insert( SOPInstanceUIDTag );
169  selectedtags.insert( frameOfReferenceUIDTag );
170 
171  std::set<std::string> frameOfReferenceUIDContainer;
172  for(const auto& item : dicomSeries->getDicomContainer())
173  {
174  const ::fwMemory::BufferObject::sptr bufferObj = item.second;
175  const ::fwMemory::BufferManager::StreamInfo streamInfo = bufferObj->getStreamInfo();
176  SPTR(std::istream) is = streamInfo.stream;
177 
178  ::gdcm::Reader reader;
179  reader.SetStream(*is);
180  if(!reader.ReadSelectedTags(selectedtags))
181  {
182  FW_RAISE("Unable to read Dicom file '"<< bufferObj->getStreamInfo().fsFile.string() <<"' "<<
183  "(slice: '" << item.first << "')");
184  }
185  const ::gdcm::DataSet& dataset = reader.GetFile().GetDataSet();
186  // SOP Instance UID
187  m_SOPInstanceUIDContainer.push_back(::fwGdcmIO::helper::DicomDataReader::getTagValue<0x0008, 0x0018>(dataset));
188  // Retrieve frame of reference UID
189  frameOfReferenceUIDContainer.insert(::fwGdcmIO::helper::DicomDataReader::getTagValue<0x0020, 0x0052>(dataset));
190  }
191 
192  if(frameOfReferenceUIDContainer.size() == 1)
193  {
194  m_frameOfReferenceUID = *(frameOfReferenceUIDContainer.begin());
195  }
196  else if(frameOfReferenceUIDContainer.size() > 1)
197  {
198  const std::string msg = "The selected DICOM series contain several Frame of Reference.";
199  SLM_WARN_IF(msg, !m_logger);
200  if(m_logger)
201  {
202  m_logger->critical(msg);
203  }
204  }
205  else
206  {
207  const std::string msg = "No Frame of Reference has been found in the selected series.";
208  SLM_WARN_IF(msg, !m_logger);
209  if(m_logger)
210  {
211  m_logger->critical(msg);
212  }
213  }
214 }
215 
216 //------------------------------------------------------------------------------
217 } //namespace container
218 } //namespace fwGdcmIO
void setSOPClassUID(const std::string &SOPClassUID)
Set SOP Class UID.
#define SPTR(_cls_)
#define SLM_TRACE_FUNC()
Trace contextual function signature.
Definition: spyLog.hpp:329
virtual FWGDCMIO_API ~DicomInstance()
Destructor.
This class defines a DICOM SOP instance. It is useful during the whole writing process. This class allows to share data between module writers.
FWGDCMIO_API DicomInstance()
Constructor.
The namespace fwGdcmIO contains reader, writer and helper for dicom data.
void generateSOPInstanceUIDs(const std::shared_ptr< const ::fwMedData::Series > &series)
Generate SOPInstanceUIDs according to series type and dimension.
void computeSOPClassUID(const std::shared_ptr< const ::fwMedData::Series > &series)
Compute SOPClassUID.
bool getIsMultiFiles() const
Get the flag on multi-files state of an image series.
#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
void readUIDFromDicomSeries(const std::shared_ptr< const ::fwMedData::DicomSeries > &dicomSeries)
Extract &#39;SOP Instance UIDs&#39; and &#39;Frame of Reference UID&#39; from a DICOM series.
#define SLM_WARN_IF(message, cond)
Definition: spyLog.hpp:265