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 void clitk::DicomRT_StructureSet::SetTransformMatrix(vtkMatrix4x4* matrix)
97 mTransformMatrix = matrix;
99 //--------------------------------------------------------------------
102 //--------------------------------------------------------------------
103 const std::string & clitk::DicomRT_StructureSet::GetTime() const
107 //--------------------------------------------------------------------
110 //--------------------------------------------------------------------
111 // const std::vector<clitk::DicomRT_ROI::Pointer> & clitk::DicomRT_StructureSet::GetListOfROI() const
113 // return mListOfROI;
115 //--------------------------------------------------------------------
118 //--------------------------------------------------------------------
119 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROINumber(int n)
121 if (mROIs.find(n) == mROIs.end()) {
122 std::cerr << "No ROI number " << n << std::endl;
127 //--------------------------------------------------------------------
129 //--------------------------------------------------------------------
130 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROIName(const std::string& name)
132 std::map<int, std::string>::iterator it = mMapOfROIName.begin();
134 while (it != mMapOfROIName.end() && number == -1) {
135 if (it->second == name)
142 std::cerr << "No ROI name " << name << std::endl;
146 return mROIs[number];
148 //--------------------------------------------------------------------
151 // RegEx version shall be available when C++x11 supports it propely
153 //--------------------------------------------------------------------
154 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROINameRegEx(const std::string& regEx)
156 std::map<int, std::string>::iterator it = mMapOfROIName.begin();
159 while (it != mMapOfROIName.end() && number == -1) {
160 if (std::tr1::regex_match (it->second, std::tr1::regex(regEx)))
167 std::cerr << "No ROI name " << number << std::endl;
171 return mROIs[number];
173 //--------------------------------------------------------------------
175 //--------------------------------------------------------------------
176 clitk::DicomRT_ROI* clitk::DicomRT_StructureSet::GetROIFromROINameSubstr(const std::string& s)
178 std::map<int, std::string>::iterator it = mMapOfROIName.begin();
181 while (it != mMapOfROIName.end() && number == -1) {
182 if (it->second.find(s) != std::string::npos)
189 std::cerr << "No ROI name " << s << std::endl;
193 return mROIs[number];
195 //--------------------------------------------------------------------
197 //--------------------------------------------------------------------
198 clitk::DicomRT_StructureSet::ROIMapContainer *
199 clitk::DicomRT_StructureSet::GetROIsFromROINameSubstr(const std::string& s)
201 static ROIMapContainer rois;
204 ROIMapContainer::iterator it = mROIs.begin();
207 while (it != mROIs.end()) {
208 if (it->second->GetName().find(s) != std::string::npos) {
210 rois[number] = it->second;
216 std::cerr << "No ROI name " << s << std::endl;
223 //--------------------------------------------------------------------
225 //--------------------------------------------------------------------
226 void clitk::DicomRT_StructureSet::Print(std::ostream & os) const
228 os << "Study ID = " << mStudyID << std::endl
229 << "Study Date = " << mStudyDate << std::endl
230 << "Study Time = " << mStudyTime << std::endl
231 << "Struct Label = " << mLabel << std::endl
232 << "Struct Name = " << mName << std::endl
233 << "Struct Time = " << mTime << std::endl
234 << "Number of ROI = " << mROIs.size() << std::endl;
235 for(ROIConstIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
236 iter->second->Print(os);
239 //--------------------------------------------------------------------
242 #if GDCM_MAJOR_VERSION == 2
243 //--------------------------------------------------------------------
244 int clitk::DicomRT_StructureSet::ReadROINumber(const gdcm::Item & item)
246 // 0x3006,0x0022 = [ROI Number]
247 const gdcm::DataSet & nestedds = item.GetNestedDataSet();
248 gdcm::Attribute<0x3006,0x0022> roinumber;
249 roinumber.SetFromDataSet( nestedds );
250 return roinumber.GetValue();
252 //--------------------------------------------------------------------
255 //--------------------------------------------------------------------
256 void clitk::DicomRT_StructureSet::Write(const std::string & filename)
258 #if GDCM_MAJOR_VERSION == 2
260 // Assert that the gdcm file is still open (we can write only if it was readed)
262 //assert(mFile != NULL);
263 FATAL("Sorry, I can write DICOM only if it was read first from a file with 'Read' function");
266 // Loop and update each ROI
268 for(ROIIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
269 iter->second->UpdateDicomItem();
273 // Write [ Structure Set ROI Sequence ] = 0x3006,0x0020
274 gdcm::DataSet & ds = mFile->GetDataSet();
275 gdcm::Tag tssroisq(0x3006,0x0020);
276 const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq );
277 gdcm::DataElement de(ssroisq);
278 de.SetValue(*mROIInfoSequenceOfItems);
281 // Write [ ROI Contour Sequence ] = 0x3006,0x0039
283 gdcm::Tag troicsq(0x3006,0x0039);
284 const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
285 gdcm::DataElement de2(roicsq);
286 de2.SetValue(*mROIContoursSequenceOfItems);
290 gdcm::DataSet & a = mROIContoursSequenceOfItems->GetItem(1).GetNestedDataSet();
291 gdcm::Tag tcsq(0x3006,0x0040);
292 const gdcm::DataElement& csq = a.GetDataElement( tcsq );
293 gdcm::SmartPointer<gdcm::SequenceOfItems> sqi2 = csq.GetValueAsSQ();
294 gdcm::Item & j = sqi2->GetItem(1);
295 gdcm::DataSet & b = j.GetNestedDataSet();
296 gdcm::Attribute<0x3006,0x0050> at;
297 gdcm::Tag tcontourdata(0x3006,0x0050);
298 gdcm::DataElement contourdata = b.GetDataElement( tcontourdata );
299 at.SetFromDataElement( contourdata );
300 const double* points = at.GetValues();
306 //writer.CheckFileMetaInformationOff();
307 writer.SetFileName(filename.c_str());
308 writer.SetFile(*mFile);
313 FATAL("Sorry not compatible with GDCM1, use GDCM2");
316 //--------------------------------------------------------------------
319 //--------------------------------------------------------------------
320 void clitk::DicomRT_StructureSet::Read(const std::string & filename)
323 //Try to avoid to use extern GDCM library
325 //check the RS file is available before conversion
326 gdcm::Reader RTreader;
327 RTreader.SetFileName( filename.c_str() );
328 if( !RTreader.Read() )
330 std::cout << "Problem reading file: " << filename << std::endl;
334 const gdcm::DataSet& ds = RTreader.GetFile().GetDataSet();
336 gdcm::MediaStorage ms;
337 ms.SetFromFile( RTreader.GetFile() );
339 // (3006,0020) SQ (Sequence with explicit length #=4) # 370, 1 StructureSetROISequence
340 gdcm::Tag tssroisq(0x3006,0x0020);
341 if( !ds.FindDataElement( tssroisq ) )
343 std::cout << "Problem locating 0x3006,0x0020 - Is this a valid RT Struct file?" << std::endl;
346 gdcm::Tag troicsq(0x3006,0x0039);
347 if( !ds.FindDataElement( troicsq ) )
349 std::cout << "Problem locating 0x3006,0x0039 - Is this a valid RT Struct file?" << std::endl;
353 const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
355 gdcm::SmartPointer<gdcm::SequenceOfItems> sqi = roicsq.GetValueAsSQ();
356 if( !sqi || !sqi->GetNumberOfItems() )
360 const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq );
361 gdcm::SmartPointer<gdcm::SequenceOfItems> ssqi = ssroisq.GetValueAsSQ();
362 if( !ssqi || !ssqi->GetNumberOfItems() )
368 gdcm::Attribute<0x20,0x10> studyid;
369 studyid.SetFromDataSet( ds );
370 gdcm::Attribute<0x8,0x20> studytime;
371 studytime.SetFromDataSet( ds );
372 gdcm::Attribute<0x8,0x30> studydate;
373 studydate.SetFromDataSet( ds );
374 gdcm::Attribute<0x3006,0x02> label;
375 label.SetFromDataSet( ds );
376 gdcm::Attribute<0x3006,0x04> atname;
377 atname.SetFromDataSet( ds );
378 gdcm::Attribute<0x3006,0x09> time;
379 time.SetFromDataSet( ds );
381 mStudyID = studyid.GetValue();
382 mStudyTime = studytime.GetValue();
383 mStudyDate = studydate.GetValue();
384 mLabel = label.GetValue();
385 mName = atname.GetValue();
386 mTime = time.GetValue();
388 // Temporary store the list of items
389 std::map<int, gdcm::Item*> mMapOfROIInfo;
390 std::map<int, gdcm::Item*> mMapOfROIContours;
393 //----------------------------------
394 // Read all ROI Names and number
395 // 0x3006,0x0020 = [ Structure Set ROI Sequence ]
396 //gdcm::Tag tssroisq(0x3006,0x0020);
397 //const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq );
398 mROIInfoSequenceOfItems = ssroisq.GetValueAsSQ();
399 gdcm::SmartPointer<gdcm::SequenceOfItems> & roi_seq = mROIInfoSequenceOfItems;
400 assert(roi_seq); // TODO error message
401 for(unsigned int ridx = 0; ridx < roi_seq->GetNumberOfItems(); ++ridx)
403 gdcm::Item & item = roi_seq->GetItem( ridx + 1); // Item starts at 1
404 const gdcm::DataSet& nestedds = item.GetNestedDataSet();
406 gdcm::Attribute<0x3006,0x26> roiname;
407 roiname.SetFromDataSet( nestedds );
408 std::string name = roiname.GetValue(); // 0x3006,0x0026 = [ROI Name]
410 // 0x3006,0x0022 = [ROI Number]
411 int nb = ReadROINumber(item);
414 mMapOfROIInfo[nb] = &item;
416 // Check if such a number already exist
417 if (mMapOfROIName.find(nb) != mMapOfROIName.end()) {
418 std::cerr << "WARNING. A Roi already exist with the number "
419 << nb << ". I replace." << std::endl;
422 mMapOfROIName[nb] = name;
425 //----------------------------------
427 // 0x3006,0x0039 = [ ROI Contour Sequence ]
428 //gdcm::Tag troicsq(0x3006,0x0039);
429 //const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
430 gdcm::SmartPointer<gdcm::SequenceOfItems> roi_contour_seq = roicsq.GetValueAsSQ();
431 mROIContoursSequenceOfItems = roi_contour_seq;
432 assert(roi_contour_seq); // TODO error message
433 for(unsigned int ridx = 0; ridx < roi_contour_seq->GetNumberOfItems(); ++ridx) {
434 gdcm::Item & item = roi_contour_seq->GetItem( ridx + 1); // Item starts at 1
435 // ROI number [Referenced ROI Number]
436 const gdcm::DataSet& nestedds = item.GetNestedDataSet();
437 gdcm::Attribute<0x3006,0x0084> referencedroinumber;
438 referencedroinumber.SetFromDataSet( nestedds );
439 int nb = referencedroinumber.GetValue();
441 mMapOfROIContours[nb] = &item;
444 //----------------------------------
446 for(std::map<int, gdcm::Item*>::iterator i = mMapOfROIInfo.begin(); i != mMapOfROIInfo.end(); i++) {
447 int nb = i->first;//ReadROINumber(i);//mROIIndex[i];
449 mROIs[nb] = DicomRT_ROI::New();
450 mROIs[nb]->SetTransformMatrix(mTransformMatrix);
451 mROIs[nb]->Read(mMapOfROIInfo[nb], mMapOfROIContours[nb]);
457 //--------------------------------------------------------------------
460 //--------------------------------------------------------------------
461 bool clitk::DicomRT_StructureSet::IsDicomRTStruct(const std::string & filename)
464 #if GDCM_MAJOR_VERSION == 2
466 mReader = new gdcm::Reader;
467 mReader->SetFileName(filename.c_str());
469 mFile = &(mReader->GetFile());
470 const gdcm::DataSet & ds = mFile->GetDataSet();
473 //Verify if the file is a RT-Structure-Set dicom file
474 gdcm::MediaStorage ms;
475 ms.SetFromFile(*mFile);
476 if( ms != gdcm::MediaStorage::RTStructureSetStorage ) return false;
478 gdcm::Attribute<0x8,0x60> modality;
479 modality.SetFromDataSet( ds );
480 if( modality.GetValue() != "RTSTRUCT" ) return false;
484 //----------------------------------------------------------------------------------------
486 mFile = new gdcm::File;
487 mFile->SetFileName(filename.c_str());
488 mFile->SetMaxSizeLoadEntry(16384); // Needed ...
489 mFile->SetLoadMode(gdcm::LD_NOSHADOW); // don't load shadow tags (in order to save memory)
493 //Verify if the file is a RT-Structure-Set dicom file
494 if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.481.3"))
496 if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0060),"RTSTRUCT"))
503 //--------------------------------------------------------------------
506 //--------------------------------------------------------------------
507 int clitk::DicomRT_StructureSet::AddBinaryImageAsNewROI(vvImage * im, std::string n)
509 // Search max ROI number
511 for(ROIConstIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
512 // for(unsigned int i=0; i<mListOfROI.size(); i++) {
513 clitk::DicomRT_ROI::Pointer roi = iter->second;
514 if (roi->GetROINumber() > max)
515 max = roi->GetROINumber();
520 std::ostringstream oss;
521 oss << vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(n));
522 mMapOfROIName[max] = oss.str();
525 std::vector<double> color;
531 DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
532 roi->SetFromBinaryImage(im, max, oss.str(), color, n);
536 //--------------------------------------------------------------------