1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
3 Main authors : XX XX XX
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
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.
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
18 =========================================================================*/
20 #include "clitkDicomRT_StructureSet.h"
21 #include <vtksys/SystemTools.hxx>
24 //--------------------------------------------------------------------
25 clitk::DicomRT_StructureSet::DicomRT_StructureSet()
27 mStudyID = "NoStudyID";
28 mStudyTime = "NoStudyTime";
29 mStudyDate = "NoStudyDate";
36 //--------------------------------------------------------------------
39 //--------------------------------------------------------------------
40 clitk::DicomRT_StructureSet::~DicomRT_StructureSet()
43 //--------------------------------------------------------------------
46 //--------------------------------------------------------------------
47 const std::string & clitk::DicomRT_StructureSet::GetStudyID() const
51 //--------------------------------------------------------------------
54 //--------------------------------------------------------------------
55 const std::string & clitk::DicomRT_StructureSet::GetStudyTime() const
59 //--------------------------------------------------------------------
62 //--------------------------------------------------------------------
63 const std::string & clitk::DicomRT_StructureSet::GetStudyDate() const
67 //--------------------------------------------------------------------
70 //--------------------------------------------------------------------
71 const std::string & clitk::DicomRT_StructureSet::GetLabel() const
75 //--------------------------------------------------------------------
78 //--------------------------------------------------------------------
79 const std::string & clitk::DicomRT_StructureSet::GetName() const
83 //--------------------------------------------------------------------
86 //--------------------------------------------------------------------
87 const std::string & clitk::DicomRT_StructureSet::GetDate() const
91 //--------------------------------------------------------------------
94 //--------------------------------------------------------------------
95 const std::string & clitk::DicomRT_StructureSet::GetTime() const
99 //--------------------------------------------------------------------
102 //--------------------------------------------------------------------
103 // const std::vector<clitk::DicomRT_ROI::Pointer> & clitk::DicomRT_StructureSet::GetListOfROI() const
105 // return mListOfROI;
107 //--------------------------------------------------------------------
110 //--------------------------------------------------------------------
111 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROINumber(int n)
113 DD("GetROIFromROINumber");
115 if (mROIs.find(n) == mROIs.end()) {
116 std::cerr << "No ROI number " << n << std::endl;
121 //--------------------------------------------------------------------
123 //--------------------------------------------------------------------
124 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROIName(const std::string& name)
126 std::map<int, std::string>::iterator it = mMapOfROIName.begin();
128 while (it != mMapOfROIName.end() && number == -1) {
129 if (it->second == name)
136 std::cerr << "No ROI name " << name << std::endl;
140 return mROIs[number];
142 //--------------------------------------------------------------------
145 // RegEx version shall be available when C++x11 supports it propely
147 //--------------------------------------------------------------------
148 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROINameRegEx(const std::string& regEx)
150 std::map<int, std::string>::iterator it = mMapOfROIName.begin();
153 while (it != mMapOfROIName.end() && number == -1) {
154 if (std::tr1::regex_match (it->second, std::tr1::regex(regEx)))
161 std::cerr << "No ROI name " << number << std::endl;
165 return mROIs[number];
167 //--------------------------------------------------------------------
169 //--------------------------------------------------------------------
170 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROINameSubstr(const std::string& s)
172 std::map<int, std::string>::iterator it = mMapOfROIName.begin();
175 while (it != mMapOfROIName.end() && number == -1) {
176 if (it->second.find(s) != std::string::npos)
183 std::cerr << "No ROI name " << s << std::endl;
187 return mROIs[number];
189 //--------------------------------------------------------------------
191 //--------------------------------------------------------------------
192 clitk::DicomRT_StructureSet::ROIMapContainer *
193 clitk::DicomRT_StructureSet::GetROIsFromROINameSubstr(const std::string& s)
195 static ROIMapContainer rois;
198 ROIMapContainer::iterator it = mROIs.begin();
201 while (it != mROIs.end()) {
202 if (it->second->GetName().find(s) != std::string::npos) {
204 rois[number] = it->second;
210 std::cerr << "No ROI name " << s << std::endl;
217 //--------------------------------------------------------------------
219 //--------------------------------------------------------------------
220 void clitk::DicomRT_StructureSet::Print(std::ostream & os) const
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);
233 //--------------------------------------------------------------------
236 #if GDCM_MAJOR_VERSION == 2
237 //--------------------------------------------------------------------
238 int clitk::DicomRT_StructureSet::ReadROINumber(const gdcm::Item & item)
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();
246 //--------------------------------------------------------------------
249 //--------------------------------------------------------------------
250 void clitk::DicomRT_StructureSet::Write(const std::string & filename)
252 #if GDCM_MAJOR_VERSION == 2
255 // Assert that the gdcm file is still open (we can write only if it was readed)
257 //assert(mFile != NULL);
258 FATAL("Sorry, I can write DICOM only if it was read first from a file with 'Read' function");
261 // Loop and update each ROI
263 for(ROIIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
264 iter->second->UpdateDicomItem();
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);
276 // Write [ ROI Contour Sequence ] = 0x3006,0x0039
278 gdcm::Tag troicsq(0x3006,0x0039);
279 const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
280 gdcm::DataElement de2(roicsq);
281 de2.SetValue(*mROIContoursSequenceOfItems);
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();
301 //writer.CheckFileMetaInformationOff();
302 writer.SetFileName(filename.c_str());
303 writer.SetFile(*mFile);
308 FATAL("Sorry not compatible with GDCM1, use GDCM2");
311 //--------------------------------------------------------------------
314 //--------------------------------------------------------------------
315 void clitk::DicomRT_StructureSet::Read(const std::string & filename)
317 DD(GDCM_MAJOR_VERSION);
318 DD(CLITK_USE_SYSTEM_GDCM);
320 #if CLITK_USE_SYSTEM_GDCM == 1
321 vtkSmartPointer<vtkGDCMPolyDataReader> reader = vtkGDCMPolyDataReader::New();
322 reader->SetFileName(filename.c_str());
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();
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);
341 DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
342 roi->Read(reader, i);
344 mROIs[roinumber] = roi;
346 #endif // END version with system gdcm (vtkGDCMPolyDataReader)
350 #if GDCM_MAJOR_VERSION == 2
353 mReader = new gdcm::Reader;
354 mReader->SetFileName(filename.c_str());
356 mFile = &(mReader->GetFile());
357 const gdcm::DataSet & ds = mFile->GetDataSet();
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 )
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])"
371 gdcm::Attribute<0x8,0x60> modality;
372 modality.SetFromDataSet( ds );
373 if( modality.GetValue() != "RTSTRUCT" )
375 std::cerr << "Error. the file " << filename
376 << " is not a Dicom Struct ? (must have 0x0008,0x0060 = RTSTRUCT [RT Structure Set Storage])"
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 );
395 mStudyID = studyid.GetValue();
396 mStudyTime = studytime.GetValue();
397 mStudyDate = studydate.GetValue();
398 mLabel = label.GetValue();
399 mName = atname.GetValue();
400 mTime = time.GetValue();
402 // Temporary store the list of items
403 std::map<int, gdcm::Item*> mMapOfROIInfo;
404 std::map<int, gdcm::Item*> mMapOfROIContours;
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;
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)
426 gdcm::Item & item = roi_seq->GetItem( ridx + 1); // Item starts at 1
427 const gdcm::DataSet& nestedds = item.GetNestedDataSet();
429 gdcm::Attribute<0x3006,0x26> roiname;
430 roiname.SetFromDataSet( nestedds );
431 std::string name = roiname.GetValue(); // 0x3006,0x0026 = [ROI Name]
433 // 0x3006,0x0022 = [ROI Number]
434 int nb = ReadROINumber(item);
437 mMapOfROIInfo[nb] = &item;
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;
445 mMapOfROIName[nb] = name;
448 //----------------------------------
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();
464 mMapOfROIContours[nb] = &item;
467 //----------------------------------
469 for(std::map<int, gdcm::Item*>::iterator i = mMapOfROIInfo.begin(); i != mMapOfROIInfo.end(); i++) {
470 int nb = i->first;//ReadROINumber(i);//mROIIndex[i];
472 DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
473 roi->Read(mMapOfROIInfo[nb], mMapOfROIContours[nb]);
474 // mListOfROI.push_back(roi);
475 // mMapOfROIIndex[nb] = i;
479 //----------------------------------------------------------------------------------------
480 //----------------------------------------------------------------------------------------
481 //----------------------------------------------------------------------------------------
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)
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])"
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])"
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)) {
513 mName = mFile->GetValEntry(0x3006,0x004)->GetValue();
515 mTime = mFile->GetValEntry(0x3006,0x009)->GetValue();
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;
531 mMapOfROIName[nb] = name;
534 //----------------------------------
536 // 0x3006,0x0039 = [ ROI Contour Sequence ]
537 gdcm::SeqEntry * roi_contour_seq=mFile->GetSeqEntry(0x3006,0x0039);
538 assert(roi_contour_seq); // TODO error message
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;
549 //--------------------------------------------------------------------
552 //--------------------------------------------------------------------
553 bool clitk::DicomRT_StructureSet::IsDicomRTStruct(const std::string & filename)
556 #if GDCM_MAJOR_VERSION == 2
558 mReader = new gdcm::Reader;
559 mReader->SetFileName(filename.c_str());
561 mFile = &(mReader->GetFile());
562 const gdcm::DataSet & ds = mFile->GetDataSet();
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;
570 gdcm::Attribute<0x8,0x60> modality;
571 modality.SetFromDataSet( ds );
572 if( modality.GetValue() != "RTSTRUCT" ) return false;
576 //----------------------------------------------------------------------------------------
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)
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"))
588 if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0060),"RTSTRUCT"))
595 //--------------------------------------------------------------------
598 //--------------------------------------------------------------------
599 int clitk::DicomRT_StructureSet::AddBinaryImageAsNewROI(vvImage * im, std::string n)
601 // Search max ROI number
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();
612 std::ostringstream oss;
613 oss << vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(n));
614 mMapOfROIName[max] = oss.str();
617 std::vector<double> color;
623 DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
624 roi->SetFromBinaryImage(im, max, oss.str(), color, n);
628 //--------------------------------------------------------------------