]> Creatis software - clitk.git/blob - common/clitkDicomRT_StructureSet.cxx
Add code to write dicom sequence tag in gateSimulation2Dicom
[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 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROIName(const std::string& name)
123 {
124   std::map<int, std::string>::iterator it = mMapOfROIName.begin();
125   int number = -1;
126   while (it != mMapOfROIName.end() && number == -1) {
127     if (it->second == name)
128       number = it->first;
129     else
130       it++;
131   }
132
133   if (number == -1) {
134     std::cerr << "No ROI name " << name << std::endl;
135     return NULL;
136   }
137   
138   return mROIs[number];
139 }
140 //--------------------------------------------------------------------
141 /*
142 // RP: 08/02/2013
143 // RegEx version shall be available when C++x11 supports it propely
144 //
145 //--------------------------------------------------------------------
146 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROINameRegEx(const std::string& regEx)
147 {
148   std::map<int, std::string>::iterator it = mMapOfROIName.begin();
149   int number = -1;
150
151   while (it != mMapOfROIName.end() && number == -1) {
152     if (std::tr1::regex_match (it->second, std::tr1::regex(regEx)))
153       number = it->first;
154     else
155       it++;
156   }
157
158   if (number == -1) {
159     std::cerr << "No ROI name " << number << std::endl;
160     return NULL;
161   }
162   
163   return mROIs[number];
164 }
165 //--------------------------------------------------------------------
166 */
167 //--------------------------------------------------------------------
168 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROINameSubstr(const std::string& s)
169 {
170   std::map<int, std::string>::iterator it = mMapOfROIName.begin();
171   int number = -1;
172
173   while (it != mMapOfROIName.end() && number == -1) {
174     if (it->second.find(s) != std::string::npos)
175       number = it->first;
176     else
177       it++;
178   }
179
180   if (number == -1) {
181     std::cerr << "No ROI name " << s << std::endl;
182     return NULL;
183   }
184   
185   return mROIs[number];
186 }
187 //--------------------------------------------------------------------
188
189 //--------------------------------------------------------------------
190 clitk::DicomRT_StructureSet::ROIMapContainer * 
191 clitk::DicomRT_StructureSet::GetROIsFromROINameSubstr(const std::string& s)
192 {
193   static ROIMapContainer rois;
194   rois.clear();
195   
196   ROIMapContainer::iterator it = mROIs.begin();
197   int number = -1;
198
199   while (it != mROIs.end()) {
200     if (it->second->GetName().find(s) != std::string::npos) {
201       number = it->first;
202       rois[number] = it->second;
203     }
204     it++;
205   }
206
207   if (number == -1) {
208     std::cerr << "No ROI name " << s << std::endl;
209     return NULL;
210   }
211   
212   return &rois;
213   
214 }
215 //--------------------------------------------------------------------
216
217 //--------------------------------------------------------------------
218 void clitk::DicomRT_StructureSet::Print(std::ostream & os) const
219 {
220   os << "Study ID      = " << mStudyID << std::endl
221      << "Study Date    = " << mStudyDate << std::endl
222      << "Study Time    = " << mStudyTime << std::endl
223      << "Struct Label  = " << mLabel << std::endl
224      << "Struct Name   = " << mName << std::endl
225      << "Struct Time   = " << mTime << std::endl
226      << "Number of ROI = " << mROIs.size() << std::endl;
227   for(ROIConstIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
228     iter->second->Print(os);
229   }
230 }
231 //--------------------------------------------------------------------
232
233
234 #if GDCM_MAJOR_VERSION == 2
235 //--------------------------------------------------------------------
236 int clitk::DicomRT_StructureSet::ReadROINumber(const gdcm::Item & item)
237 {
238   // 0x3006,0x0022 = [ROI Number]
239   const gdcm::DataSet & nestedds = item.GetNestedDataSet();
240   gdcm::Attribute<0x3006,0x0022> roinumber;
241   roinumber.SetFromDataSet( nestedds );
242   return roinumber.GetValue();  
243 }
244 //--------------------------------------------------------------------
245 #endif
246
247 //--------------------------------------------------------------------
248 void clitk::DicomRT_StructureSet::Write(const std::string & filename)
249 {
250 #if GDCM_MAJOR_VERSION == 2
251
252   // Assert that the gdcm file is still open (we can write only if it was readed)
253   if (mFile == NULL) {
254     //assert(mFile != NULL);
255     FATAL("Sorry, I can write DICOM only if it was read first from a file with 'Read' function");
256   }
257
258   // Loop and update each ROI 
259   int i=0;
260   for(ROIIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
261     iter->second->UpdateDicomItem();
262     i++;
263   }
264
265   // Write [ Structure Set ROI Sequence ] = 0x3006,0x0020
266   gdcm::DataSet & ds = mFile->GetDataSet();
267   gdcm::Tag tssroisq(0x3006,0x0020);
268   const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq );
269   gdcm::DataElement de(ssroisq);
270   de.SetValue(*mROIInfoSequenceOfItems);
271   ds.Replace(de);
272   
273   // Write [ ROI Contour Sequence ] = 0x3006,0x0039 
274   DD("ici");
275   gdcm::Tag troicsq(0x3006,0x0039);
276   const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
277   gdcm::DataElement de2(roicsq);
278   de2.SetValue(*mROIContoursSequenceOfItems);
279   ds.Replace(de2);
280
281   //DEBUG
282   gdcm::DataSet & a = mROIContoursSequenceOfItems->GetItem(1).GetNestedDataSet();
283   gdcm::Tag tcsq(0x3006,0x0040);
284   const gdcm::DataElement& csq = a.GetDataElement( tcsq );
285   gdcm::SmartPointer<gdcm::SequenceOfItems> sqi2 = csq.GetValueAsSQ();
286   gdcm::Item & j = sqi2->GetItem(1);
287   gdcm::DataSet & b = j.GetNestedDataSet();
288   gdcm::Attribute<0x3006,0x0050> at;
289   gdcm::Tag tcontourdata(0x3006,0x0050);
290   gdcm::DataElement contourdata = b.GetDataElement( tcontourdata );
291   at.SetFromDataElement( contourdata );
292   const double* points = at.GetValues();
293   DD(points[0]);
294
295
296   // Write dicom
297   gdcm::Writer writer;
298   //writer.CheckFileMetaInformationOff();
299   writer.SetFileName(filename.c_str());
300   writer.SetFile(*mFile);
301   DD("before write");
302   writer.Write();
303   DD("End write");
304 #else
305   FATAL("Sorry not compatible with GDCM1, use GDCM2");
306 #endif
307 }
308 //--------------------------------------------------------------------
309
310
311 //--------------------------------------------------------------------
312 void clitk::DicomRT_StructureSet::Read(const std::string & filename)
313 {
314
315 //Try to avoid to use extern GDCM library
316     
317   //check the RS file is available before conversion
318   gdcm::Reader RTreader;
319   RTreader.SetFileName( filename.c_str() );
320   if( !RTreader.Read() ) 
321   {
322     std::cout << "Problem reading file: " << filename << std::endl;
323     return;
324   }
325   
326   const gdcm::DataSet& ds = RTreader.GetFile().GetDataSet();
327   
328   gdcm::MediaStorage ms;
329   ms.SetFromFile( RTreader.GetFile() );
330     
331   // (3006,0020) SQ (Sequence with explicit length #=4)      # 370, 1 StructureSetROISequence  
332   gdcm::Tag tssroisq(0x3006,0x0020);
333   if( !ds.FindDataElement( tssroisq ) )
334   {
335     std::cout << "Problem locating 0x3006,0x0020 - Is this a valid RT Struct file?" << std::endl;
336     return;
337   }
338   gdcm::Tag troicsq(0x3006,0x0039);
339   if( !ds.FindDataElement( troicsq ) )
340   {
341     std::cout << "Problem locating 0x3006,0x0039 - Is this a valid RT Struct file?" << std::endl;
342     return;
343   }
344
345   const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
346
347   gdcm::SmartPointer<gdcm::SequenceOfItems> sqi = roicsq.GetValueAsSQ();
348   if( !sqi || !sqi->GetNumberOfItems() )
349   {
350     return;
351   }
352   const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq );
353   gdcm::SmartPointer<gdcm::SequenceOfItems> ssqi = ssroisq.GetValueAsSQ();
354   if( !ssqi || !ssqi->GetNumberOfItems() )
355   {
356     return;
357   }
358   
359   // Read global info
360   gdcm::Attribute<0x20,0x10> studyid;
361   studyid.SetFromDataSet( ds );
362   gdcm::Attribute<0x8,0x20> studytime;
363   studytime.SetFromDataSet( ds );
364   gdcm::Attribute<0x8,0x30> studydate;
365   studydate.SetFromDataSet( ds );
366   gdcm::Attribute<0x3006,0x02> label;
367   label.SetFromDataSet( ds );
368   gdcm::Attribute<0x3006,0x04> atname;
369   atname.SetFromDataSet( ds );
370   gdcm::Attribute<0x3006,0x09> time;
371   time.SetFromDataSet( ds );
372
373   mStudyID   = studyid.GetValue();
374   mStudyTime = studytime.GetValue();
375   mStudyDate = studydate.GetValue();
376   mLabel     = label.GetValue();
377   mName      = atname.GetValue();
378   mTime      = time.GetValue();
379
380   // Temporary store the list of items
381   std::map<int, gdcm::Item*> mMapOfROIInfo;
382   std::map<int, gdcm::Item*> mMapOfROIContours;
383   
384
385   //----------------------------------
386   // Read all ROI Names and number
387   // 0x3006,0x0020 = [ Structure Set ROI Sequence ]
388   //gdcm::Tag tssroisq(0x3006,0x0020);
389   //const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq );
390   mROIInfoSequenceOfItems = ssroisq.GetValueAsSQ();
391   gdcm::SmartPointer<gdcm::SequenceOfItems> & roi_seq = mROIInfoSequenceOfItems;
392   assert(roi_seq); // TODO error message
393   for(unsigned int ridx = 0; ridx < roi_seq->GetNumberOfItems(); ++ridx)
394     {
395     gdcm::Item & item = roi_seq->GetItem( ridx + 1); // Item starts at 1
396     const gdcm::DataSet& nestedds = item.GetNestedDataSet();
397
398     gdcm::Attribute<0x3006,0x26> roiname;
399     roiname.SetFromDataSet( nestedds );
400     std::string name = roiname.GetValue(); // 0x3006,0x0026 = [ROI Name]
401
402     // 0x3006,0x0022 = [ROI Number]
403     int nb = ReadROINumber(item);
404
405     // Store the item
406     mMapOfROIInfo[nb] = &item;
407
408     // Check if such a number already exist
409     if (mMapOfROIName.find(nb) != mMapOfROIName.end()) {
410       std::cerr << "WARNING. A Roi already exist with the number "
411         << nb << ". I replace." << std::endl;
412     }
413     // Add in map
414     mMapOfROIName[nb] = name;
415     }
416
417   //----------------------------------
418   // Read all ROI item
419   // 0x3006,0x0039 = [ ROI Contour Sequence ]
420   //gdcm::Tag troicsq(0x3006,0x0039);
421   //const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
422   gdcm::SmartPointer<gdcm::SequenceOfItems> roi_contour_seq = roicsq.GetValueAsSQ();
423   mROIContoursSequenceOfItems = roi_contour_seq;
424   assert(roi_contour_seq); // TODO error message
425   for(unsigned int ridx = 0; ridx < roi_contour_seq->GetNumberOfItems(); ++ridx) {
426     gdcm::Item & item = roi_contour_seq->GetItem( ridx + 1); // Item starts at 1
427     // ROI number [Referenced ROI Number]
428     const gdcm::DataSet& nestedds = item.GetNestedDataSet();
429     gdcm::Attribute<0x3006,0x0084> referencedroinumber;
430     referencedroinumber.SetFromDataSet( nestedds );
431     int nb = referencedroinumber.GetValue();
432     // Store the item
433     mMapOfROIContours[nb] = &item;
434   }
435
436   //----------------------------------
437   // Create the ROIs
438   for(std::map<int, gdcm::Item*>::iterator i = mMapOfROIInfo.begin(); i != mMapOfROIInfo.end(); i++) {
439     int nb = i->first;//ReadROINumber(i);//mROIIndex[i];
440     // Create the roi
441     mROIs[nb] = DicomRT_ROI::New();
442     mROIs[nb]->Read(mMapOfROIInfo[nb], mMapOfROIContours[nb]);
443   }
444     
445   return;
446
447 }
448 //--------------------------------------------------------------------
449
450
451 //--------------------------------------------------------------------
452 bool clitk::DicomRT_StructureSet::IsDicomRTStruct(const std::string & filename)
453 {
454   // Open DICOM
455 #if GDCM_MAJOR_VERSION == 2
456   // Read gdcm file
457   mReader = new gdcm::Reader;
458   mReader->SetFileName(filename.c_str());
459   mReader->Read();
460   mFile = &(mReader->GetFile());
461   const gdcm::DataSet & ds = mFile->GetDataSet();
462   
463   // Check file type
464   //Verify if the file is a RT-Structure-Set dicom file
465   gdcm::MediaStorage ms;
466   ms.SetFromFile(*mFile);
467   if( ms != gdcm::MediaStorage::RTStructureSetStorage ) return false;
468
469   gdcm::Attribute<0x8,0x60> modality;
470   modality.SetFromDataSet( ds );
471   if( modality.GetValue() != "RTSTRUCT" ) return false;
472   
473   return true;
474
475   //----------------------------------------------------------------------------------------
476 #else
477   mFile = new gdcm::File;
478   mFile->SetFileName(filename.c_str());
479   mFile->SetMaxSizeLoadEntry(16384); // Needed ...
480   mFile->SetLoadMode(gdcm::LD_NOSHADOW); // don't load shadow tags (in order to save memory)
481   mFile->Load();
482   
483   // Check file type
484   //Verify if the file is a RT-Structure-Set dicom file
485   if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.481.3")) 
486     return false;
487   if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0060),"RTSTRUCT"))
488     return false;
489
490   return true;
491
492 #endif
493 }
494 //--------------------------------------------------------------------
495
496
497 //--------------------------------------------------------------------
498 int clitk::DicomRT_StructureSet::AddBinaryImageAsNewROI(vvImage * im, std::string n)
499 {
500   // Search max ROI number
501   int max = -1;
502   for(ROIConstIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
503     //  for(unsigned int i=0; i<mListOfROI.size(); i++) {
504     clitk::DicomRT_ROI::Pointer roi = iter->second;
505     if (roi->GetROINumber() > max)
506       max = roi->GetROINumber();
507   }
508   ++max;
509
510   // Compute name
511   std::ostringstream oss;
512   oss << vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(n));
513   mMapOfROIName[max] = oss.str();
514
515   // Set color
516   std::vector<double> color;
517   color.push_back(1);
518   color.push_back(0);
519   color.push_back(0);
520
521   // Create ROI
522   DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
523   roi->SetFromBinaryImage(im, max, oss.str(), color, n);
524   mROIs[max] = roi;
525   return max;
526 }
527 //--------------------------------------------------------------------
528
529