]> Creatis software - clitk.git/blob - common/clitkDicomRT_StructureSet.cxx
4945693f8694beaf84dd6ac39ef047dfaf9b12db
[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 #if CLITK_USE_SYSTEM_GDCM == 1
315   vtkSmartPointer<vtkGDCMPolyDataReader> reader = vtkGDCMPolyDataReader::New();
316   reader->SetFileName(filename.c_str());
317   reader->Update();
318   
319   // Get global information
320   vtkRTStructSetProperties * p = reader->GetRTStructSetProperties();  
321   mStudyID   = p->GetStudyInstanceUID();
322   mStudyDate = p->GetStructureSetDate();
323   mLabel     = p->GetStructureSetLabel();
324   mName      = p->GetStructureSetName();
325   mTime      = p->GetStructureSetTime();
326
327   int n = p->GetNumberOfStructureSetROIs();
328   for(unsigned int i=0; i<n; i++) {
329     // Get the roi number
330     int roinumber = p->GetStructureSetROINumber(i);
331     // Create the roi
332     DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
333     roi->Read(reader, i);
334     // Insert in the map
335     mROIs[roinumber] = roi;
336   }
337   return;
338 #endif // END version with system gdcm (vtkGDCMPolyDataReader)
339
340
341   // Open DICOM
342 #if GDCM_MAJOR_VERSION == 2
343   FATAL("Error : compile vv with itk4 + external gdcm");
344
345   // Read gdcm file
346   mReader = new gdcm::Reader;
347   mReader->SetFileName(filename.c_str());
348   mReader->Read();
349   mFile = &(mReader->GetFile());
350   const gdcm::DataSet & ds = mFile->GetDataSet();
351   
352   // Check file type
353   //Verify if the file is a RT-Structure-Set dicom file
354   gdcm::MediaStorage ms;
355   ms.SetFromFile(*mFile);
356   if( ms != gdcm::MediaStorage::RTStructureSetStorage )
357     {
358     std::cerr << "Error. the file " << filename
359               << " 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])"
360               << std::endl;
361     exit(0);
362     }
363
364   gdcm::Attribute<0x8,0x60> modality;
365   modality.SetFromDataSet( ds );
366   if( modality.GetValue() != "RTSTRUCT" )
367     {
368     std::cerr << "Error. the file " << filename
369               << " is not a Dicom Struct ? (must have 0x0008,0x0060 = RTSTRUCT [RT Structure Set Storage])"
370               << std::endl;
371     exit(0);
372     }
373
374   // Read global info
375   gdcm::Attribute<0x20,0x10> studyid;
376   studyid.SetFromDataSet( ds );
377   gdcm::Attribute<0x8,0x20> studytime;
378   studytime.SetFromDataSet( ds );
379   gdcm::Attribute<0x8,0x30> studydate;
380   studydate.SetFromDataSet( ds );
381   gdcm::Attribute<0x3006,0x02> label;
382   label.SetFromDataSet( ds );
383   gdcm::Attribute<0x3006,0x04> atname;
384   atname.SetFromDataSet( ds );
385   gdcm::Attribute<0x3006,0x09> time;
386   time.SetFromDataSet( ds );
387
388   mStudyID   = studyid.GetValue();
389   mStudyTime = studytime.GetValue();
390   mStudyDate = studydate.GetValue();
391   mLabel     = label.GetValue();
392   mName      = atname.GetValue();
393   mTime      = time.GetValue();
394
395   // Temporary store the list of items
396   std::map<int, gdcm::Item*> mMapOfROIInfo;
397   std::map<int, gdcm::Item*> mMapOfROIContours;
398  
399 std::map<int, clitk::DicomRT_ROI::Pointer> mROIs;
400   std::map<int, std::string> mMapOfROIName;
401 #if GDCM_MAJOR_VERSION == 2
402   gdcm::Reader * mReader;
403   gdcm::SmartPointer<gdcm::SequenceOfItems> mROIInfoSequenceOfItems;
404   gdcm::SmartPointer<gdcm::SequenceOfItems> mROIContoursSequenceOfItems;  
405 #endif
406   gdcm::File * mFile;
407
408
409   //----------------------------------
410   // Read all ROI Names and number
411   // 0x3006,0x0020 = [ Structure Set ROI Sequence ]
412   gdcm::Tag tssroisq(0x3006,0x0020);
413   const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq );
414   mROIInfoSequenceOfItems = ssroisq.GetValueAsSQ();
415   gdcm::SmartPointer<gdcm::SequenceOfItems> & roi_seq = mROIInfoSequenceOfItems;
416   assert(roi_seq); // TODO error message
417   for(unsigned int ridx = 0; ridx < roi_seq->GetNumberOfItems(); ++ridx)
418     {
419     gdcm::Item & item = roi_seq->GetItem( ridx + 1); // Item starts at 1
420     const gdcm::DataSet& nestedds = item.GetNestedDataSet();
421
422     gdcm::Attribute<0x3006,0x26> roiname;
423     roiname.SetFromDataSet( nestedds );
424     std::string name = roiname.GetValue(); // 0x3006,0x0026 = [ROI Name]
425
426     // 0x3006,0x0022 = [ROI Number]
427     int nb = ReadROINumber(item);
428
429     // Store the item
430     mMapOfROIInfo[nb] = &item;
431
432     // Check if such a number already exist
433     if (mMapOfROIName.find(nb) != mMapOfROIName.end()) {
434       std::cerr << "WARNING. A Roi already exist with the number "
435         << nb << ". I replace." << std::endl;
436     }
437     // Add in map
438     mMapOfROIName[nb] = name;
439     }
440
441   //----------------------------------
442   // Read all ROI item
443   // 0x3006,0x0039 = [ ROI Contour Sequence ]
444   gdcm::Tag troicsq(0x3006,0x0039);
445   const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
446   gdcm::SmartPointer<gdcm::SequenceOfItems> roi_contour_seq = roicsq.GetValueAsSQ();
447   mROIContoursSequenceOfItems = roi_contour_seq;
448   assert(roi_contour_seq); // TODO error message
449   for(unsigned int ridx = 0; ridx < roi_contour_seq->GetNumberOfItems(); ++ridx) {
450     gdcm::Item & item = roi_contour_seq->GetItem( ridx + 1); // Item starts at 1
451     // ROI number [Referenced ROI Number]
452     const gdcm::DataSet& nestedds = item.GetNestedDataSet();
453     gdcm::Attribute<0x3006,0x0084> referencedroinumber;
454     referencedroinumber.SetFromDataSet( nestedds );
455     int nb = referencedroinumber.GetValue();
456     // Store the item
457     mMapOfROIContours[nb] = &item;
458   }
459
460   //----------------------------------
461   // Create the ROIs
462   for(std::map<int, gdcm::Item*>::iterator i = mMapOfROIInfo.begin(); i != mMapOfROIInfo.end(); i++) {
463     int nb = i->first;//ReadROINumber(i);//mROIIndex[i];
464     // Create the roi
465     DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
466     roi->Read(mMapOfROIInfo[nb], mMapOfROIContours[nb]);
467     //    mListOfROI.push_back(roi);
468     //    mMapOfROIIndex[nb] = i;
469     mROIs[nb] = roi;
470   }
471
472   //----------------------------------------------------------------------------------------
473   //----------------------------------------------------------------------------------------
474   //----------------------------------------------------------------------------------------
475 #else
476   mFile = new gdcm::File;
477   mFile->SetFileName(filename.c_str());
478   mFile->SetMaxSizeLoadEntry(16384); // Needed ...
479   mFile->SetLoadMode(gdcm::LD_NOSHADOW); // don't load shadow tags (in order to save memory)
480   mFile->Load();
481   
482   // Check file type
483   //Verify if the file is a RT-Structure-Set dicom file
484   if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.481.3")) {  //SOP clas UID
485     std::cerr << "Error. the file " << filename
486               << " 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])"
487               << std::endl;
488     exit(0);
489   }
490   if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0060),"RTSTRUCT")) {  //SOP clas UID
491     std::cerr << "Error. the file " << filename
492               << " is not a Dicom Struct ? (must have 0x0008,0x0060 = RTSTRUCT [RT Structure Set Storage])"
493               << std::endl;
494     exit(0);
495   }
496
497   // Read global info
498   mStudyID   = mFile->GetValEntry(0x0020,0x0010)->GetValue();
499   mStudyTime = mFile->GetValEntry(0x008,0x0020)->GetValue();
500   mStudyDate = mFile->GetValEntry(0x008,0x0030)->GetValue();
501   mLabel     = mFile->GetValEntry(0x3006,0x002)->GetValue();
502   if (!mFile->GetValEntry(0x3006,0x004)) {
503     mName = "Anonymous";
504   }
505   else {
506     mName = mFile->GetValEntry(0x3006,0x004)->GetValue();
507   }
508   mTime      = mFile->GetValEntry(0x3006,0x009)->GetValue();
509
510   //----------------------------------
511   // Read all ROI Names and number
512   // 0x3006,0x0020 = [ Structure Set ROI Sequence ]
513   gdcm::SeqEntry * roi_seq=mFile->GetSeqEntry(0x3006,0x0020);
514   assert(roi_seq); // TODO error message
515   for (gdcm::SQItem* r=roi_seq->GetFirstSQItem(); r!=0; r=roi_seq->GetNextSQItem()) {
516     std::string name = r->GetEntryValue(0x3006,0x0026);      // 0x3006,0x0026 = [ROI Name]
517     int nb = atoi(r->GetEntryValue(0x3006,0x0022).c_str());  // 0x3006,0x0022 = [ROI Number]
518     // Check if such a number already exist
519     if (mMapOfROIName.find(nb) != mMapOfROIName.end()) {
520       std::cerr << "WARNING. A Roi already exist with the number "
521                 << nb << ". I replace." << std::endl;
522     }
523     // Add in map
524     mMapOfROIName[nb] = name;
525   }
526
527   //----------------------------------
528   // Read all ROI
529   // 0x3006,0x0039 = [ ROI Contour Sequence ]
530   gdcm::SeqEntry * roi_contour_seq=mFile->GetSeqEntry(0x3006,0x0039);
531   assert(roi_contour_seq); // TODO error message
532   int n=0;
533   for (gdcm::SQItem* r=roi_contour_seq->GetFirstSQItem(); r!=0; r=roi_contour_seq->GetNextSQItem()) {
534     DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
535     roi->Read(mMapOfROIName, r);
536     mROIs[roi->GetROINumber()] = roi;
537     n++;
538   }
539
540 #endif
541 }
542 //--------------------------------------------------------------------
543
544
545 //--------------------------------------------------------------------
546 bool clitk::DicomRT_StructureSet::IsDicomRTStruct(const std::string & filename)
547 {
548   // Open DICOM
549 #if GDCM_MAJOR_VERSION == 2
550   // Read gdcm file
551   mReader = new gdcm::Reader;
552   mReader->SetFileName(filename.c_str());
553   mReader->Read();
554   mFile = &(mReader->GetFile());
555   const gdcm::DataSet & ds = mFile->GetDataSet();
556   
557   // Check file type
558   //Verify if the file is a RT-Structure-Set dicom file
559   gdcm::MediaStorage ms;
560   ms.SetFromFile(*mFile);
561   if( ms != gdcm::MediaStorage::RTStructureSetStorage ) return false;
562
563   gdcm::Attribute<0x8,0x60> modality;
564   modality.SetFromDataSet( ds );
565   if( modality.GetValue() != "RTSTRUCT" ) return false;
566   
567   return true;
568
569   //----------------------------------------------------------------------------------------
570 #else
571   mFile = new gdcm::File;
572   mFile->SetFileName(filename.c_str());
573   mFile->SetMaxSizeLoadEntry(16384); // Needed ...
574   mFile->SetLoadMode(gdcm::LD_NOSHADOW); // don't load shadow tags (in order to save memory)
575   mFile->Load();
576   
577   // Check file type
578   //Verify if the file is a RT-Structure-Set dicom file
579   if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.481.3")) 
580     return false;
581   if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0060),"RTSTRUCT"))
582     return false;
583
584   return true;
585
586 #endif
587 }
588 //--------------------------------------------------------------------
589
590
591 //--------------------------------------------------------------------
592 int clitk::DicomRT_StructureSet::AddBinaryImageAsNewROI(vvImage * im, std::string n)
593 {
594   // Search max ROI number
595   int max = -1;
596   for(ROIConstIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
597     //  for(unsigned int i=0; i<mListOfROI.size(); i++) {
598     clitk::DicomRT_ROI::Pointer roi = iter->second;
599     if (roi->GetROINumber() > max)
600       max = roi->GetROINumber();
601   }
602   ++max;
603
604   // Compute name
605   std::ostringstream oss;
606   oss << vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(n));
607   mMapOfROIName[max] = oss.str();
608
609   // Set color
610   std::vector<double> color;
611   color.push_back(1);
612   color.push_back(0);
613   color.push_back(0);
614
615   // Create ROI
616   DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
617   roi->SetFromBinaryImage(im, max, oss.str(), color, n);
618   mROIs[max] = roi;
619   return max;
620 }
621 //--------------------------------------------------------------------
622
623