]> Creatis software - clitk.git/blob - common/clitkDicomRT_StructureSet.cxx
Read with vtkGDCMPolyDataReader
[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   DD("GetROIFromROINumber");
114   DD(n);
115   if (mROIs.find(n) == mROIs.end()) {
116     std::cerr << "No ROI number " << n << std::endl;
117     return NULL;
118   }
119   return mROIs[n];
120 }
121 //--------------------------------------------------------------------
122
123 //--------------------------------------------------------------------
124 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROIName(const std::string& name)
125 {
126   std::map<int, std::string>::iterator it = mMapOfROIName.begin();
127   int number = -1;
128   while (it != mMapOfROIName.end() && number == -1) {
129     if (it->second == name)
130       number = it->first;
131     else
132       it++;
133   }
134
135   if (number == -1) {
136     std::cerr << "No ROI name " << name << std::endl;
137     return NULL;
138   }
139   
140   return mROIs[number];
141 }
142 //--------------------------------------------------------------------
143 /*
144 // RP: 08/02/2013
145 // RegEx version shall be available when C++x11 supports it propely
146 //
147 //--------------------------------------------------------------------
148 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROINameRegEx(const std::string& regEx)
149 {
150   std::map<int, std::string>::iterator it = mMapOfROIName.begin();
151   int number = -1;
152
153   while (it != mMapOfROIName.end() && number == -1) {
154     if (std::tr1::regex_match (it->second, std::tr1::regex(regEx)))
155       number = it->first;
156     else
157       it++;
158   }
159
160   if (number == -1) {
161     std::cerr << "No ROI name " << number << std::endl;
162     return NULL;
163   }
164   
165   return mROIs[number];
166 }
167 //--------------------------------------------------------------------
168 */
169 //--------------------------------------------------------------------
170 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROINameSubstr(const std::string& s)
171 {
172   std::map<int, std::string>::iterator it = mMapOfROIName.begin();
173   int number = -1;
174
175   while (it != mMapOfROIName.end() && number == -1) {
176     if (it->second.find(s) != std::string::npos)
177       number = it->first;
178     else
179       it++;
180   }
181
182   if (number == -1) {
183     std::cerr << "No ROI name " << s << std::endl;
184     return NULL;
185   }
186   
187   return mROIs[number];
188 }
189 //--------------------------------------------------------------------
190
191 //--------------------------------------------------------------------
192 clitk::DicomRT_StructureSet::ROIMapContainer * 
193 clitk::DicomRT_StructureSet::GetROIsFromROINameSubstr(const std::string& s)
194 {
195   static ROIMapContainer rois;
196   rois.clear();
197   
198   ROIMapContainer::iterator it = mROIs.begin();
199   int number = -1;
200
201   while (it != mROIs.end()) {
202     if (it->second->GetName().find(s) != std::string::npos) {
203       number = it->first;
204       rois[number] = it->second;
205     }
206     it++;
207   }
208
209   if (number == -1) {
210     std::cerr << "No ROI name " << s << std::endl;
211     return NULL;
212   }
213   
214   return &rois;
215   
216 }
217 //--------------------------------------------------------------------
218
219 //--------------------------------------------------------------------
220 void clitk::DicomRT_StructureSet::Print(std::ostream & os) const
221 {
222   os << "Study ID      = " << mStudyID << std::endl
223      << "Study Date    = " << mStudyDate << std::endl
224      << "Study Time    = " << mStudyTime << std::endl
225      << "Struct Label  = " << mLabel << std::endl
226      << "Struct Name   = " << mName << std::endl
227      << "Struct Time   = " << mTime << std::endl
228      << "Number of ROI = " << mROIs.size() << std::endl;
229   for(ROIConstIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
230     iter->second->Print(os);
231   }
232 }
233 //--------------------------------------------------------------------
234
235
236 #if GDCM_MAJOR_VERSION == 2
237 //--------------------------------------------------------------------
238 int clitk::DicomRT_StructureSet::ReadROINumber(const gdcm::Item & item)
239 {
240   // 0x3006,0x0022 = [ROI Number]
241   const gdcm::DataSet & nestedds = item.GetNestedDataSet();
242   gdcm::Attribute<0x3006,0x0022> roinumber;
243   roinumber.SetFromDataSet( nestedds );
244   return roinumber.GetValue();  
245 }
246 //--------------------------------------------------------------------
247 #endif
248
249 //--------------------------------------------------------------------
250 void clitk::DicomRT_StructureSet::Write(const std::string & filename)
251 {
252 #if GDCM_MAJOR_VERSION == 2
253   DD("DCM RT Writer");
254
255   // Assert that the gdcm file is still open (we can write only if it was readed)
256   if (mFile == NULL) {
257     //assert(mFile != NULL);
258     FATAL("Sorry, I can write DICOM only if it was read first from a file with 'Read' function");
259   }
260
261   // Loop and update each ROI 
262   int i=0;
263   for(ROIIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
264     iter->second->UpdateDicomItem();
265     i++;
266   }
267
268   // Write [ Structure Set ROI Sequence ] = 0x3006,0x0020
269   gdcm::DataSet & ds = mFile->GetDataSet();
270   gdcm::Tag tssroisq(0x3006,0x0020);
271   const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq );
272   gdcm::DataElement de(ssroisq);
273   de.SetValue(*mROIInfoSequenceOfItems);
274   ds.Replace(de);
275   
276   // Write [ ROI Contour Sequence ] = 0x3006,0x0039 
277   DD("ici");
278   gdcm::Tag troicsq(0x3006,0x0039);
279   const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
280   gdcm::DataElement de2(roicsq);
281   de2.SetValue(*mROIContoursSequenceOfItems);
282   ds.Replace(de2);
283
284   //DEBUG
285   gdcm::DataSet & a = mROIContoursSequenceOfItems->GetItem(1).GetNestedDataSet();
286   gdcm::Tag tcsq(0x3006,0x0040);
287   const gdcm::DataElement& csq = a.GetDataElement( tcsq );
288   gdcm::SmartPointer<gdcm::SequenceOfItems> sqi2 = csq.GetValueAsSQ();
289   gdcm::Item & j = sqi2->GetItem(1);
290   gdcm::DataSet & b = j.GetNestedDataSet();
291   gdcm::Attribute<0x3006,0x0050> at;
292   gdcm::Tag tcontourdata(0x3006,0x0050);
293   gdcm::DataElement contourdata = b.GetDataElement( tcontourdata );
294   at.SetFromDataElement( contourdata );
295   const double* points = at.GetValues();
296   DD(points[0]);
297
298
299   // Write dicom
300   gdcm::Writer writer;
301   //writer.CheckFileMetaInformationOff();
302   writer.SetFileName(filename.c_str());
303   writer.SetFile(*mFile);
304   DD("before write");
305   writer.Write();
306   DD("End write");
307 #else
308   FATAL("Sorry not compatible with GDCM1, use GDCM2");
309 #endif
310 }
311 //--------------------------------------------------------------------
312
313
314 //--------------------------------------------------------------------
315 void clitk::DicomRT_StructureSet::Read(const std::string & filename)
316 {
317   DD(GDCM_MAJOR_VERSION);
318   DD(CLITK_USE_SYSTEM_GDCM);
319   
320 #if CLITK_USE_SYSTEM_GDCM == 1
321   vtkSmartPointer<vtkGDCMPolyDataReader> reader = vtkGDCMPolyDataReader::New();
322   reader->SetFileName(filename.c_str());
323   reader->Update();
324   
325   // FIXME : check
326
327   // Get global information
328   // FIXME (could be remove with a single access to properties objet.
329   vtkRTStructSetProperties * p = reader->GetRTStructSetProperties();  
330   mStudyID   = p->GetStudyInstanceUID();
331   mStudyDate = p->GetStructureSetDate();
332   mLabel     = p->GetStructureSetLabel();
333   mName      = p->GetStructureSetName();
334   mTime      = p->GetStructureSetTime();
335
336   int n = p->GetNumberOfStructureSetROIs();
337   for(unsigned int i=0; i<n; i++) {
338     // Get the roi number
339     int roinumber = p->GetStructureSetROINumber(i);
340     // Create the roi
341     DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
342     roi->Read(reader, i);
343     // Insert in the map
344     mROIs[roinumber] = roi;
345   }
346 #endif // END version with system gdcm (vtkGDCMPolyDataReader)
347
348
349   // Open DICOM
350 #if GDCM_MAJOR_VERSION == 2
351
352   // Read gdcm file
353   mReader = new gdcm::Reader;
354   mReader->SetFileName(filename.c_str());
355   mReader->Read();
356   mFile = &(mReader->GetFile());
357   const gdcm::DataSet & ds = mFile->GetDataSet();
358   
359   // Check file type
360   //Verify if the file is a RT-Structure-Set dicom file
361   gdcm::MediaStorage ms;
362   ms.SetFromFile(*mFile);
363   if( ms != gdcm::MediaStorage::RTStructureSetStorage )
364     {
365     std::cerr << "Error. the file " << filename
366               << " 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])"
367               << std::endl;
368     exit(0);
369     }
370
371   gdcm::Attribute<0x8,0x60> modality;
372   modality.SetFromDataSet( ds );
373   if( modality.GetValue() != "RTSTRUCT" )
374     {
375     std::cerr << "Error. the file " << filename
376               << " is not a Dicom Struct ? (must have 0x0008,0x0060 = RTSTRUCT [RT Structure Set Storage])"
377               << std::endl;
378     exit(0);
379     }
380
381   // Read global info
382   gdcm::Attribute<0x20,0x10> studyid;
383   studyid.SetFromDataSet( ds );
384   gdcm::Attribute<0x8,0x20> studytime;
385   studytime.SetFromDataSet( ds );
386   gdcm::Attribute<0x8,0x30> studydate;
387   studydate.SetFromDataSet( ds );
388   gdcm::Attribute<0x3006,0x02> label;
389   label.SetFromDataSet( ds );
390   gdcm::Attribute<0x3006,0x04> atname;
391   atname.SetFromDataSet( ds );
392   gdcm::Attribute<0x3006,0x09> time;
393   time.SetFromDataSet( ds );
394
395   mStudyID   = studyid.GetValue();
396   mStudyTime = studytime.GetValue();
397   mStudyDate = studydate.GetValue();
398   mLabel     = label.GetValue();
399   mName      = atname.GetValue();
400   mTime      = time.GetValue();
401
402   // Temporary store the list of items
403   std::map<int, gdcm::Item*> mMapOfROIInfo;
404   std::map<int, gdcm::Item*> mMapOfROIContours;
405  
406 std::map<int, clitk::DicomRT_ROI::Pointer> mROIs;
407   std::map<int, std::string> mMapOfROIName;
408 #if GDCM_MAJOR_VERSION == 2
409   gdcm::Reader * mReader;
410   gdcm::SmartPointer<gdcm::SequenceOfItems> mROIInfoSequenceOfItems;
411   gdcm::SmartPointer<gdcm::SequenceOfItems> mROIContoursSequenceOfItems;  
412 #endif
413   gdcm::File * mFile;
414
415
416   //----------------------------------
417   // Read all ROI Names and number
418   // 0x3006,0x0020 = [ Structure Set ROI Sequence ]
419   gdcm::Tag tssroisq(0x3006,0x0020);
420   const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq );
421   mROIInfoSequenceOfItems = ssroisq.GetValueAsSQ();
422   gdcm::SmartPointer<gdcm::SequenceOfItems> & roi_seq = mROIInfoSequenceOfItems;
423   assert(roi_seq); // TODO error message
424   for(unsigned int ridx = 0; ridx < roi_seq->GetNumberOfItems(); ++ridx)
425     {
426     gdcm::Item & item = roi_seq->GetItem( ridx + 1); // Item starts at 1
427     const gdcm::DataSet& nestedds = item.GetNestedDataSet();
428
429     gdcm::Attribute<0x3006,0x26> roiname;
430     roiname.SetFromDataSet( nestedds );
431     std::string name = roiname.GetValue(); // 0x3006,0x0026 = [ROI Name]
432
433     // 0x3006,0x0022 = [ROI Number]
434     int nb = ReadROINumber(item);
435
436     // Store the item
437     mMapOfROIInfo[nb] = &item;
438
439     // Check if such a number already exist
440     if (mMapOfROIName.find(nb) != mMapOfROIName.end()) {
441       std::cerr << "WARNING. A Roi already exist with the number "
442         << nb << ". I replace." << std::endl;
443     }
444     // Add in map
445     mMapOfROIName[nb] = name;
446     }
447
448   //----------------------------------
449   // Read all ROI item
450   // 0x3006,0x0039 = [ ROI Contour Sequence ]
451   gdcm::Tag troicsq(0x3006,0x0039);
452   const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
453   gdcm::SmartPointer<gdcm::SequenceOfItems> roi_contour_seq = roicsq.GetValueAsSQ();
454   mROIContoursSequenceOfItems = roi_contour_seq;
455   assert(roi_contour_seq); // TODO error message
456   for(unsigned int ridx = 0; ridx < roi_contour_seq->GetNumberOfItems(); ++ridx) {
457     gdcm::Item & item = roi_contour_seq->GetItem( ridx + 1); // Item starts at 1
458     // ROI number [Referenced ROI Number]
459     const gdcm::DataSet& nestedds = item.GetNestedDataSet();
460     gdcm::Attribute<0x3006,0x0084> referencedroinumber;
461     referencedroinumber.SetFromDataSet( nestedds );
462     int nb = referencedroinumber.GetValue();
463     // Store the item
464     mMapOfROIContours[nb] = &item;
465   }
466
467   //----------------------------------
468   // Create the ROIs
469   for(std::map<int, gdcm::Item*>::iterator i = mMapOfROIInfo.begin(); i != mMapOfROIInfo.end(); i++) {
470     int nb = i->first;//ReadROINumber(i);//mROIIndex[i];
471     // Create the roi
472     DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
473     roi->Read(mMapOfROIInfo[nb], mMapOfROIContours[nb]);
474     //    mListOfROI.push_back(roi);
475     //    mMapOfROIIndex[nb] = i;
476     mROIs[nb] = roi;
477   }
478
479   //----------------------------------------------------------------------------------------
480   //----------------------------------------------------------------------------------------
481   //----------------------------------------------------------------------------------------
482 #else
483   mFile = new gdcm::File;
484   mFile->SetFileName(filename.c_str());
485   mFile->SetMaxSizeLoadEntry(16384); // Needed ...
486   mFile->SetLoadMode(gdcm::LD_NOSHADOW); // don't load shadow tags (in order to save memory)
487   mFile->Load();
488   
489   // Check file type
490   //Verify if the file is a RT-Structure-Set dicom file
491   if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.481.3")) {  //SOP clas UID
492     std::cerr << "Error. the file " << filename
493               << " 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])"
494               << std::endl;
495     exit(0);
496   }
497   if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0060),"RTSTRUCT")) {  //SOP clas UID
498     std::cerr << "Error. the file " << filename
499               << " is not a Dicom Struct ? (must have 0x0008,0x0060 = RTSTRUCT [RT Structure Set Storage])"
500               << std::endl;
501     exit(0);
502   }
503
504   // Read global info
505   mStudyID   = mFile->GetValEntry(0x0020,0x0010)->GetValue();
506   mStudyTime = mFile->GetValEntry(0x008,0x0020)->GetValue();
507   mStudyDate = mFile->GetValEntry(0x008,0x0030)->GetValue();
508   mLabel     = mFile->GetValEntry(0x3006,0x002)->GetValue();
509   if (!mFile->GetValEntry(0x3006,0x004)) {
510     mName = "Anonymous";
511   }
512   else {
513     mName = mFile->GetValEntry(0x3006,0x004)->GetValue();
514   }
515   mTime      = mFile->GetValEntry(0x3006,0x009)->GetValue();
516
517   //----------------------------------
518   // Read all ROI Names and number
519   // 0x3006,0x0020 = [ Structure Set ROI Sequence ]
520   gdcm::SeqEntry * roi_seq=mFile->GetSeqEntry(0x3006,0x0020);
521   assert(roi_seq); // TODO error message
522   for (gdcm::SQItem* r=roi_seq->GetFirstSQItem(); r!=0; r=roi_seq->GetNextSQItem()) {
523     std::string name = r->GetEntryValue(0x3006,0x0026);      // 0x3006,0x0026 = [ROI Name]
524     int nb = atoi(r->GetEntryValue(0x3006,0x0022).c_str());  // 0x3006,0x0022 = [ROI Number]
525     // Check if such a number already exist
526     if (mMapOfROIName.find(nb) != mMapOfROIName.end()) {
527       std::cerr << "WARNING. A Roi already exist with the number "
528                 << nb << ". I replace." << std::endl;
529     }
530     // Add in map
531     mMapOfROIName[nb] = name;
532   }
533
534   //----------------------------------
535   // Read all ROI
536   // 0x3006,0x0039 = [ ROI Contour Sequence ]
537   gdcm::SeqEntry * roi_contour_seq=mFile->GetSeqEntry(0x3006,0x0039);
538   assert(roi_contour_seq); // TODO error message
539   int n=0;
540   for (gdcm::SQItem* r=roi_contour_seq->GetFirstSQItem(); r!=0; r=roi_contour_seq->GetNextSQItem()) {
541     DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
542     roi->Read(mMapOfROIName, r);
543     mROIs[roi->GetROINumber()] = roi;
544     n++;
545   }
546
547 #endif
548 }
549 //--------------------------------------------------------------------
550
551
552 //--------------------------------------------------------------------
553 bool clitk::DicomRT_StructureSet::IsDicomRTStruct(const std::string & filename)
554 {
555   // Open DICOM
556 #if GDCM_MAJOR_VERSION == 2
557   // Read gdcm file
558   mReader = new gdcm::Reader;
559   mReader->SetFileName(filename.c_str());
560   mReader->Read();
561   mFile = &(mReader->GetFile());
562   const gdcm::DataSet & ds = mFile->GetDataSet();
563   
564   // Check file type
565   //Verify if the file is a RT-Structure-Set dicom file
566   gdcm::MediaStorage ms;
567   ms.SetFromFile(*mFile);
568   if( ms != gdcm::MediaStorage::RTStructureSetStorage ) return false;
569
570   gdcm::Attribute<0x8,0x60> modality;
571   modality.SetFromDataSet( ds );
572   if( modality.GetValue() != "RTSTRUCT" ) return false;
573   
574   return true;
575
576   //----------------------------------------------------------------------------------------
577 #else
578   mFile = new gdcm::File;
579   mFile->SetFileName(filename.c_str());
580   mFile->SetMaxSizeLoadEntry(16384); // Needed ...
581   mFile->SetLoadMode(gdcm::LD_NOSHADOW); // don't load shadow tags (in order to save memory)
582   mFile->Load();
583   
584   // Check file type
585   //Verify if the file is a RT-Structure-Set dicom file
586   if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.481.3")) 
587     return false;
588   if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0060),"RTSTRUCT"))
589     return false;
590
591   return true;
592
593 #endif
594 }
595 //--------------------------------------------------------------------
596
597
598 //--------------------------------------------------------------------
599 int clitk::DicomRT_StructureSet::AddBinaryImageAsNewROI(vvImage * im, std::string n)
600 {
601   // Search max ROI number
602   int max = -1;
603   for(ROIConstIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
604     //  for(unsigned int i=0; i<mListOfROI.size(); i++) {
605     clitk::DicomRT_ROI::Pointer roi = iter->second;
606     if (roi->GetROINumber() > max)
607       max = roi->GetROINumber();
608   }
609   ++max;
610
611   // Compute name
612   std::ostringstream oss;
613   oss << vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(n));
614   mMapOfROIName[max] = oss.str();
615
616   // Set color
617   std::vector<double> color;
618   color.push_back(1);
619   color.push_back(0);
620   color.push_back(0);
621
622   // Create ROI
623   DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
624   roi->SetFromBinaryImage(im, max, oss.str(), color, n);
625   mROIs[max] = roi;
626   return max;
627 }
628 //--------------------------------------------------------------------
629
630