2 /*=========================================================================
5 Module: $RCSfile: exDicomRTStructSetFile.cxx,v $
7 Date: $Date: 2007/06/21 15:06:13 $
8 Version: $Revision: 1.2 $
10 Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
11 l'Image). All rights reserved. See Doc/License.txt or
12 http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
14 This software is distributed WITHOUT ANY WARRANTY; without even
15 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 PURPOSE. See the above copyright notices for more information.
18 =========================================================================*/
20 /* =================================================
21 * freely inspired from : clitkDicomRTIOCommon.cxx
22 * written by : Laurent ZAGNI
25 =================================================*/
30 //#include "gdcmValEntry.h"
31 #include "gdcmDataEntry.h"
33 #include "gdcmSeqEntry.h"
34 #include "gdcmSQItem.h"
35 #include "gdcmDocEntrySet.h"
36 #include "gdcmSerieHelper.h"
37 #include "gdcmDirList.h"
41 #define GetEntryValue(g,e) GetEntryString(g,e)
42 #define GetValEntry(g,e) GetDataEntry(g,e)
43 #define GetValue() GetString()
44 #define ValEntry DataEntry
45 #define InsertValEntry(a,b,c) InsertEntryString(a,b,c) // warning mind the VR!
48 #define itkGenericExceptionMacro(a) std::cout<<"===========================Exception "a<<std::endl;return false;
50 #include "gdcmArgMgr.h"
52 bool TestDicomRTStructSetFile(GDCM_NAME_SPACE::File* file);
53 bool TestDicomCTSerie(const GDCM_NAME_SPACE::FileList serie);
55 //====================================================================
57 //====================================================================
58 //In a dicom seq try to find an item with a gived tag/(int)value pair, else creates it
59 GDCM_NAME_SPACE::SQItem* GetAnItemWithTagValue(GDCM_NAME_SPACE::SeqEntry* seqEntry, const uint16_t group,
60 const uint16_t elem, const int value, const bool writeItem) {
62 std::stringstream valueStream;
64 std::string strValue = valueStream.str();
65 GDCM_NAME_SPACE::SQItem* curItem = seqEntry->GetFirstSQItem();
66 GDCM_NAME_SPACE::ValEntry* valEntry;
67 while (curItem != NULL) {
68 valEntry = curItem->GetValEntry(group,elem);
69 std::istringstream(valEntry->GetValue())>>foundValue;
70 if (foundValue == value) {
73 curItem = seqEntry->GetNextSQItem();
75 if (writeItem == true) {
76 unsigned int newItemNumber = seqEntry->GetNumberOfSQItems ();
78 //GDCM_NAME_SPACE::SQItem* newItem = new GDCM_NAME_SPACE::SQItem(seqEntry->GetDepthLevel()+1);
79 GDCM_NAME_SPACE::SQItem* newItem = GDCM_NAME_SPACE::SQItem::New(seqEntry->GetDepthLevel()+1);
81 seqEntry->AddSQItem(newItem,(int)newItemNumber);
82 newItem->InsertValEntry(strValue, group, elem); /// \TODO : si VR absent, le chercher dans le dict!
90 /* =================================================
91 * freely inspired from : clitkDicomRTIOCommon.cxx
92 * written by : Laurent ZAGNI
95 =================================================*/
96 // Test if a file list is a valid CT serie
98 bool TestDicomCTSerie(const GDCM_NAME_SPACE::FileList serie) {
100 if (serie.size() < 2) {
101 itkGenericExceptionMacro(<<"Serie must contain at least 2 files !");
104 float firstSliceImagePosition[3];
105 float currentSliceImagePosition[3];
107 GDCM_NAME_SPACE::FileList::const_iterator first = serie.begin();
108 GDCM_NAME_SPACE::FileList::const_iterator it = first ++;
110 bool res = (*first)->GetImageOrientationPatient(firstSliceImagePosition);
112 itkGenericExceptionMacro(<<"No ImagePositionPatient found;");
115 while (it != serie.end()) {
116 if (!GDCM_NAME_SPACE::Util::DicomStringEqual((*it)->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.2")) {
117 itkGenericExceptionMacro();
118 //CT Dicom slices must have a SOP Class UID [0008|0016] = [1.2.840.10008.5.1.4.1.1.2] ==> [CT Image Storage]
121 if (!GDCM_NAME_SPACE::Util::DicomStringEqual((*it)->GetEntryValue(0x0008,0x0060),"CT")) {
122 itkGenericExceptionMacro();
123 //CT Dicom slices must have a Modality [0008|0060] = [CT]
126 if (!GDCM_NAME_SPACE::Util::DicomStringEqual((*it)->GetEntryValue(0x0020,0x0037),"1.0000\\0.0000\\0.0000\\0.0000\\1.0000\\0.0000")) {
127 itkGenericExceptionMacro("CT Dicom slices must an Image Orientation [0020|0037]"
128 <<" = [1.0000\0.0000\0.0000\0.0000\1.0000\0.0000]");
131 res =(*it)->GetImageOrientationPatient(currentSliceImagePosition);
133 itkGenericExceptionMacro(<<"No ImagePositionPatient found;");
135 if ((firstSliceImagePosition[0] != currentSliceImagePosition[0])||(firstSliceImagePosition[1] != currentSliceImagePosition[1])){
136 itkGenericExceptionMacro("All CT Dicom slices must have same image position on x and y [0020|0032]");
139 if ((*it)->GetEntryValue(0x0028,0x0030) != (*first)->GetEntryValue(0x0028,0x0030).c_str()) {
140 itkGenericExceptionMacro("All CT Dicom slices must have same Pixel Spacing [0028|0030]");
143 if ((*it)->GetEntryValue(0x0028,0x0010) != (*first)->GetEntryValue(0x0028,0x0010).c_str()) {
144 itkGenericExceptionMacro("All CT Dicom slices must have same Rows number [0028|0010]");
147 if ((*it)->GetEntryValue(0x0028,0x0011) != (*first)->GetEntryValue(0x0028,0x0011).c_str()) {
148 itkGenericExceptionMacro("All CT Dicom slices must have same Columns number [0028|0011]");
151 if ((*it)->GetEntryValue(0x0018,0x0050) != (*first)->GetEntryValue(0x0018,0x0050).c_str()) {
152 itkGenericExceptionMacro("All CT Dicom slices must have same slice thickness [0018|0050]");
156 //it = serie.begin();
157 // while (it != serie.end()) {
158 // fileName = (*it)->GetFileName();
159 // std::cout << fileName << std::endl;
167 // -----------------------------------------------------------------------------------------------------------------
168 /* =================================================
169 * freely inspired from : clitkDicomRTIOCommon.cxx
170 * written by : Laurent ZAGNI
171 * on : 18 August 2006
173 =================================================*/
175 // Test if a file is a valid Dicom-RT Structure-Set file (readable by us)
176 bool TestDicomRTStructSetFile(GDCM_NAME_SPACE::File* file) {
178 //GDCM_NAME_SPACE::ValEntry* valEntry;
179 GDCM_NAME_SPACE::DataEntry* valEntry;
182 std::string exception0 = "Not a [RT Structure Set Storage]";
183 std::string exception1 = "2 or more different 'Roi Referenced Frame UID'!";
184 std::string exception2 = "No 'Series Instance UID'!";
185 std::string exception3 = "Modality not= RTSTRUCT";
187 //Verify if the file is a RT-Structure-Set dicom file
188 if (!GDCM_NAME_SPACE::Util::DicomStringEqual(file->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.481.3")) { //SOP clas UID
189 itkGenericExceptionMacro(<<exception0);
190 // (the file must have a SOP Class UID [0008|0016] = 1.2.840.10008.5.1.4.1.1.481.3 ==> [RT Structure Set Storage] !
193 if (!GDCM_NAME_SPACE::Util::DicomStringEqual(file->GetEntryValue(0x0008,0x0060),"RTSTRUCT")) { //SOP clas UID
194 itkGenericExceptionMacro(<<exception3);
195 // (the file must have a Modality tag = RTSTRUCT !
198 //Verify only one Referenced Frame UID and one or more Series UID
200 GDCM_NAME_SPACE::SeqEntry* seqEntry;
201 GDCM_NAME_SPACE::SQItem* currentItem;
202 std::string currentFrameRefUID;
204 seqEntry = file->GetSeqEntry(0x3006,0x0020); //Structure Set ROI sequence
205 if (seqEntry->GetNumberOfSQItems() > 1) {
206 currentItem = seqEntry->GetFirstSQItem();
207 valEntry = currentItem->GetValEntry(0x3006,0x0024); //Roi Frame of Reference UID
208 currentFrameRefUID = valEntry->GetValue();
209 currentItem = seqEntry->GetNextSQItem();
210 while (currentItem != NULL) {
211 valEntry = currentItem->GetValEntry(0x3006,0x0024); //Roi Frame of Reference UID
212 if (valEntry->GetValue() != currentFrameRefUID) {
213 // std::cout<<"..ref UID"<<currentFrameRefUID<<std::endl;
214 // std::cout<<"..new UID"<<valEntry->GetValue().c_str()<<std::endl;
215 // std::cout<<"..exception"<<std::endl;
216 itkGenericExceptionMacro(<<exception1);
218 currentItem = seqEntry->GetNextSQItem();
222 seqEntry = file->GetSeqEntry(0x3006,0x0010); //Referenced Frame of Reference Sequence
223 currentItem = seqEntry->GetFirstSQItem();
224 while (currentItem != NULL) {
225 valEntry = currentItem->GetValEntry(0x0020,0x0052); //Frame of Reference UID
226 if (valEntry->GetValue() == currentFrameRefUID) { //search for the ROI Frame of Reference UID
229 currentItem = seqEntry->GetNextSQItem();
232 if (currentItem == NULL) {
233 itkGenericExceptionMacro(<<exception1);
236 GDCM_NAME_SPACE::SeqEntry* seqEntry2 = currentItem->GetSeqEntry(0x3006,0x0012); //Referenced Study sequence
237 if (seqEntry2->GetNumberOfSQItems() < 1) {
238 itkGenericExceptionMacro(<<exception2);
241 valEntry = file->GetValEntry(0x0020,0x0010); //study ID
242 if ((valEntry == 0) || (valEntry->GetValue() == "")) { //(type 1 : mandatory attribute)
243 itkGenericExceptionMacro("RT-Structure-Set file must contain Study ID [0020|0010] !");
246 valEntry = file->GetValEntry(0x3006,0x002); //structure set label
247 if ((valEntry == 0) || (valEntry->GetValue() == "")) { //(type 1 : mandatory attribute)
248 itkGenericExceptionMacro("RT-Structure-Set file must contain Structure Set Label [0006|0002] !");
251 seqEntry = file->GetSeqEntry(0x3006,0x0020); //Structure Set ROI sequence
253 currentItem = seqEntry->GetFirstSQItem();
254 while (currentItem != NULL) {
255 valEntry = currentItem->GetValEntry(0x3006,0x0022); //Roi number
256 if ((valEntry == 0) || (valEntry->GetValue() == "")) { //(type 1 : mandatory attribute)
257 itkGenericExceptionMacro("All ROI in Structure Set Roi Sequence must contain Roi Number [3006|0022] !");
259 currentItem = seqEntry->GetNextSQItem();
263 seqEntry = file->GetSeqEntry(0x3006,0x0080); //ROI Observation sequence
264 if (seqEntry == 0) { //(type 1 : mandatory attribute)
265 itkGenericExceptionMacro("RT-Structure-Set file must contain ROI Observations Sequence [3006|0080] !");
268 seqEntry = file->GetSeqEntry(0x3006,0x0039); //ROI Contour sequence
269 if (seqEntry == 0) { //(type 1 : mandatory attribute)
270 itkGenericExceptionMacro("RT-Structure-Set file must contain ROI Contour Sequence [3006|0039] !");
272 std::cout<<"..."<<file->GetFileName()<<" is a valid DICOM RT-Structure-Set file"<<std::endl;
275 // -------------------------------------------------------------------------------------------------------
277 int main(int argc, char *argv[])
280 "\n exExtractCSA :\n ",
281 "Extracts and displays the CSA tag(s) of gdcm-parsable Dicom file ",
283 "usage: exExtractCSA {filein=inputFileName|dirin=inputDirectoryName} ",
284 " tmp=temporaryWorkFileName ",
285 " [extract=listOfElementsToExtract] ",
286 " [ { [noshadowseq] | [noshadow][noseq] } ] [debug] ",
287 " inputFileName : Name of the (single) file user wants to anonymize ",
288 " listOfElementsExtract : group-elem,g2-e2,... (in hexa, no space) ",
289 " of Elements to extract ",
290 " default : 0029-1210,0029-1220 ",
291 " noshadowseq: user doesn't want to load Private Sequences ",
292 " noshadow : user doesn't want to load Private groups (odd number) ",
293 " noseq : user doesn't want to load Sequences ",
294 " verbose : developper wants to run the program in 'verbose mode' ",
295 " debug : developper wants to run the program in 'debug mode' ",
298 // ----- Initialize Arguments Manager ------
300 GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv);
302 if (am->ArgMgrDefined("usage") || argc == 1)
304 am->ArgMgrUsage(usage); // Display 'usage'
309 if (am->ArgMgrDefined("debug"))
310 GDCM_NAME_SPACE::Debug::DebugOn();
312 bool verbose = am->ArgMgrDefined("verbose");
314 const char *fileName = am->ArgMgrGetString("filein");
316 /* if unused Param we give up */
317 if ( am->ArgMgrPrintUnusedLabels() )
319 am->ArgMgrUsage(usage);
323 delete am; // ------ we don't need Arguments Manager any longer ------
325 // ============================================================
326 // Read the input image.
327 // ============================================================
329 GDCM_NAME_SPACE::File *f = GDCM_NAME_SPACE::File::New( );
331 //f->SetLoadMode(GDCM_NAME_SPACE::LD_NOSEQ | GDCM_NAME_SPACE::LD_NOSHADOW);
332 f->SetFileName( fileName );
333 f->SetMaxSizeLoadEntry(0xffff);
334 bool res = f->Load();
336 if( GDCM_NAME_SPACE::Debug::GetDebugFlag())
338 std::cout << "---------------------------------------------" << std::endl;
340 std::cout << "---------------------------------------------" << std::endl;
343 std::cerr << "Sorry, " << fileName << " not a gdcm-readable "
344 << "DICOM / ACR File"
349 std::cout << " ... is readable " << std::endl;
352 TestDicomRTStructSetFile(f);
353 std::cout << " ... is readable " << std::endl;