]> Creatis software - gdcm.git/blob - Example/exExplorePresentationState.cxx
Add some explanations
[gdcm.git] / Example / exExplorePresentationState.cxx
1  
2  /*=========================================================================
3                                                                                 
4   Program:   gdcm
5   Module:    $RCSfile: exExplorePresentationState.cxx,v $
6   Language:  C++
7   Date:      $Date: 2010/09/01 14:40:00 $
8   Version:   $Revision: 1.1 $
9                                                                                 
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.
13                                                                                 
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.
17                                                                                 
18 =========================================================================*/
19
20 #include "gdcmFile.h"
21
22 #include "gdcmArgMgr.h"
23
24 #include "gdcmSeqEntry.h"
25 #include "gdcmSQItem.h"
26 #include "gdcmDocEntrySet.h"
27 //#include "gdcmSerieHelper.h"
28 #include "gdcmDirList.h"
29 #include "gdcmUtil.h"
30
31 typedef struct {
32        // 0020|0013 [IS]  [Instance Number]
33        std::string referencedInstanceNumber;
34        // 0004|1500 [CS] [Referenced File ID]
35        std::string referencedFileName;
36 } FILEINFO;
37
38
39   GDCM_NAME_SPACE::SeqEntry *CheckIfSequenceExists(GDCM_NAME_SPACE::File *fPS,  uint16_t gr, uint16_t el);
40   GDCM_NAME_SPACE::SeqEntry *CheckIfSequenceExists(GDCM_NAME_SPACE::SQItem *si, uint16_t gr, uint16_t el); 
41   bool dealWithCurrentFile(const char *PSName);
42   bool dealWithTopLevelItem(GDCM_NAME_SPACE::SQItem* currentItem);
43   bool dealWithEndLevelItem(GDCM_NAME_SPACE::SQItem* currentItem);
44   void displaySeekResult(GDCM_NAME_SPACE::SeqEntry* currentItem, uint16_t g, uint16_t e);
45   bool dealWithSequence(GDCM_NAME_SPACE::SeqEntry* se);
46   std::string dealWithReferencedFile(GDCM_NAME_SPACE::SQItem *si);
47   std::map<std::string, FILEINFO> dealWithDicomDir(const char *dicomdirname);
48     
49 bool verbose;
50 bool PSNameAlreadyShown;
51 std::map<std::string, FILEINFO> m;
52 std::string currentPSFileName;
53
54    
55 int main(int argc, char *argv[])
56 {
57    START_USAGE(usage)
58    "\n exExplorePresentationState :\n    ",
59    FINISH_USAGE
60    
61
62    // ----- Initialize Arguments Manager ------
63   
64    GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv);
65   
66    if (am->ArgMgrDefined("usage") || argc == 1) 
67    {
68       am->ArgMgrUsage(usage); // Display 'usage'
69       delete am;
70       return 0;
71    }
72    
73    if (am->ArgMgrDefined("debug"))
74       GDCM_NAME_SPACE::Debug::DebugOn();
75
76    /*bool */verbose = am->ArgMgrDefined("verbose");
77    bool rec  = ( 0 != am->ArgMgrDefined("rec") );
78       
79    const char *dirName  = am->ArgMgrGetString("dirin");
80    const char *dicomdirname = am->ArgMgrGetString("dicomdir");
81       
82    /* if unused Param we give up */
83    if ( am->ArgMgrPrintUnusedLabels() )
84    {
85       am->ArgMgrUsage(usage);
86       delete am;
87       return 0;
88    }  
89    delete am;  // ------ we don't need Arguments Manager any longer ------
90    
91      // ===========================================================================
92      // ========================= Deal with the relevant DICOMDIR =================
93      // ===========================================================================
94    
95    
96       /*std::map<std::string, std::string> */ m = dealWithDicomDir(dicomdirname);   
97
98      // ===========================================================================
99      // ========================= Deal with the Directory holding DICOM images   ==
100      // ===========================================================================
101
102       std::cout << " Image Directory Name [" << dirName << "]\n\n" << std::endl;
103       
104       GDCM_NAME_SPACE::DirList dirList(dirName,rec); // gets recursively (or not) the file list
105       GDCM_NAME_SPACE::DirListType fileList = dirList.GetFilenames();
106       GDCM_NAME_SPACE::File *f;
107       bool res;
108
109       if (fileList.size() == 0)
110       {
111          std::cout << "No file found in : [" << dirName << "]" << std::endl;
112       }
113       
114       for( GDCM_NAME_SPACE::DirListType::iterator it  = fileList.begin();
115                                  it != fileList.end();
116                                  ++it )
117       {
118       
119          currentPSFileName = it->c_str();
120          if (verbose)
121             std::cout << std::endl<<" Start processing :[" << it->c_str() << "]"
122                       << std::endl;
123          f = GDCM_NAME_SPACE::File::New();
124          //f->SetLoadMode(loadMode);
125          f->SetFileName( it->c_str() );
126  
127          res = f->GDCM_NAME_SPACE::Document::Load();
128
129          if ( !res )
130          {
131             if (verbose)
132             { 
133                std::cout << "Cannot process file [" << it->c_str() << "]" 
134                          << std::endl;
135                std::cout << "Either it doesn't exist, or it's read protected " 
136                          << std::endl;
137                std::cout << "or it's not a Dicom File, or its 'header' is bugged" 
138                          << std::endl;
139                std::cout << "use 'PrintFile filein=... debug' "
140                          << "to try to guess the pb"
141                          << std::endl;
142             }
143             f->Delete();
144             continue;
145          }
146  
147          bool resFile = dealWithCurrentFile(it->c_str());
148          if (verbose)
149            std::cout << "\n\n"  <<std::endl;
150          //std::cout << "=====================================================[" <<  it->c_str() << "]==" << resFile << std::endl;
151          //return resFile;
152  
153          continue;
154  
155       }
156 }
157
158
159
160 //----------------------------------------------------------------------------------------------------
161 bool dealWithCurrentFile(const char *PSName)
162 {
163
164    GDCM_NAME_SPACE::File *fPS = GDCM_NAME_SPACE::File::New( );
165    fPS->SetFileName( PSName );
166    fPS->SetMaxSizeLoadEntry(0xffff);
167    bool res2 = fPS->Load();
168            
169    if (!res2) {
170       if (verbose)
171           std::cout << "Sorry, " << PSName << " not a gdcm-readable "
172                     << "DICOM / ACR File"
173                     << std::endl;
174       fPS->Delete();
175       return false;
176    }
177    
178    GDCM_NAME_SPACE::SeqEntry *se;
179    
180    se = CheckIfSequenceExists( fPS, 0x0070, 0x0001);
181    //displaySeekResult(se, 0x0070, 0x0001);
182    if (!se)
183    {
184          if (verbose)
185             std::cout << "[" << PSName << "] : Hopeless (" << std::hex <<  0x0070 << "|" << 0x0001 << std::dec << " doesn't exist...)" <<std::endl;
186          return false;      
187    }
188    
189    if (verbose){   
190       std::cout << "\n\n =========================================================================================" <<std::endl;       
191       std::cout << "[" << PSName << "] is a gdcm-readable PresentationState file, "
192                 << "that (probabely?) holds one or more 'ROI' within [0070|0001] (Graphic Annotation Sequence)"   <<std::endl; 
193       std::cout << " =========================================================================================\n\n" <<std::endl;
194    }
195    GDCM_NAME_SPACE::SQItem* currentItem = se->GetFirstSQItem(); // Get the first 'ROI'
196    if (currentItem == NULL)
197    {
198       if (verbose)
199          std::cout << "======== Deal With NOTHING! (Sequence 0070|0001 [Graphic Annotation Sequence] has NO item ?!?) within " 
200                  << PSName << "]" << std::endl;
201       return false;
202    }
203    int i =0;
204    bool res3;
205    bool finalRes = false;
206    while (currentItem != NULL)
207    {
208       if (verbose)
209         std::cout << "======== Deal With 'ROI' n." << i << std::endl;
210
211         // do what you want with the current 'ROI'
212          res3 = dealWithTopLevelItem(currentItem);
213        if (res3)
214          finalRes = true;
215         //...
216
217         currentItem = se->GetNextSQItem(); // Get the next 'ROI'
218         i++;
219    }
220
221    if (finalRes)
222       std::cout << "=============================(within PS File :[" <<  PSName << "]\n\n" << std::endl;   
223    fPS->Delete();
224    
225    if(verbose)
226       std::cout << "\n\n"  <<std::endl;
227    return true;
228 }
229  
230 //----------------------------------------------------------------------------------------------------
231  
232 bool dealWithTopLevelItem(GDCM_NAME_SPACE::SQItem* currentItem)
233 {
234   // probably this list should be cleaned up.
235   // (I didn't find the exact architecture of Presentation State)
236    int tabElement[] = {         0x0008, 0x0009, 0x005a, 0x0060, 0x0086, 
237                         0x0308, 0x0309, 0x030A, 0x030d, 0x0311, 0x0314, 
238                         0x0318, 0x031c, 0x031e, 0x0402, 0x0404, 0x0000 };
239
240    bool finalRes = false;
241    bool res;
242    GDCM_NAME_SPACE::SeqEntry *se;
243
244    se = CheckIfSequenceExists(currentItem, 0x0008, 0x1140);
245    displaySeekResult(se, 0x0008, 0x1140); 
246    if (se != 0)
247    {
248       res = dealWithSequence(se);
249       if (!res)
250          return false;
251    }
252    
253    for(int i=0; tabElement[i]!=0x0000; i++)
254    {
255       se = CheckIfSequenceExists(currentItem, 0x0070, tabElement[i]);
256       //displaySeekResult(se, 0x0070, tabElement[i]);       
257       if (se != 0)
258       {
259          res = dealWithSequence(se);
260          if (res)
261             finalRes = true;
262       }
263    } 
264    return (finalRes);
265 }
266
267
268 //----------------------------------------------------------------------------------------------------
269  
270 bool dealWithEndLevelItem(GDCM_NAME_SPACE::SQItem* currentItem)
271 {
272   // probably this list should be cleaned up, too.
273   // (I didn't find the exact architecture of Presentation State)
274    int tabElement[] = {         0x0008, 0x0009, 0x005a, 0x0060, 0x0086, 
275                         0x0308, 0x0309, 0x030A, 0x030d, 0x0311, 0x0314, 
276                         0x0318, 0x031c, 0x031e, 0x0402, 0x0404, 0x0000 };
277
278    bool res = false;
279    GDCM_NAME_SPACE::SeqEntry *se;
280
281    se = CheckIfSequenceExists(currentItem, 0x0008, 0x1140);
282    displaySeekResult(se, 0x0008, 0x1140); 
283    if (se != 0)
284    {
285       res = true;
286       dealWithSequence(se);
287    }
288
289    for(int i=0; tabElement[i]!=0x0000; i++)
290    {
291       se = CheckIfSequenceExists(currentItem, 0x0070, tabElement[i]);
292       displaySeekResult(se, 0x0070, tabElement[i]);       
293       if (se != 0)
294       {
295          res = true;
296          dealWithSequence(se);
297       }
298    } 
299    return (res);
300 }
301 //----------------------------------------------------------------------------------------------------
302
303 bool dealWithSequence(GDCM_NAME_SPACE::SeqEntry* se)
304 {    
305    uint16_t g = se->GetGroup();
306    uint16_t e = se->GetElement();
307    if (verbose)  
308       std::cout << std::hex << "\n------------------------ deal with " << g <<"|" << e <<  std::dec 
309                 << "  " << se->GetName() << std::endl;
310
311    GDCM_NAME_SPACE::SQItem *si = se->GetFirstSQItem();
312    if (!si) {
313       if (verbose)
314          std::cout << "Sequence " << std::hex << g <<"|" << e <<  std::dec <<  "has no Item ?!?" << std::endl;
315       return false;
316    }
317    std::string referencedFileUID;
318    //std::cout << "\n============================== [" << currentPSFileName << "] =================" << std::endl;  
319    if (g == 0x0008) {
320       if (verbose)
321          si->Print(std::cout);
322       referencedFileUID = dealWithReferencedFile(si);
323 //      std::cout << "   referencedFile UID[" << referencedFileUID <<"]" << std::endl;
324       
325    } else if (g == 0x0070) {
326       if (verbose)   
327          si->Print(std::cout);   
328    } else {
329         if (verbose)
330            std::cout << "Unexpected Group " << std::hex << g << std::hex << std::endl;
331    }
332    
333    si =  se->GetNextSQItem();
334    if (si)
335    {
336       if (verbose)
337          std::cout << "Sequence " << std::hex << g <<"|" << e <<  std::dec <<  "should have only ONE Item ?!?" << std::endl;
338      // if (verbose)  
339      //    si->Print(std::cout);
340       return false;
341    }
342    return true;
343 }
344
345 //----------------------------------------------------------------------------------------------------
346
347 void displaySeekResult(GDCM_NAME_SPACE::SeqEntry* se, uint16_t g, uint16_t e)
348 {  
349       if (se)
350       {
351         // std::cout << std::hex <<  g << "|" << e << std::dec << " [" << se->GetName() << "] exists" <<std::endl;
352       }
353       else
354       {
355          if (verbose)
356             std::cout << " No " << std::hex <<  g << "|" << e << std::dec << " found" <<std::endl;
357       }
358 }
359       
360 //----------------------------------------------------------------------------------------------------  
361
362 bool TestPresentationState(GDCM_NAME_SPACE::File *f, GDCM_NAME_SPACE::File *fPS)
363 {
364
365 /*------------------------------------------------------
366
367 0070 0001 SQ 1 Graphic Annotation Sequence
368 0070 0008 SQ 1 Text Object Sequence
369 0070 0009 SQ 1 Graphic Object Sequence
370 0070 005a SQ 1 Displayed Area Selection Sequence
371 0070 0060 SQ 1 Graphic Layer Sequence
372 0070 0086 SQ 1 Content Creator's Identification Code Sequence
373 0070 0308 SQ 1 Registration Sequence
374 0070 0309 SQ 1 Matrix Registration Sequence
375 0070 030a SQ 1 Matrix Sequence
376 0070 030d SQ 1 Registration Type Code Sequence
377 0070 0311 SQ 1 Fiducial Identifier Code Sequence
378 0070 0314 SQ 1 Used Fiducials Sequence
379 0070 0318 SQ 1 Graphic Coordinates Data Sequence
380 0070 031c SQ 1 Fiducial Set Sequence
381 0070 031e SQ 1 Fiducial Sequence
382 0070 0402 SQ 1 Blending Sequence
383 0070 0404 SQ 1 Referenced Spatial Registration Sequence
384 ------------------------------------------------------- */
385
386 /*------------------------------------------------------
387 Relevant part of Dicom V3 Dict
388
389 0070 0000 UL 1 Group Length
390 0070 0001 SQ 1 Graphic Annotation Sequence
391 0070 0002 CS 1 Graphic Layer
392 0070 0003 CS 1 Bounding Box Annotation Units
393 0070 0004 CS 1 Anchor Point Annotation Units
394 0070 0005 CS 1 Graphic Annotation Units
395 0070 0006 ST 1 Unformatted Text Value
396 0070 0008 SQ 1 Text Object Sequence
397 0070 0009 SQ 1 Graphic Object Sequence
398 0070 0010 FL 2 Bounding Box Top Left Hand Corner
399 0070 0011 FL 2 Bounding Box Bottom Right Hand Corner
400 0070 0012 CS 1 Bounding Box Text Horizontal Justification
401 0070 0014 FL 2 Anchor Point
402 0070 0015 CS 1 Anchor Point Visibility
403 0070 0020 US 1 Graphic Dimensions
404 0070 0021 US 1 Number of Graphic Points
405 0070 0022 FL 2-2n Graphic Data
406 0070 0023 CS 1 Graphic Type
407 0070 0024 CS 1 Graphic Filled
408 0070 0041 CS 1 Image Horizontal Flip
409 0070 0042 US 1 Image Rotation
410 0070 0052 SL 2 Displayed Area Top Left Hand Corner
411 0070 0053 SL 2 Displayed Area Bottom Right Hand Corner
412 0070 005a SQ 1 Displayed Area Selection Sequence
413 0070 0060 SQ 1 Graphic Layer Sequence
414 0070 0062 IS 1 Graphic Layer Order
415 0070 0066 US 1 Graphic Layer Recommended Display Grayscale Value
416 0070 0067 US 3 Graphic Layer Recommended Display RGB Value (RET)
417 0070 0068 LO 1 Graphic Layer Description
418 0070 0080 CS 1 Content Label
419 0070 0081 LO 1 Content Description
420 0070 0082 DA 1 Presentation Creation Date
421 0070 0083 TM 1 Presentation Creation Time
422 0070 0084 PN 1 Content Creator's Name
423 0070 0086 SQ 1 Content Creator's Identification Code Sequence
424 0070 0100 CS 1 Presentation Size Mode
425 0070 0101 DS 2 Presentation Pixel Spacing
426 0070 0102 IS 2 Presentation Pixel Aspect Ratio
427 0070 0103 FL 1 Presentation Pixel Magnification Ratio
428 0070 0306 CS 1 Shape Type
429 0070 0308 SQ 1 Registration Sequence
430 0070 0309 SQ 1 Matrix Registration Sequence
431 0070 030a SQ 1 Matrix Sequence
432 0070 030c CS 1 Frame of Reference Transformation Matrix Type
433 0070 030d SQ 1 Registration Type Code Sequence
434 0070 030f ST 1 Fiducial Description
435 0070 0310 SH 1 Fiducial Identifier
436 0070 0311 SQ 1 Fiducial Identifier Code Sequence
437 0070 0312 FD 1 Contour Uncertainty Radius
438 0070 0314 SQ 1 Used Fiducials Sequence
439 0070 0318 SQ 1 Graphic Coordinates Data Sequence
440 0070 031a UI 1 Fiducial UID
441 0070 031c SQ 1 Fiducial Set Sequence
442 0070 031e SQ 1 Fiducial Sequence
443 0070 0401 US 3 Graphic Layer Recommended Display CIELab Value
444 0070 0402 SQ 1 Blending Sequence
445 0070 0403 FL 1 Relative Opacity
446 0070 0404 SQ 1 Referenced Spatial Registration Sequence
447 0070 0405 CS 1 Blending Position
448 ------------------------------------------------------- */
449
450 }
451
452 // ----------------------------------------------------------------------------------
453
454
455 GDCM_NAME_SPACE::SeqEntry *CheckIfSequenceExists( GDCM_NAME_SPACE::File *fPS, uint16_t gr, uint16_t el)
456 {
457    GDCM_NAME_SPACE::SeqEntry *se= fPS->GetSeqEntry(gr, el);
458    return se;     
459 }
460
461 // ----------------------------------------------------------------------------------
462   
463 GDCM_NAME_SPACE::SeqEntry *CheckIfSequenceExists( GDCM_NAME_SPACE::SQItem *si, uint16_t gr, uint16_t el)
464 {
465    GDCM_NAME_SPACE::SeqEntry *se= si->GetSeqEntry(gr, el);
466    return se;     
467 }
468
469 // ----------------------------------------------------------------------------------
470
471 std::string dealWithReferencedFile(GDCM_NAME_SPACE::SQItem *si)
472 {
473   // GDCM_NAME_SPACE::DocEntry *si = GetDocEntry(0x0008, 0x1155);
474   
475   // Look for : 0004|1511  [UI]  [Referenced SOP Instance UID in File]  
476   std::string referencedFileUID = si->GetEntryString(0x0008, 0x1155);
477   // std::cout << "   referencedFile UID[" << referencedFileUID <<"]" << std::endl;
478       
479   if (verbose)
480      std::cout << "m[" << referencedFileUID << "] = ";
481
482   std::cout << "[" << m[referencedFileUID].referencedInstanceNumber << "] [" << m[referencedFileUID].referencedFileName << "]" << std::endl;
483
484   return referencedFileUID;
485    
486 }  
487
488 // ----------------------------------------------------------------------------------
489 std::map<std::string, FILEINFO> dealWithDicomDir(const char *dicomdirname)
490 {
491    FILEINFO fi;
492    GDCM_NAME_SPACE::File *f;
493    bool res;
494    std::map<std::string, FILEINFO> m;
495          
496          std::cout << std::endl<<" Start reading DICOMDIR :[" << dicomdirname << "]"
497                    << std::endl;
498    
499          f = GDCM_NAME_SPACE::File::New();
500          //f->SetLoadMode(loadMode);
501          f->SetFileName( dicomdirname );
502  
503          // Don't load a DicomDir !
504          res = f->GDCM_NAME_SPACE::Document::Load();
505
506          if ( !res )
507          {
508             std::cout << "Cannot process file [" << dicomdirname << "]" 
509                       << std::endl;
510             std::cout << "Either it doesn't exist, or it's read protected " 
511                       << std::endl;
512             std::cout << "or it's not a Dicom File, or its 'header' is bugged" 
513                       << std::endl;
514             std::cout << "use 'PrintFile filein=... debug' "
515                       << "to try to guess the pb"
516                       << std::endl;
517             f->Delete();
518             /// \TODO : throw an exception
519             return m;;
520          }
521
522    // Get 0004|1220 [SQ]  [Directory Record Sequence]
523    
524    GDCM_NAME_SPACE::SeqEntry *dsr= f->GetSeqEntry(0x0004,0x1220);
525    if (!dsr)
526    {
527          if (verbose)
528             std::cout << "[" << dicomdirname << "] : Hopeless (" << std::hex <<  0x0094 << "|" << 0x01220 
529                     << std::dec << " -Directory Record Sequence- doesn't exist...)" <<std::endl;
530
531          f->Delete();
532        /// \TODO : throw an exception
533          return m;      
534    }
535
536    GDCM_NAME_SPACE::SQItem* currentItem = dsr->GetFirstSQItem(); // Get the first 'ROI'
537    if (currentItem == NULL)
538    {
539       if (verbose)
540          std::cout << "======== Deal With NOTHING! (Sequence 0004|1220 [Directory Record Sequence] has NO item ?!?)" << std::endl;
541        /// \TODO : throw an exception
542          return m;   
543    }
544   
545    int i =0;
546    while (currentItem != NULL)
547    {
548        // Get 0020|0013 [IS]  [Instance Number]
549        fi.referencedInstanceNumber = currentItem->GetEntryString(0x0020, 0x0013);
550   
551        // Get 0004|1500 [CS] [Referenced File ID]
552        fi.referencedFileName = currentItem->GetEntryString(0x0004, 0x1500);
553
554        // Get0004|1511 [UI] [Referenced SOP Instance UID in File] 
555        std::string referencedFileSopInstanceUID = currentItem->GetEntryString(0x0004, 0x1511);
556
557        m[referencedFileSopInstanceUID] = fi;
558        currentItem = dsr->GetNextSQItem(); // Get the next 'ROI'
559        i++;
560    }
561
562    if (verbose)   
563       for(std::map<std::string, FILEINFO>::iterator it = m.begin(); it != m.end(); ++it)
564       {
565          std::cout << "m[" << (*it).first << "] = [" << (*it).second.referencedInstanceNumber << "] ["  << (*it).second.referencedFileName << std::endl;
566       }
567  
568  return m;  
569
570 }