1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://www.centreleonberard.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
20 #include "clitkDicomRTDoseIO.h"
21 #include "clitkCommon.h"
24 #if GDCM_MAJOR_VERSION == 2
25 // IMPLEMENTATION NOTE:
26 // The following has been done without the use of vtkGDCMImageReader which directly
27 // handle RTDOSE image. Another approach would have been to use gdcm::ImageReader
28 // which also properly recognize RTDOSE
29 #include <gdcmReader.h>
30 #include <gdcmAttribute.h>
32 #include <gdcmFileHelper.h>
35 #define GFOV_SPACING_TOL (1e-1)
37 //--------------------------------------------------------------------
38 // Read Image Information
39 void clitk::DicomRTDoseIO::ReadImageInformation()
41 #if GDCM_MAJOR_VERSION < 2
44 m_GdcmFile = new gdcm::File;
52 double *gfov; /* gfov = GridFrameOffsetVector */
54 #if GDCM_MAJOR_VERSION < 2
59 #if GDCM_MAJOR_VERSION == 2
60 m_GdcmImageReader.SetFileName(m_FileName.c_str());
61 m_GdcmImageReader.Read();
62 gdcm::File* m_GdcmFile = &m_GdcmImageReader.GetFile();
64 m_GdcmFile->SetMaxSizeLoadEntry (0xffff);
65 m_GdcmFile->SetFileName (m_FileName.c_str());
66 m_GdcmFile->SetLoadMode (0);
70 /* Modality -- better be RTSTRUCT */
71 #if GDCM_MAJOR_VERSION == 2
72 gdcm::DataSet &ds = m_GdcmFile->GetDataSet();
74 gdcm::Attribute<0x8,0x60> at1;
75 at1.SetFromDataSet(ds);
78 tmp = m_GdcmFile->GetEntryValue (0x0008, 0x0060);
80 if (strncmp (tmp.c_str(), "RTDOSE", strlen("RTDOSE"))) {
81 itkExceptionMacro(<< "Error. Input file not RTDOSE: " << m_FileName);
84 /* ImagePositionPatient */
85 #if GDCM_MAJOR_VERSION == 2
86 gdcm::Attribute<0x20,0x32> at2;
87 at2.SetFromDataSet(ds);
88 ipp[0] = at2.GetValue(0);
89 ipp[1] = at2.GetValue(1);
90 ipp[2] = at2.GetValue(2);
92 tmp = m_GdcmFile->GetEntryValue (0x0020, 0x0032);
93 rc = sscanf (tmp.c_str(), "%f\\%f\\%f", &ipp[0], &ipp[1], &ipp[2]);
95 itkExceptionMacro(<< "Error parsing RTDOSE ipp.");
100 #if GDCM_MAJOR_VERSION == 2
101 gdcm::Attribute<0x28,0x10> at3;
102 at3.SetFromDataSet(ds);
103 dim[1] = at3.GetValue();
105 tmp = m_GdcmFile->GetEntryValue (0x0028, 0x0010);
106 rc = sscanf (tmp.c_str(), "%d", &dim[1]);
108 itkExceptionMacro(<< "Error parsing RTDOSE rows.");
113 #if GDCM_MAJOR_VERSION == 2
114 gdcm::Attribute<0x28,0x11> at4;
115 at4.SetFromDataSet(ds);
116 dim[0] = at4.GetValue();
118 tmp = m_GdcmFile->GetEntryValue (0x0028, 0x0011);
119 rc = sscanf (tmp.c_str(), "%d", &dim[0]);
121 itkExceptionMacro(<< "Error parsing RTDOSE columns.");
126 #if GDCM_MAJOR_VERSION == 2
127 gdcm::Attribute<0x28,0x30> at5;
128 at5.SetFromDataSet(ds);
129 spacing[0] = at5.GetValue(0);
130 spacing[1] = at5.GetValue(1);
132 tmp = m_GdcmFile->GetEntryValue (0x0028, 0x0030);
133 rc = sscanf (tmp.c_str(), "%g\\%g", &spacing[0], &spacing[1]);
135 itkExceptionMacro(<< "Error parsing RTDOSE pixel spacing.");
139 /* GridFrameOffsetVector */
140 #if GDCM_MAJOR_VERSION == 2
141 gdcm::Attribute<0x3004,0x000C> at6;
142 const gdcm::DataElement& de6 = ds.GetDataElement( at6.GetTag() );
143 at6.SetFromDataElement(de6);
144 gfov = (double*) at6.GetValues();
145 gfov_len = at6.GetNumberOfValues();
147 tmp = m_GdcmFile->GetEntryValue (0x3004, 0x000C);
150 gfov_str = tmp.c_str();
153 gfov = (double*) realloc (gfov, (gfov_len + 1) * sizeof(double));
154 rc = sscanf (gfov_str, "%lf%n", &gfov[gfov_len], &len);
160 if (gfov_str[0] == '\\') {
168 itkExceptionMacro(<< "Error parsing RTDOSE gfov.");
171 /* --- Analyze GridFrameOffsetVector --- */
173 /* (1) Make sure first element is 0. */
175 itkExceptionMacro(<< "Error RTDOSE gfov[0] is not 0.");
178 /* (2) Handle case where gfov_len == 1 (only one slice). */
180 spacing[2] = spacing[0];
183 /* (3) Check to make sure spacing is regular. */
184 for (i = 1; i < gfov_len; i++) {
186 spacing[2] = gfov[1] - gfov[0];
188 double sp = gfov[i] - gfov[i-1];
189 if (fabs(sp - spacing[2]) > GFOV_SPACING_TOL) {
190 itkExceptionMacro(<< "Error RTDOSE grid has irregular spacing:"
191 << sp << " vs " << spacing[2]);
196 #if GDCM_MAJOR_VERSION < 2
200 /* DoseGridScaling */
201 #if GDCM_MAJOR_VERSION == 2
202 gdcm::Attribute<0x3004,0x000E> at7 = { 1. } ;
203 at7.SetFromDataSet(ds);
204 m_DoseScaling = at7.GetValue();
207 tmp = m_GdcmFile->GetEntryValue (0x3004, 0x000E);
208 rc = sscanf (tmp.c_str(), "%f", &m_DoseScaling);
210 /* If element doesn't exist, scaling is 1.0 */
212 // set dimension values
213 SetNumberOfDimensions(3);
214 for(int i=0; i<3; i++) {
215 SetDimensions(i, dim[i]);
216 SetSpacing(i, spacing[i]);
217 SetOrigin(i, ipp[i]);
220 // set other information
221 SetByteOrderToLittleEndian();
222 SetPixelType(itk::ImageIOBase::SCALAR);
223 SetNumberOfComponents(1);
224 SetComponentType(itk::ImageIOBase::FLOAT);
227 //--------------------------------------------------------------------
228 // Read Image Information
229 bool clitk::DicomRTDoseIO::CanReadFile(const char* FileNameToRead)
231 #if GDCM_MAJOR_VERSION == 2
232 gdcm::Reader creader;
233 creader.SetFileName(FileNameToRead);
237 gdcm::DataSet &ds = creader.GetFile().GetDataSet();
238 gdcm::Attribute<0x8,0x60> at1;
239 at1.SetFromDataSet(ds);
240 std::string tmp = at1.GetValue();
242 // opening dicom input file
244 dcmFile.SetFileName(FileNameToRead);
245 if (!dcmFile.OpenFile())
248 //Taken from plastimatch
249 dcmFile.SetMaxSizeLoadEntry (0xffff);
250 dcmFile.SetLoadMode (0);
253 /* Modality -- better be RTDOSE */
254 std::string tmp = dcmFile.GetEntryValue (0x0008, 0x0060);
256 if (!strncmp (tmp.c_str(), "RTDOSE", strlen("RTDOSE"))) {
263 //--------------------------------------------------------------------
266 clitk::DicomRTDoseIO::dose_copy_raw (float *img_out, T *img_in, int nvox, float scale)
268 for (int i = 0; i < nvox; i++) {
269 img_out[i] = img_in[i] * scale;
273 //--------------------------------------------------------------------
274 // Read Image Content
275 void clitk::DicomRTDoseIO::Read(void * buffer)
277 unsigned long npix = 1;
278 for(unsigned int i=0; i<GetNumberOfDimensions(); i++)
279 npix *= GetDimensions(i);
282 #if GDCM_MAJOR_VERSION == 2
283 gdcm::Image &i = m_GdcmImageReader.GetImage();
285 char* image_data = new char[i.GetBufferLength()];
286 i.GetBuffer(image_data);
288 gdcm::DataSet& ds = m_GdcmImageReader.GetFile().GetDataSet();
289 float *img = (float*) buffer;
291 gdcm::Attribute<0x28, 0x100> pixel_size;
292 pixel_size.SetFromDataSet(ds);
293 if (pixel_size.GetValue() == 16) {
294 unsigned short* image_data2 = (unsigned short*) image_data ;
295 dose_copy_raw (img, image_data2, npix, m_DoseScaling);
297 else if (pixel_size.GetValue() == 32) {
298 unsigned long* image_data2 = (unsigned long*) image_data;
299 dose_copy_raw (img, image_data2, npix, m_DoseScaling);
301 itkExceptionMacro(<< "Error RTDOSE not type 16U and 32U (type="
302 << pixel_size.GetValue() << ")");
305 delete [] image_data;
307 float *img = (float*) buffer;
309 gdcm::FileHelper m_GdcmFile_helper (m_GdcmFile);
311 //size_t image_data_size = m_GdcmFile_helper.GetImageDataSize();
312 if (strcmp (m_GdcmFile->GetPixelType().c_str(), "16U")==0) {
313 unsigned short* image_data = (unsigned short*) m_GdcmFile_helper.GetImageData();
314 dose_copy_raw (img, image_data, npix, m_DoseScaling);
315 } else if (strcmp(m_GdcmFile->GetPixelType().c_str(),"32U")==0) {
316 unsigned long* image_data = (unsigned long*) m_GdcmFile_helper.GetImageData ();
317 dose_copy_raw (img, image_data, npix, m_DoseScaling);
319 itkExceptionMacro(<< "Error RTDOSE not type 16U and 32U (type="
320 << m_GdcmFile->GetPixelType().c_str() << ")");
325 /* GCS FIX: Do I need to do something about endian-ness? */
329 /* Copy data to volume */
330 // float *img = (float*) vol->img;
331 // for (i = 0; i < vol->npix; i++) {
332 //img[i] = image_data[i] * m_DoseScaling;
336 //--------------------------------------------------------------------
337 // Write Image Information
338 void clitk::DicomRTDoseIO::WriteImageInformation(bool keepOfStream)
342 //--------------------------------------------------------------------
343 // Write Image Information
344 bool clitk::DicomRTDoseIO::CanWriteFile(const char* FileNameToWrite)
349 //--------------------------------------------------------------------
351 void clitk::DicomRTDoseIO::Write(const void * buffer)