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 if (mROIs.find(n) == mROIs.end()) {
114 std::cerr << "No ROI number " << n << std::endl;
119 //--------------------------------------------------------------------
121 //--------------------------------------------------------------------
122 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROIName(const std::string& name)
124 std::map<int, std::string>::iterator it = mMapOfROIName.begin();
126 while (it != mMapOfROIName.end() && number == -1) {
127 if (it->second == name)
134 std::cerr << "No ROI name " << name << std::endl;
138 return mROIs[number];
140 //--------------------------------------------------------------------
143 // RegEx version shall be available when C++x11 supports it propely
145 //--------------------------------------------------------------------
146 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROINameRegEx(const std::string& regEx)
148 std::map<int, std::string>::iterator it = mMapOfROIName.begin();
151 while (it != mMapOfROIName.end() && number == -1) {
152 if (std::tr1::regex_match (it->second, std::tr1::regex(regEx)))
159 std::cerr << "No ROI name " << number << std::endl;
163 return mROIs[number];
165 //--------------------------------------------------------------------
167 //--------------------------------------------------------------------
168 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROINameSubstr(const std::string& s)
170 std::map<int, std::string>::iterator it = mMapOfROIName.begin();
173 while (it != mMapOfROIName.end() && number == -1) {
174 if (it->second.find(s) != std::string::npos)
181 std::cerr << "No ROI name " << s << std::endl;
185 return mROIs[number];
187 //--------------------------------------------------------------------
189 //--------------------------------------------------------------------
190 clitk::DicomRT_StructureSet::ROIMapContainer *
191 clitk::DicomRT_StructureSet::GetROIsFromROINameSubstr(const std::string& s)
193 static ROIMapContainer rois;
196 ROIMapContainer::iterator it = mROIs.begin();
199 while (it != mROIs.end()) {
200 if (it->second->GetName().find(s) != std::string::npos) {
202 rois[number] = it->second;
208 std::cerr << "No ROI name " << s << std::endl;
215 //--------------------------------------------------------------------
217 //--------------------------------------------------------------------
218 void clitk::DicomRT_StructureSet::Print(std::ostream & os) const
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);
231 //--------------------------------------------------------------------
234 #if GDCM_MAJOR_VERSION == 2
235 //--------------------------------------------------------------------
236 int clitk::DicomRT_StructureSet::ReadROINumber(const gdcm::Item & item)
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();
244 //--------------------------------------------------------------------
247 //--------------------------------------------------------------------
248 void clitk::DicomRT_StructureSet::Write(const std::string & filename)
250 #if GDCM_MAJOR_VERSION == 2
252 // Assert that the gdcm file is still open (we can write only if it was readed)
254 //assert(mFile != NULL);
255 FATAL("Sorry, I can write DICOM only if it was read first from a file with 'Read' function");
258 // Loop and update each ROI
260 for(ROIIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
261 iter->second->UpdateDicomItem();
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);
273 // Write [ ROI Contour Sequence ] = 0x3006,0x0039
275 gdcm::Tag troicsq(0x3006,0x0039);
276 const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
277 gdcm::DataElement de2(roicsq);
278 de2.SetValue(*mROIContoursSequenceOfItems);
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();
298 //writer.CheckFileMetaInformationOff();
299 writer.SetFileName(filename.c_str());
300 writer.SetFile(*mFile);
305 FATAL("Sorry not compatible with GDCM1, use GDCM2");
308 //--------------------------------------------------------------------
311 //--------------------------------------------------------------------
312 void clitk::DicomRT_StructureSet::Read(const std::string & filename)
314 #if CLITK_USE_SYSTEM_GDCM == 1
315 vtkSmartPointer<vtkGDCMPolyDataReader> reader = vtkGDCMPolyDataReader::New();
316 reader->SetFileName(filename.c_str());
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();
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);
332 DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
333 roi->Read(reader, i);
335 mROIs[roinumber] = roi;
338 #endif // END version with system gdcm (vtkGDCMPolyDataReader)
342 #if GDCM_MAJOR_VERSION == 2
343 FATAL("Error : compile vv with itk4 + external gdcm");
346 mReader = new gdcm::Reader;
347 mReader->SetFileName(filename.c_str());
349 mFile = &(mReader->GetFile());
350 const gdcm::DataSet & ds = mFile->GetDataSet();
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 )
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])"
364 gdcm::Attribute<0x8,0x60> modality;
365 modality.SetFromDataSet( ds );
366 if( modality.GetValue() != "RTSTRUCT" )
368 std::cerr << "Error. the file " << filename
369 << " is not a Dicom Struct ? (must have 0x0008,0x0060 = RTSTRUCT [RT Structure Set Storage])"
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 );
388 mStudyID = studyid.GetValue();
389 mStudyTime = studytime.GetValue();
390 mStudyDate = studydate.GetValue();
391 mLabel = label.GetValue();
392 mName = atname.GetValue();
393 mTime = time.GetValue();
395 // Temporary store the list of items
396 std::map<int, gdcm::Item*> mMapOfROIInfo;
397 std::map<int, gdcm::Item*> mMapOfROIContours;
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;
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)
419 gdcm::Item & item = roi_seq->GetItem( ridx + 1); // Item starts at 1
420 const gdcm::DataSet& nestedds = item.GetNestedDataSet();
422 gdcm::Attribute<0x3006,0x26> roiname;
423 roiname.SetFromDataSet( nestedds );
424 std::string name = roiname.GetValue(); // 0x3006,0x0026 = [ROI Name]
426 // 0x3006,0x0022 = [ROI Number]
427 int nb = ReadROINumber(item);
430 mMapOfROIInfo[nb] = &item;
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;
438 mMapOfROIName[nb] = name;
441 //----------------------------------
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();
457 mMapOfROIContours[nb] = &item;
460 //----------------------------------
462 for(std::map<int, gdcm::Item*>::iterator i = mMapOfROIInfo.begin(); i != mMapOfROIInfo.end(); i++) {
463 int nb = i->first;//ReadROINumber(i);//mROIIndex[i];
465 DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
466 roi->Read(mMapOfROIInfo[nb], mMapOfROIContours[nb]);
467 // mListOfROI.push_back(roi);
468 // mMapOfROIIndex[nb] = i;
472 //----------------------------------------------------------------------------------------
473 //----------------------------------------------------------------------------------------
474 //----------------------------------------------------------------------------------------
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)
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])"
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])"
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)) {
506 mName = mFile->GetValEntry(0x3006,0x004)->GetValue();
508 mTime = mFile->GetValEntry(0x3006,0x009)->GetValue();
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;
524 mMapOfROIName[nb] = name;
527 //----------------------------------
529 // 0x3006,0x0039 = [ ROI Contour Sequence ]
530 gdcm::SeqEntry * roi_contour_seq=mFile->GetSeqEntry(0x3006,0x0039);
531 assert(roi_contour_seq); // TODO error message
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;
542 //--------------------------------------------------------------------
545 //--------------------------------------------------------------------
546 bool clitk::DicomRT_StructureSet::IsDicomRTStruct(const std::string & filename)
549 #if GDCM_MAJOR_VERSION == 2
551 mReader = new gdcm::Reader;
552 mReader->SetFileName(filename.c_str());
554 mFile = &(mReader->GetFile());
555 const gdcm::DataSet & ds = mFile->GetDataSet();
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;
563 gdcm::Attribute<0x8,0x60> modality;
564 modality.SetFromDataSet( ds );
565 if( modality.GetValue() != "RTSTRUCT" ) return false;
569 //----------------------------------------------------------------------------------------
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)
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"))
581 if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0060),"RTSTRUCT"))
588 //--------------------------------------------------------------------
591 //--------------------------------------------------------------------
592 int clitk::DicomRT_StructureSet::AddBinaryImageAsNewROI(vvImage * im, std::string n)
594 // Search max ROI number
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();
605 std::ostringstream oss;
606 oss << vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(n));
607 mMapOfROIName[max] = oss.str();
610 std::vector<double> color;
616 DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
617 roi->SetFromBinaryImage(im, max, oss.str(), color, n);
621 //--------------------------------------------------------------------