]> Creatis software - clitk.git/blob - common/clitkDicomRT_StructureSet.cxx
Merge branch 'master' of /home/dsarrut/clitk3.server
[clitk.git] / common / clitkDicomRT_StructureSet.cxx
1 /*=========================================================================
2   Program:         vv http://www.creatis.insa-lyon.fr/rio/vv
3   Main authors :   XX XX XX
4
5   Authors belongs to:
6   - University of LYON           http://www.universite-lyon.fr/
7   - Léon Bérard cancer center    http://www.centreleonberard.fr
8   - CREATIS CNRS laboratory      http://www.creatis.insa-lyon.fr
9
10   This software is distributed WITHOUT ANY WARRANTY; without even
11   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12   PURPOSE.  See the copyright notices for more information.
13
14   It is distributed under dual licence
15   - BSD       http://www.opensource.org/licenses/bsd-license.php
16   - CeCILL-B  http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17
18   =========================================================================*/
19
20 #include "clitkDicomRT_StructureSet.h"
21 #include <vtksys/SystemTools.hxx>
22 #include "gdcmFile.h"
23
24 //--------------------------------------------------------------------
25 clitk::DicomRT_StructureSet::DicomRT_StructureSet()
26 {
27   mStudyID = "NoStudyID";
28   mStudyTime = "NoStudyTime";
29   mStudyDate = "NoStudyDate";
30   mLabel = "NoLabel";
31   mName = "NoName";
32   mDate = "NoDate";
33   mTime = "NoTime";
34   mFile = NULL;
35 }
36 //--------------------------------------------------------------------
37
38
39 //--------------------------------------------------------------------
40 clitk::DicomRT_StructureSet::~DicomRT_StructureSet()
41 {
42 }
43 //--------------------------------------------------------------------
44
45
46 //--------------------------------------------------------------------
47 const std::string & clitk::DicomRT_StructureSet::GetStudyID() const
48 {
49   return mStudyID;
50 }
51 //--------------------------------------------------------------------
52
53
54 //--------------------------------------------------------------------
55 const std::string & clitk::DicomRT_StructureSet::GetStudyTime() const
56 {
57   return mStudyTime;
58 }
59 //--------------------------------------------------------------------
60
61
62 //--------------------------------------------------------------------
63 const std::string & clitk::DicomRT_StructureSet::GetStudyDate() const
64 {
65   return mStudyDate;
66 }
67 //--------------------------------------------------------------------
68
69
70 //--------------------------------------------------------------------
71 const std::string & clitk::DicomRT_StructureSet::GetLabel() const
72 {
73   return mLabel;
74 }
75 //--------------------------------------------------------------------
76
77
78 //--------------------------------------------------------------------
79 const std::string & clitk::DicomRT_StructureSet::GetName() const
80 {
81   return mName;
82 }
83 //--------------------------------------------------------------------
84
85
86 //--------------------------------------------------------------------
87 const std::string & clitk::DicomRT_StructureSet::GetDate() const
88 {
89   return mDate;
90 }
91 //--------------------------------------------------------------------
92
93
94 //--------------------------------------------------------------------
95 const std::string & clitk::DicomRT_StructureSet::GetTime() const
96 {
97   return mTime;
98 }
99 //--------------------------------------------------------------------
100
101
102 //--------------------------------------------------------------------
103 // const std::vector<clitk::DicomRT_ROI::Pointer> & clitk::DicomRT_StructureSet::GetListOfROI() const
104 // {
105 //   return mListOfROI;
106 // }
107 //--------------------------------------------------------------------
108
109
110 //--------------------------------------------------------------------
111 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROINumber(int n)
112 {
113   if (mROIs.find(n) == mROIs.end()) {
114     std::cerr << "No ROI number " << n << std::endl;
115     return NULL;
116   }
117   return mROIs[n];
118 }
119 //--------------------------------------------------------------------
120
121
122 //--------------------------------------------------------------------
123 void clitk::DicomRT_StructureSet::Print(std::ostream & os) const
124 {
125   os << "Study ID      = " << mStudyID << std::endl
126      << "Study Date    = " << mStudyDate << std::endl
127      << "Study Time    = " << mStudyTime << std::endl
128      << "Struct Label  = " << mLabel << std::endl
129      << "Struct Name   = " << mName << std::endl
130      << "Struct Time   = " << mTime << std::endl
131      << "Number of ROI = " << mROIs.size() << std::endl;
132   for(ROIConstIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
133     iter->second->Print(os);
134   }
135 }
136 //--------------------------------------------------------------------
137
138
139 #if GDCM_MAJOR_VERSION == 2
140 //--------------------------------------------------------------------
141 int clitk::DicomRT_StructureSet::ReadROINumber(const gdcm::Item & item)
142 {
143   // 0x3006,0x0022 = [ROI Number]
144   const gdcm::DataSet & nestedds = item.GetNestedDataSet();
145   gdcm::Attribute<0x3006,0x0022> roinumber;
146   roinumber.SetFromDataSet( nestedds );
147   return roinumber.GetValue();  
148 }
149 //--------------------------------------------------------------------
150 #endif
151
152 //--------------------------------------------------------------------
153 void clitk::DicomRT_StructureSet::Write(const std::string & filename)
154 {
155 #if GDCM_MAJOR_VERSION == 2
156   DD("DCM RT Writer");
157
158   // Assert that the gdcm file is still open (we can write only if it was readed)
159   if (mFile == NULL) {
160     //assert(mFile != NULL);
161     FATAL("Sorry, I can write DICOM only if it was read first from a file with 'Read' function");
162   }
163
164   // Loop and update each ROI 
165   for(ROIIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
166     iter->second->UpdateDicomItem();
167   }
168
169   // Write [ Structure Set ROI Sequence ] = 0x3006,0x0020
170   gdcm::DataSet & ds = mFile->GetDataSet();
171   gdcm::Tag tssroisq(0x3006,0x0020);
172   const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq );
173   gdcm::DataElement de(ssroisq);
174   de.SetValue(*mROIInfoSequenceOfItems);
175   ds.Replace(de);
176   
177   // Write [ ROI Contour Sequence ] = 0x3006,0x0039 
178   DD("ici");
179   gdcm::Tag troicsq(0x3006,0x0039);
180   const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
181   gdcm::DataElement de2(roicsq);
182   de2.SetValue(*mROIContoursSequenceOfItems);
183   ds.Replace(de);
184   
185   // Write dicom
186   gdcm::Writer writer;
187   //writer.CheckFileMetaInformationOff();
188   writer.SetFileName(filename.c_str());
189   writer.SetFile(*mFile);
190   DD("before write");
191   writer.Write();
192   DD("End write");
193 #else
194   FATAL("Sorry not compatible with GDCM1, use GDCM2");
195 #endif
196 }
197 //--------------------------------------------------------------------
198
199
200 //--------------------------------------------------------------------
201 void clitk::DicomRT_StructureSet::Read(const std::string & filename)
202 {
203   // Open DICOM
204 #if GDCM_MAJOR_VERSION == 2
205   // Read gdcm file
206   mReader = new gdcm::Reader;
207   mReader->SetFileName(filename.c_str());
208   mReader->Read();
209   mFile = &(mReader->GetFile());
210   const gdcm::DataSet & ds = mFile->GetDataSet();
211   
212   // Check file type
213   //Verify if the file is a RT-Structure-Set dicom file
214   gdcm::MediaStorage ms;
215   ms.SetFromFile(*mFile);
216   if( ms != gdcm::MediaStorage::RTStructureSetStorage )
217     {
218     std::cerr << "Error. the file " << filename
219               << " is not a Dicom Struct ? (must have a SOP Class UID [0008|0016] = 1.2.840.10008.5.1.4.1.1.481.3 ==> [RT Structure Set Storage])"
220               << std::endl;
221     exit(0);
222     }
223
224   gdcm::Attribute<0x8,0x60> modality;
225   modality.SetFromDataSet( ds );
226   if( modality.GetValue() != "RTSTRUCT" )
227     {
228     std::cerr << "Error. the file " << filename
229               << " is not a Dicom Struct ? (must have 0x0008,0x0060 = RTSTRUCT [RT Structure Set Storage])"
230               << std::endl;
231     exit(0);
232     }
233
234   // Read global info
235   gdcm::Attribute<0x20,0x10> studyid;
236   studyid.SetFromDataSet( ds );
237   gdcm::Attribute<0x8,0x20> studytime;
238   studytime.SetFromDataSet( ds );
239   gdcm::Attribute<0x8,0x30> studydate;
240   studydate.SetFromDataSet( ds );
241   gdcm::Attribute<0x3006,0x02> label;
242   label.SetFromDataSet( ds );
243   gdcm::Attribute<0x3006,0x04> atname;
244   atname.SetFromDataSet( ds );
245   gdcm::Attribute<0x3006,0x09> time;
246   time.SetFromDataSet( ds );
247
248   mStudyID   = studyid.GetValue();
249   mStudyTime = studytime.GetValue();
250   mStudyDate = studydate.GetValue();
251   mLabel     = label.GetValue();
252   mName      = atname.GetValue();
253   mTime      = time.GetValue();
254
255   // Temporary store the list of items
256   std::map<int, gdcm::Item*> mMapOfROIInfo;
257   std::map<int, gdcm::Item*> mMapOfROIContours;
258
259   //----------------------------------
260   // Read all ROI Names and number
261   // 0x3006,0x0020 = [ Structure Set ROI Sequence ]
262   gdcm::Tag tssroisq(0x3006,0x0020);
263   const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq );
264   mROIInfoSequenceOfItems = ssroisq.GetValueAsSQ();
265   gdcm::SmartPointer<gdcm::SequenceOfItems> & roi_seq = mROIInfoSequenceOfItems;
266   assert(roi_seq); // TODO error message
267   for(unsigned int ridx = 0; ridx < roi_seq->GetNumberOfItems(); ++ridx)
268     {
269     gdcm::Item & item = roi_seq->GetItem( ridx + 1); // Item starts at 1
270     const gdcm::DataSet& nestedds = item.GetNestedDataSet();
271
272     gdcm::Attribute<0x3006,0x26> roiname;
273     roiname.SetFromDataSet( nestedds );
274     std::string name = roiname.GetValue(); // 0x3006,0x0026 = [ROI Name]
275
276     // 0x3006,0x0022 = [ROI Number]
277     int nb = ReadROINumber(item);
278
279     // Store the item
280     mMapOfROIInfo[nb] = &item;
281
282     // Check if such a number already exist
283     if (mMapOfROIName.find(nb) != mMapOfROIName.end()) {
284       std::cerr << "WARNING. A Roi already exist with the number "
285         << nb << ". I replace." << std::endl;
286     }
287     // Add in map
288     mMapOfROIName[nb] = name;
289     }
290
291   //----------------------------------
292   // Read all ROI item
293   // 0x3006,0x0039 = [ ROI Contour Sequence ]
294   gdcm::Tag troicsq(0x3006,0x0039);
295   const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
296   gdcm::SmartPointer<gdcm::SequenceOfItems> roi_contour_seq = roicsq.GetValueAsSQ();
297   mROIContoursSequenceOfItems = roi_contour_seq;
298   assert(roi_contour_seq); // TODO error message
299   for(unsigned int ridx = 0; ridx < roi_contour_seq->GetNumberOfItems(); ++ridx) {
300     gdcm::Item & item = roi_contour_seq->GetItem( ridx + 1); // Item starts at 1
301     // ROI number [Referenced ROI Number]
302     const gdcm::DataSet& nestedds = item.GetNestedDataSet();
303     gdcm::Attribute<0x3006,0x0084> referencedroinumber;
304     referencedroinumber.SetFromDataSet( nestedds );
305     int nb = referencedroinumber.GetValue();
306     // Store the item
307     mMapOfROIContours[nb] = &item;
308   }
309
310   //----------------------------------
311   // Create the ROIs
312   for(std::map<int, gdcm::Item*>::iterator i = mMapOfROIInfo.begin(); i != mMapOfROIInfo.end(); i++) {
313     int nb = i->first;//ReadROINumber(i);//mROIIndex[i];
314     // Create the roi
315     DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
316     roi->Read(mMapOfROIInfo[nb], mMapOfROIContours[nb]);
317     //    mListOfROI.push_back(roi);
318     //    mMapOfROIIndex[nb] = i;
319     mROIs[nb] = roi;
320   }
321
322   //----------------------------------------------------------------------------------------
323   //----------------------------------------------------------------------------------------
324   //----------------------------------------------------------------------------------------
325 #else
326   mFile = new gdcm::File;
327   mFile->SetFileName(filename.c_str());
328   mFile->SetMaxSizeLoadEntry(16384); // Needed ...
329   mFile->SetLoadMode(gdcm::LD_NOSHADOW); // don't load shadow tags (in order to save memory)
330   mFile->Load();
331   
332   // Check file type
333   //Verify if the file is a RT-Structure-Set dicom file
334   if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.481.3")) {  //SOP clas UID
335     std::cerr << "Error. the file " << filename
336               << " is not a Dicom Struct ? (must have a SOP Class UID [0008|0016] = 1.2.840.10008.5.1.4.1.1.481.3 ==> [RT Structure Set Storage])"
337               << std::endl;
338     exit(0);
339   }
340   if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0060),"RTSTRUCT")) {  //SOP clas UID
341     std::cerr << "Error. the file " << filename
342               << " is not a Dicom Struct ? (must have 0x0008,0x0060 = RTSTRUCT [RT Structure Set Storage])"
343               << std::endl;
344     exit(0);
345   }
346
347   // Read global info
348   mStudyID   = mFile->GetValEntry(0x0020,0x0010)->GetValue();
349   mStudyTime = mFile->GetValEntry(0x008,0x0020)->GetValue();
350   mStudyDate = mFile->GetValEntry(0x008,0x0030)->GetValue();
351   mLabel     = mFile->GetValEntry(0x3006,0x002)->GetValue();
352   if (!mFile->GetValEntry(0x3006,0x004)) {
353     mName = "Anonymous";
354   }
355   else {
356     mName = mFile->GetValEntry(0x3006,0x004)->GetValue();
357   }
358   mTime      = mFile->GetValEntry(0x3006,0x009)->GetValue();
359
360   //----------------------------------
361   // Read all ROI Names and number
362   // 0x3006,0x0020 = [ Structure Set ROI Sequence ]
363   gdcm::SeqEntry * roi_seq=mFile->GetSeqEntry(0x3006,0x0020);
364   assert(roi_seq); // TODO error message
365   for (gdcm::SQItem* r=roi_seq->GetFirstSQItem(); r!=0; r=roi_seq->GetNextSQItem()) {
366     std::string name = r->GetEntryValue(0x3006,0x0026);      // 0x3006,0x0026 = [ROI Name]
367     int nb = atoi(r->GetEntryValue(0x3006,0x0022).c_str());  // 0x3006,0x0022 = [ROI Number]
368     // Check if such a number already exist
369     if (mMapOfROIName.find(nb) != mMapOfROIName.end()) {
370       std::cerr << "WARNING. A Roi already exist with the number "
371                 << nb << ". I replace." << std::endl;
372     }
373     // Add in map
374     mMapOfROIName[nb] = name;
375   }
376
377   //----------------------------------
378   // Read all ROI
379   // 0x3006,0x0039 = [ ROI Contour Sequence ]
380   gdcm::SeqEntry * roi_contour_seq=mFile->GetSeqEntry(0x3006,0x0039);
381   assert(roi_contour_seq); // TODO error message
382   int n=0;
383   for (gdcm::SQItem* r=roi_contour_seq->GetFirstSQItem(); r!=0; r=roi_contour_seq->GetNextSQItem()) {
384     DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
385     roi->Read(mMapOfROIName, r);
386     mROIs[roi->GetROINumber()] = roi;
387     n++;
388   }
389
390 #endif
391 }
392 //--------------------------------------------------------------------
393
394
395 //--------------------------------------------------------------------
396 int clitk::DicomRT_StructureSet::AddBinaryImageAsNewROI(vvImage * im, std::string n)
397 {
398   // Search max ROI number
399   int max = -1;
400   for(ROIConstIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
401     //  for(unsigned int i=0; i<mListOfROI.size(); i++) {
402     clitk::DicomRT_ROI::Pointer roi = iter->second;
403     if (roi->GetROINumber() > max)
404       max = roi->GetROINumber();
405   }
406   ++max;
407
408   // Compute name
409   std::ostringstream oss;
410   oss << vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(n));
411   mMapOfROIName[max] = oss.str();
412
413   // Set color
414   std::vector<double> color;
415   color.push_back(1);
416   color.push_back(0);
417   color.push_back(0);
418
419   // Create ROI
420   DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
421   roi->SetFromBinaryImage(im, max, oss.str(), color, n);
422   mROIs[max] = roi;
423   return max;
424 }
425 //--------------------------------------------------------------------
426
427