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 //--------------------------------------------------------------------
122 //--------------------------------------------------------------------
123 void clitk::DicomRT_StructureSet::Print(std::ostream & os) const
125 os << "Study ID = " << mStudyID << std::endl
126 << "Study Date = " << mStudyDate << std::endl
127 << "Study Time = " << mStudyTime << std::endl
128 << "Struct Label = " << mLabel << std::endl
129 << "Struct Name = " << mName << std::endl
130 << "Struct Time = " << mTime << std::endl
131 << "Number of ROI = " << mROIs.size() << std::endl;
132 for(ROIConstIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
133 iter->second->Print(os);
136 //--------------------------------------------------------------------
139 #if GDCM_MAJOR_VERSION == 2
140 //--------------------------------------------------------------------
141 int clitk::DicomRT_StructureSet::ReadROINumber(const gdcm::Item & item)
143 // 0x3006,0x0022 = [ROI Number]
144 const gdcm::DataSet & nestedds = item.GetNestedDataSet();
145 gdcm::Attribute<0x3006,0x0022> roinumber;
146 roinumber.SetFromDataSet( nestedds );
147 return roinumber.GetValue();
149 //--------------------------------------------------------------------
152 //--------------------------------------------------------------------
153 void clitk::DicomRT_StructureSet::Write(const std::string & filename)
155 #if GDCM_MAJOR_VERSION == 2
158 // Assert that the gdcm file is still open (we can write only if it was readed)
160 //assert(mFile != NULL);
161 FATAL("Sorry, I can write DICOM only if it was read first from a file with 'Read' function");
164 // Loop and update each ROI
165 for(ROIIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
166 iter->second->UpdateDicomItem();
169 // Write [ Structure Set ROI Sequence ] = 0x3006,0x0020
170 gdcm::DataSet & ds = mFile->GetDataSet();
171 gdcm::Tag tssroisq(0x3006,0x0020);
172 const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq );
173 gdcm::DataElement de(ssroisq);
174 de.SetValue(*mROIInfoSequenceOfItems);
177 // Write [ ROI Contour Sequence ] = 0x3006,0x0039
179 gdcm::Tag troicsq(0x3006,0x0039);
180 const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
181 gdcm::DataElement de2(roicsq);
182 de2.SetValue(*mROIContoursSequenceOfItems);
186 gdcm::DataSet & a = mROIContoursSequenceOfItems->GetItem(1).GetNestedDataSet();
187 gdcm::Tag tcsq(0x3006,0x0040);
188 const gdcm::DataElement& csq = a.GetDataElement( tcsq );
189 gdcm::SmartPointer<gdcm::SequenceOfItems> sqi2 = csq.GetValueAsSQ();
190 gdcm::Item & j = sqi2->GetItem(1);
191 gdcm::DataSet & b = j.GetNestedDataSet();
192 gdcm::Attribute<0x3006,0x0050> at;
193 gdcm::Tag tcontourdata(0x3006,0x0050);
194 gdcm::DataElement contourdata = b.GetDataElement( tcontourdata );
195 at.SetFromDataElement( contourdata );
196 const double* points = at.GetValues();
202 //writer.CheckFileMetaInformationOff();
203 writer.SetFileName(filename.c_str());
204 writer.SetFile(*mFile);
209 FATAL("Sorry not compatible with GDCM1, use GDCM2");
212 //--------------------------------------------------------------------
215 //--------------------------------------------------------------------
216 void clitk::DicomRT_StructureSet::Read(const std::string & filename)
219 #if GDCM_MAJOR_VERSION == 2
221 mReader = new gdcm::Reader;
222 mReader->SetFileName(filename.c_str());
224 mFile = &(mReader->GetFile());
225 const gdcm::DataSet & ds = mFile->GetDataSet();
228 //Verify if the file is a RT-Structure-Set dicom file
229 gdcm::MediaStorage ms;
230 ms.SetFromFile(*mFile);
231 if( ms != gdcm::MediaStorage::RTStructureSetStorage )
233 std::cerr << "Error. the file " << filename
234 << " 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])"
239 gdcm::Attribute<0x8,0x60> modality;
240 modality.SetFromDataSet( ds );
241 if( modality.GetValue() != "RTSTRUCT" )
243 std::cerr << "Error. the file " << filename
244 << " is not a Dicom Struct ? (must have 0x0008,0x0060 = RTSTRUCT [RT Structure Set Storage])"
250 gdcm::Attribute<0x20,0x10> studyid;
251 studyid.SetFromDataSet( ds );
252 gdcm::Attribute<0x8,0x20> studytime;
253 studytime.SetFromDataSet( ds );
254 gdcm::Attribute<0x8,0x30> studydate;
255 studydate.SetFromDataSet( ds );
256 gdcm::Attribute<0x3006,0x02> label;
257 label.SetFromDataSet( ds );
258 gdcm::Attribute<0x3006,0x04> atname;
259 atname.SetFromDataSet( ds );
260 gdcm::Attribute<0x3006,0x09> time;
261 time.SetFromDataSet( ds );
263 mStudyID = studyid.GetValue();
264 mStudyTime = studytime.GetValue();
265 mStudyDate = studydate.GetValue();
266 mLabel = label.GetValue();
267 mName = atname.GetValue();
268 mTime = time.GetValue();
270 // Temporary store the list of items
271 std::map<int, gdcm::Item*> mMapOfROIInfo;
272 std::map<int, gdcm::Item*> mMapOfROIContours;
274 //----------------------------------
275 // Read all ROI Names and number
276 // 0x3006,0x0020 = [ Structure Set ROI Sequence ]
277 gdcm::Tag tssroisq(0x3006,0x0020);
278 const gdcm::DataElement &ssroisq = ds.GetDataElement( tssroisq );
279 mROIInfoSequenceOfItems = ssroisq.GetValueAsSQ();
280 gdcm::SmartPointer<gdcm::SequenceOfItems> & roi_seq = mROIInfoSequenceOfItems;
281 assert(roi_seq); // TODO error message
282 for(unsigned int ridx = 0; ridx < roi_seq->GetNumberOfItems(); ++ridx)
284 gdcm::Item & item = roi_seq->GetItem( ridx + 1); // Item starts at 1
285 const gdcm::DataSet& nestedds = item.GetNestedDataSet();
287 gdcm::Attribute<0x3006,0x26> roiname;
288 roiname.SetFromDataSet( nestedds );
289 std::string name = roiname.GetValue(); // 0x3006,0x0026 = [ROI Name]
291 // 0x3006,0x0022 = [ROI Number]
292 int nb = ReadROINumber(item);
295 mMapOfROIInfo[nb] = &item;
297 // Check if such a number already exist
298 if (mMapOfROIName.find(nb) != mMapOfROIName.end()) {
299 std::cerr << "WARNING. A Roi already exist with the number "
300 << nb << ". I replace." << std::endl;
303 mMapOfROIName[nb] = name;
306 //----------------------------------
308 // 0x3006,0x0039 = [ ROI Contour Sequence ]
309 gdcm::Tag troicsq(0x3006,0x0039);
310 const gdcm::DataElement &roicsq = ds.GetDataElement( troicsq );
311 gdcm::SmartPointer<gdcm::SequenceOfItems> roi_contour_seq = roicsq.GetValueAsSQ();
312 mROIContoursSequenceOfItems = roi_contour_seq;
313 assert(roi_contour_seq); // TODO error message
314 for(unsigned int ridx = 0; ridx < roi_contour_seq->GetNumberOfItems(); ++ridx) {
315 gdcm::Item & item = roi_contour_seq->GetItem( ridx + 1); // Item starts at 1
316 // ROI number [Referenced ROI Number]
317 const gdcm::DataSet& nestedds = item.GetNestedDataSet();
318 gdcm::Attribute<0x3006,0x0084> referencedroinumber;
319 referencedroinumber.SetFromDataSet( nestedds );
320 int nb = referencedroinumber.GetValue();
322 mMapOfROIContours[nb] = &item;
325 //----------------------------------
327 for(std::map<int, gdcm::Item*>::iterator i = mMapOfROIInfo.begin(); i != mMapOfROIInfo.end(); i++) {
328 int nb = i->first;//ReadROINumber(i);//mROIIndex[i];
330 DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
331 roi->Read(mMapOfROIInfo[nb], mMapOfROIContours[nb]);
332 // mListOfROI.push_back(roi);
333 // mMapOfROIIndex[nb] = i;
337 //----------------------------------------------------------------------------------------
338 //----------------------------------------------------------------------------------------
339 //----------------------------------------------------------------------------------------
341 mFile = new gdcm::File;
342 mFile->SetFileName(filename.c_str());
343 mFile->SetMaxSizeLoadEntry(16384); // Needed ...
344 mFile->SetLoadMode(gdcm::LD_NOSHADOW); // don't load shadow tags (in order to save memory)
348 //Verify if the file is a RT-Structure-Set dicom file
349 if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.481.3")) { //SOP clas UID
350 std::cerr << "Error. the file " << filename
351 << " 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])"
355 if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0060),"RTSTRUCT")) { //SOP clas UID
356 std::cerr << "Error. the file " << filename
357 << " is not a Dicom Struct ? (must have 0x0008,0x0060 = RTSTRUCT [RT Structure Set Storage])"
363 mStudyID = mFile->GetValEntry(0x0020,0x0010)->GetValue();
364 mStudyTime = mFile->GetValEntry(0x008,0x0020)->GetValue();
365 mStudyDate = mFile->GetValEntry(0x008,0x0030)->GetValue();
366 mLabel = mFile->GetValEntry(0x3006,0x002)->GetValue();
367 if (!mFile->GetValEntry(0x3006,0x004)) {
371 mName = mFile->GetValEntry(0x3006,0x004)->GetValue();
373 mTime = mFile->GetValEntry(0x3006,0x009)->GetValue();
375 //----------------------------------
376 // Read all ROI Names and number
377 // 0x3006,0x0020 = [ Structure Set ROI Sequence ]
378 gdcm::SeqEntry * roi_seq=mFile->GetSeqEntry(0x3006,0x0020);
379 assert(roi_seq); // TODO error message
380 for (gdcm::SQItem* r=roi_seq->GetFirstSQItem(); r!=0; r=roi_seq->GetNextSQItem()) {
381 std::string name = r->GetEntryValue(0x3006,0x0026); // 0x3006,0x0026 = [ROI Name]
382 int nb = atoi(r->GetEntryValue(0x3006,0x0022).c_str()); // 0x3006,0x0022 = [ROI Number]
383 // Check if such a number already exist
384 if (mMapOfROIName.find(nb) != mMapOfROIName.end()) {
385 std::cerr << "WARNING. A Roi already exist with the number "
386 << nb << ". I replace." << std::endl;
389 mMapOfROIName[nb] = name;
392 //----------------------------------
394 // 0x3006,0x0039 = [ ROI Contour Sequence ]
395 gdcm::SeqEntry * roi_contour_seq=mFile->GetSeqEntry(0x3006,0x0039);
396 assert(roi_contour_seq); // TODO error message
398 for (gdcm::SQItem* r=roi_contour_seq->GetFirstSQItem(); r!=0; r=roi_contour_seq->GetNextSQItem()) {
399 DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
400 roi->Read(mMapOfROIName, r);
401 mROIs[roi->GetROINumber()] = roi;
407 //--------------------------------------------------------------------
410 //--------------------------------------------------------------------
411 bool clitk::DicomRT_StructureSet::IsDicomRTStruct(const std::string & filename)
414 #if GDCM_MAJOR_VERSION == 2
416 mReader = new gdcm::Reader;
417 mReader->SetFileName(filename.c_str());
419 mFile = &(mReader->GetFile());
420 const gdcm::DataSet & ds = mFile->GetDataSet();
423 //Verify if the file is a RT-Structure-Set dicom file
424 gdcm::MediaStorage ms;
425 ms.SetFromFile(*mFile);
426 if( ms != gdcm::MediaStorage::RTStructureSetStorage ) return false;
428 gdcm::Attribute<0x8,0x60> modality;
429 modality.SetFromDataSet( ds );
430 if( modality.GetValue() != "RTSTRUCT" ) return false;
434 //----------------------------------------------------------------------------------------
436 mFile = new gdcm::File;
437 mFile->SetFileName(filename.c_str());
438 mFile->SetMaxSizeLoadEntry(16384); // Needed ...
439 mFile->SetLoadMode(gdcm::LD_NOSHADOW); // don't load shadow tags (in order to save memory)
443 //Verify if the file is a RT-Structure-Set dicom file
444 if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.481.3"))
446 if (!gdcm::Util::DicomStringEqual(mFile->GetEntryValue(0x0008,0x0060),"RTSTRUCT"))
453 //--------------------------------------------------------------------
456 //--------------------------------------------------------------------
457 int clitk::DicomRT_StructureSet::AddBinaryImageAsNewROI(vvImage * im, std::string n)
459 // Search max ROI number
461 for(ROIConstIteratorType iter = mROIs.begin(); iter != mROIs.end(); iter++) {
462 // for(unsigned int i=0; i<mListOfROI.size(); i++) {
463 clitk::DicomRT_ROI::Pointer roi = iter->second;
464 if (roi->GetROINumber() > max)
465 max = roi->GetROINumber();
470 std::ostringstream oss;
471 oss << vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(n));
472 mMapOfROIName[max] = oss.str();
475 std::vector<double> color;
481 DicomRT_ROI::Pointer roi = DicomRT_ROI::New();
482 roi->SetFromBinaryImage(im, max, oss.str(), color, n);
486 //--------------------------------------------------------------------