fw4spl
ImageSeriesWriter.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 "vtkGdcmIO/ImageSeriesWriter.hpp"
8 
9 #include <fwCore/base.hpp>
10 
11 #include <fwDataIO/writer/registry/macros.hpp>
12 
13 #include <fwJobs/IJob.hpp>
14 #include <fwJobs/Observer.hpp>
15 
16 #include <fwMedData/Equipment.hpp>
17 #include <fwMedData/ImageSeries.hpp>
18 #include <fwMedData/Patient.hpp>
19 #include <fwMedData/Study.hpp>
20 
21 #include <fwTools/dateAndTime.hpp>
22 #include <fwTools/Dispatcher.hpp>
23 #include <fwTools/DynamicTypeKeyTypeMapping.hpp>
24 #include <fwTools/IntrinsicTypes.hpp>
25 
26 #include <fwVtkIO/helper/vtkLambdaCommand.hpp>
27 #include <fwVtkIO/vtk.hpp>
28 
29 #include <boost/filesystem.hpp>
30 
31 #include <gdcmDicts.h>
32 #include <gdcmFilenameGenerator.h>
33 #include <gdcmGlobal.h>
34 #include <time.h>
35 #include <vtkGDCMImageWriter.h>
36 #include <vtkImageData.h>
37 #include <vtkMedicalImageProperties.h>
38 #include <vtkSmartPointer.h>
39 #include <vtkStringArray.h>
40 
41 #include <iostream>
42 
43 fwDataIOWriterRegisterMacro( ::vtkGdcmIO::ImageSeriesWriter );
44 
45 namespace vtkGdcmIO
46 {
47 
48 //------------------------------------------------------------------------------
49 
50 void setValue(vtkMedicalImageProperties* medprop,
51  const std::uint16_t group,
52  const std::uint16_t element,
53  const std::string& value)
54 {
55  const gdcm::Global& g = gdcm::Global::GetInstance();
56  const gdcm::Dicts& ds = g.GetDicts();
57 
58  const gdcm::Tag tag(group, element);
59  const gdcm::DictEntry& dicEntry = ds.GetDictEntry( tag );
60  medprop->AddUserDefinedValue( dicEntry.GetName(), value.c_str() );
61 }
62 
63 //------------------------------------------------------------------------------
64 
66  ::fwData::location::enableFolder< ::fwDataIO::writer::IObjectWriter >(this),
67  m_job(::fwJobs::Observer::New("VTK Image writer")),
68  m_compressionTypes(CompressionTypes::RAW)
69 {
70 }
71 
72 //------------------------------------------------------------------------------
73 
75 {
76  ::fwMedData::ImageSeries::csptr imgSeries = this->getConcreteObject();
77  ::fwData::Image::sptr dataImage = imgSeries->getImage();
78  ::fwMedData::Patient::sptr patient = imgSeries->getPatient();
79  ::fwMedData::Study::sptr study = imgSeries->getStudy();
80  ::fwMedData::Equipment::sptr equipment = imgSeries->getEquipment();
81 
82  // Vtk Conversion
83  vtkSmartPointer< vtkImageData > vtkImage = vtkSmartPointer< vtkImageData >::New();
84  ::fwVtkIO::toVTKImage( dataImage, vtkImage );
85 
86  ::boost::filesystem::path outputDirectory = this->getFolder();
87  FW_RAISE_IF("'" << outputDirectory << "' is not a directory.",
88  !::boost::filesystem::is_directory( outputDirectory ) );
89 
90  // Generate filenames
91  const std::string gdcmfile = ( outputDirectory / "image_" ).string() + "%01d.dcm";
92  ::gdcm::FilenameGenerator fg;
93  fg.SetPattern( gdcmfile.c_str() );
94  int nfiles = vtkImage->GetDimensions()[2];
95  fg.SetNumberOfFilenames( nfiles );
96 
97  bool isGenerated = fg.Generate();
98  FW_RAISE_IF("Filename generation failed.", !isGenerated);
99 
100  auto filenames = vtkSmartPointer<vtkStringArray>::New();
101  for(unsigned int i = 0; i < fg.GetNumberOfFilenames(); ++i)
102  {
103  filenames->InsertNextValue( fg.GetFilename(i) );
104  }
105 
106  // Medical informations
107  auto medprop = vtkSmartPointer<vtkMedicalImageProperties>::New();
108 
109  // Patient name
110  // tagkey = "0010|0010";
111  medprop->SetPatientName(patient->getName().c_str());
112 
113  // Patient sex
114  // tagkey = "0010|0040";
115  medprop->SetPatientSex(patient->getSex().c_str());
116 
117  // Modality
118  // tagkey = "0008|0060";
119  std::string modality = imgSeries->getModality();
120  if(modality.empty())
121  {
122  modality = "OT";
123  }
124  medprop->SetModality(modality.c_str());
125 
126  // Zone
127  // tagkey = "0008|1030";
128  medprop->SetStudyDescription(study->getDescription().c_str());
129  medprop->SetSeriesDescription(imgSeries->getDescription().c_str());
130 
131  // ID
132  // tagkey = "0010|0020";
133  medprop->SetPatientID(patient->getPatientId().c_str());
134 
135  // Birthdate
136  // tagkey = "0010|0030";
137  medprop->SetPatientBirthDate(patient->getBirthdate().c_str());
138 
139  // Hospital
140  // tagkey = "0008|0080";
141  medprop->SetInstitutionName(equipment->getInstitutionName().c_str());
142 
143  // Patient age
144  // Format: nnnD, nnW, nnnM or nnnY (eventually nnD, nnW, nnY)
145  // with D (day), M (month), W (week), Y (year)
146  // For ex: DICOM (0010,1010) = 031Y
147  medprop->SetPatientAge(study->getPatientAge().c_str());
148 
149  // Study Date
150  // tagkey = "0008|0020";
151  medprop->SetStudyDate(study->getDate().c_str());
152 
153  // Study Time
154  // tagkey = "0008|0030";
155 // medprop->SetStudyTime(study->getTime().c_str()); // Do not work (write current time)
156  setValue(medprop, 0x0008, 0x0030, study->getTime());
157 
158  //Series Date
159  setValue(medprop, 0x0008, 0x0021, imgSeries->getDate());
160 
161  // Series Time
162  setValue(medprop, 0x0008, 0x0031, imgSeries->getTime());
163 
164  ::fwMedData::DicomValuesType performingPhysicians = imgSeries->getPerformingPhysiciansName();
165  std::stringstream physicians;
166  if (!performingPhysicians.empty())
167  {
168  ::fwMedData::DicomValuesType::const_iterator itr = performingPhysicians.begin();
169 
170  physicians << *itr++;
171  for (; itr < performingPhysicians.end(); ++itr)
172  {
173  physicians << "\\" << *itr;
174  }
175 
176  }
177  setValue(medprop, 0x0008, 0x1050, physicians.str());
178 
179  setValue(medprop, 0x0008, 0x0090, study->getReferringPhysicianName());
180 
181  // Center and Width
182  // Center = tagkey = "0028|1050";
183  // Width = "0028|1051";
184  medprop->AddWindowLevelPreset( dataImage->getWindowWidth(), dataImage->getWindowCenter() );
185 
186  // Spacing
187  // tagkey = "0028|0030";
188  std::string value;
189  std::vector<double> spacing = dataImage->getSpacing();
190  value = ::fwTools::getString< double >(spacing[0]);
191  value += '\\';
192  value += ::fwTools::getString< double >(spacing[1]);
193  setValue(medprop, 0x0028, 0x0030, value);
194 
195  std::string origin;
196  ::fwData::Image::OriginType orginVec = dataImage->getOrigin();
197  origin = ::fwTools::getString< ::fwData::Image::OriginType::value_type >(orginVec[0]);
198  origin += '\\';
199  origin = ::fwTools::getString< ::fwData::Image::OriginType::value_type >(orginVec[1]);
200 
201  if (dataImage->getNumberOfDimensions() > 2)
202  {
203  // Thickness
204  // tagkey = "0018|0050";
205  value = ::fwTools::getString< double >(spacing[2]);
206  medprop->SetSliceThickness(value.c_str());
207 
208  // InterSlice
209  // tagkey = "0018|0088";
210  value = ::fwTools::getString< double >(spacing[2]);
211  setValue(medprop, 0x0018, 0x0088, value);
212 
213  origin += '\\';
214  origin = ::fwTools::getString< ::fwData::Image::OriginType::value_type >(orginVec[2]);
215  }
216 
217  setValue(medprop, 0x0020, 0x0032, origin);
218 
219  // Writing data
220  //--------------------------------------------------------------
221  vtkSmartPointer< vtkGDCMImageWriter > writer = vtkSmartPointer< vtkGDCMImageWriter >::New();
222 
223  //add progress observation
224  writer->SetStudyUID(study->getInstanceUID().c_str());
225  writer->SetSeriesUID(imgSeries->getInstanceUID().c_str());
226  writer->SetInputData( vtkImage );
227  writer->FileLowerLeftOn();
228  writer->SetFileDimensionality( 2 ); // test the 3D to 2D writing mode
229  writer->SetMedicalImageProperties( medprop );
230  writer->SetFileNames( filenames );
231  writer->SetCompressionType(static_cast<int>(m_compressionTypes));
232 
233  using namespace fwVtkIO::helper;
234  vtkSmartPointer<vtkLambdaCommand> progressCallback;
235  progressCallback = vtkSmartPointer<vtkLambdaCommand>::New();
236  progressCallback->SetCallback([this](vtkObject* caller, long unsigned int, void* )
237  {
238  auto filter = static_cast<vtkGDCMImageWriter*>(caller);
239  m_job->doneWork( filter->GetProgress()*100 );
240  });
241  writer->AddObserver(vtkCommand::ProgressEvent, progressCallback);
242 
243  m_job->addSimpleCancelHook( [&]()
244  {
245  writer->AbortExecuteOn();
246  });
247 
248  writer->Write();
249 
250  m_job->finish();
251 }
252 
253 //------------------------------------------------------------------------------
254 
256 {
257  return "";
258 }
259 
260 //------------------------------------------------------------------------------
261 
263 {
264  return m_job;
265 }
266 
267 } // namespace dicomIO
ILocation::PathType getFolder()
Get folder filesystem path.
Definition: Folder.hpp:99
VTKGDCMIO_API ImageSeriesWriter(::fwDataIO::writer::IObjectWriter::Key key)
Constructor. Does nothing.
This namespace fwDataIO contains reader and writer for several framework&#39;s data.
virtual std::shared_ptr< const DataType > getConcreteObject() const
m_object getter.
VTKGDCMIO_API std::shared_ptr< ::fwJobs::IJob > getJob() const override
Key class used to restrict access to Object construction. See http://www.drdobbs.com/184402053.
vtkmGdcm reader/writer lib
Definition: GdcmHelper.hpp:15
Write an ImageSeries in DICOM format.
std::shared_ptr< ::fwJobs::IJob > sptr
Cancel request callback type.
Definition: IJob.hpp:54
Contains the representation of the data objects used in the framework.
VTKGDCMIO_API std::string extension() override
Return an empty string.
VTKGDCMIO_API void write() override
Write the image series in DICOM format.
This namespace fwJobs provides jobs management.
std::vector< double > OriginType
Image origin type.