]> Creatis software - gdcm.git/commitdiff
First (dirty) version of a Dicom RT checker
authorjpr <jpr>
Mon, 18 Jun 2007 12:02:54 +0000 (12:02 +0000)
committerjpr <jpr>
Mon, 18 Jun 2007 12:02:54 +0000 (12:02 +0000)
Don't use right now!

Example/exDicomRTStructSetFile.cxx [new file with mode: 0755]

diff --git a/Example/exDicomRTStructSetFile.cxx b/Example/exDicomRTStructSetFile.cxx
new file mode 100755 (executable)
index 0000000..edd10d7
--- /dev/null
@@ -0,0 +1,360 @@
+ /*=========================================================================
+                                                                                
+  Program:   gdcm
+  Module:    $RCSfile: exDicomRTStructSetFile.cxx,v $
+  Language:  C++
+  Date:      $Date: 2007/06/18 12:02:54 $
+  Version:   $Revision: 1.1 $
+                                                                                
+  Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
+  l'Image). All rights reserved. See Doc/License.txt or
+  http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
+                                                                                
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+                                                                                
+=========================================================================*/
+
+  /* =================================================
+   * freely inspired from : clitkDicomRTIOCommon.cxx
+   * written by : Laurent ZAGNI
+   * on : 18 August 2006
+   * 
+   =================================================*/
+   
+    
+#include "gdcmFile.h"
+// ----------
+//#include "gdcmValEntry.h"
+#include "gdcmDataEntry.h"
+// ----------
+#include "gdcmSeqEntry.h"
+#include "gdcmSQItem.h"
+#include "gdcmDocEntrySet.h"
+#include "gdcmSerieHelper.h"
+#include "gdcmDirList.h"
+#include "gdcmUtil.h"
+
+// ---------- 
+#define GetEntryValue(g,e) GetEntryString(g,e)
+#define GetValEntry(g,e)   GetDataEntry(g,e)
+#define GetValue()         GetString()
+#define ValEntry           DataEntry
+#define InsertValEntry(a,b,c) InsertEntryString(a,b,c) // warning mind the VR!
+// ----------
+
+#define itkGenericExceptionMacro(a) std::cout<<"===========================Exception "a<<std::endl;return false;
+
+#include "gdcmArgMgr.h" 
+bool TestDicomRTStructSetFile(gdcm::File* file); 
+bool TestDicomCTSerie(const gdcm::FileList serie);
+
+  //====================================================================
+  
+  //====================================================================
+  //In a dicom seq try to find an item with a gived tag/(int)value pair, else creates it
+  gdcm::SQItem* GetAnItemWithTagValue(gdcm::SeqEntry* seqEntry, const uint16_t group, 
+      const uint16_t elem, const int value, const bool writeItem) {
+    int foundValue;
+    std::stringstream valueStream;
+    valueStream<<value;
+    std::string strValue = valueStream.str();
+    gdcm::SQItem* curItem = seqEntry->GetFirstSQItem();
+    gdcm::ValEntry* valEntry;
+    while (curItem != NULL) {
+      valEntry = curItem->GetValEntry(group,elem);
+      std::istringstream(valEntry->GetValue())>>foundValue;
+      if (foundValue == value) {
+         return curItem;
+      }
+      curItem = seqEntry->GetNextSQItem();
+    }
+    if (writeItem == true) {
+      unsigned int newItemNumber = seqEntry->GetNumberOfSQItems ();
+// ----------       
+      //gdcm::SQItem* newItem = new gdcm::SQItem(seqEntry->GetDepthLevel()+1);
+       gdcm::SQItem* newItem = gdcm::SQItem::New(seqEntry->GetDepthLevel()+1);
+// ---------- 
+      seqEntry->AddSQItem(newItem,(int)newItemNumber);
+      newItem->InsertValEntry(strValue, group, elem);  /// \TODO : si VR absent, le chercher dans le dict!
+      return newItem;
+    } else {
+      return NULL;
+    }
+  }  
+  
+
+  /* =================================================
+   * freely inspired from : clitkDicomRTIOCommon.cxx
+   * written by : Laurent ZAGNI
+   * on : 18 August 2006
+   * 
+   =================================================*/
+  // Test if a file list is  a valid CT serie
+       
+  bool TestDicomCTSerie(const gdcm::FileList serie) {
+  
+    if (serie.size() < 2) {
+      itkGenericExceptionMacro(<<"Serie must contain at least 2 files !");
+    }
+    
+    float firstSliceImagePosition[3];
+    float currentSliceImagePosition[3];    
+    
+    gdcm::FileList::const_iterator first = serie.begin();
+    gdcm::FileList::const_iterator it = first ++;
+    
+    bool res = (*first)->GetImageOrientationPatient(firstSliceImagePosition);
+    if (!res) {
+       itkGenericExceptionMacro(<<"No ImagePositionPatient found;");
+    }
+    
+    while (it != serie.end()) {
+      if (!gdcm::Util::DicomStringEqual((*it)->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.2")) {
+           itkGenericExceptionMacro();
+           //CT Dicom slices must have a SOP Class UID [0008|0016] = [1.2.840.10008.5.1.4.1.1.2] ==> [CT Image Storage]
+      }
+      
+      if (!gdcm::Util::DicomStringEqual((*it)->GetEntryValue(0x0008,0x0060),"CT")) {
+        itkGenericExceptionMacro();
+       //CT Dicom slices must have a Modality [0008|0060] = [CT]
+      }
+      
+      if (!gdcm::Util::DicomStringEqual((*it)->GetEntryValue(0x0020,0x0037),"1.0000\\0.0000\\0.0000\\0.0000\\1.0000\\0.0000")) {
+         itkGenericExceptionMacro("CT Dicom slices must an Image Orientation [0020|0037]"
+         <<" = [1.0000\0.0000\0.0000\0.0000\1.0000\0.0000]");  
+      }
+      
+      res =(*it)->GetImageOrientationPatient(currentSliceImagePosition);
+      if (!res) {
+         itkGenericExceptionMacro(<<"No ImagePositionPatient found;");
+      }
+      if ((firstSliceImagePosition[0] != currentSliceImagePosition[0])||(firstSliceImagePosition[1] != currentSliceImagePosition[1])){
+         itkGenericExceptionMacro("All CT Dicom slices must have same image position on x and y [0020|0032]");      
+      }
+      
+      if ((*it)->GetEntryValue(0x0028,0x0030) != (*first)->GetEntryValue(0x0028,0x0030).c_str()) {
+        itkGenericExceptionMacro("All CT Dicom slices must have same Pixel Spacing [0028|0030]");
+      }
+      
+      if ((*it)->GetEntryValue(0x0028,0x0010) != (*first)->GetEntryValue(0x0028,0x0010).c_str()) {
+         itkGenericExceptionMacro("All CT Dicom slices must have same Rows number [0028|0010]");      
+      }
+      
+      if ((*it)->GetEntryValue(0x0028,0x0011) != (*first)->GetEntryValue(0x0028,0x0011).c_str()) {
+         itkGenericExceptionMacro("All CT Dicom slices must have same Columns number [0028|0011]");     
+      }
+      
+      if ((*it)->GetEntryValue(0x0018,0x0050) != (*first)->GetEntryValue(0x0018,0x0050).c_str()) {
+         itkGenericExceptionMacro("All CT Dicom slices must have same slice thickness [0018|0050]");    
+      }
+      it++;
+    }
+    //it = serie.begin();
+    //     while (it != serie.end()) {
+    //       fileName = (*it)->GetFileName();
+    //       std::cout << fileName << std::endl;
+    //       it++;
+    //     }
+  }
+
+
+
+
+// -----------------------------------------------------------------------------------------------------------------
+  /* =================================================
+   * freely inspired from : clitkDicomRTIOCommon.cxx
+   * written by : Laurent ZAGNI
+   * on : 18 August 2006
+   * 
+   =================================================*/
+    
+ // Test if a file is a valid Dicom-RT Structure-Set file (readable by us) 
+  bool TestDicomRTStructSetFile(gdcm::File* file) {
+// ----------  
+    //gdcm::ValEntry* valEntry;
+    gdcm::DataEntry* valEntry;
+// ---------- 
+
+    std::string exception0 = "Not a [RT Structure Set Storage]";
+    std::string exception1 = "2 or more different 'Roi Referenced Frame UID'!";
+    std::string exception2 = "No 'Series Instance UID'!";
+    std::string exception3 = "Modality not= RTSTRUCT"; 
+            
+    //Verify if the file is a RT-Structure-Set dicom file
+    if (!gdcm::Util::DicomStringEqual(file->GetEntryValue(0x0008,0x0016),"1.2.840.10008.5.1.4.1.1.481.3")) {  //SOP clas UID
+      itkGenericExceptionMacro(<<exception0);
+      // (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] !
+    }
+        
+    if (!gdcm::Util::DicomStringEqual(file->GetEntryValue(0x0008,0x0060),"RTSTRUCT")) {  //SOP clas UID
+      itkGenericExceptionMacro(<<exception3);
+      // (the file must have a Modality tag = RTSTRUCT !
+    }    
+
+    //Verify only one Referenced Frame UID and one or more Series UID
+
+    gdcm::SeqEntry* seqEntry;
+    gdcm::SQItem* currentItem;
+    std::string currentFrameRefUID;
+    
+    seqEntry  = file->GetSeqEntry(0x3006,0x0020); //Structure Set ROI sequence
+    if (seqEntry->GetNumberOfSQItems() > 1) {
+      currentItem = seqEntry->GetFirstSQItem();
+      valEntry = currentItem->GetValEntry(0x3006,0x0024); //Roi Frame of Reference UID
+      currentFrameRefUID = valEntry->GetValue();
+      currentItem = seqEntry->GetNextSQItem();
+      while (currentItem != NULL) {
+        valEntry = currentItem->GetValEntry(0x3006,0x0024); //Roi Frame of Reference UID
+        if (valEntry->GetValue() != currentFrameRefUID) {
+        // std::cout<<"..ref UID"<<currentFrameRefUID<<std::endl;
+        // std::cout<<"..new UID"<<valEntry->GetValue().c_str()<<std::endl;
+        // std::cout<<"..exception"<<std::endl;
+        itkGenericExceptionMacro(<<exception1);
+        }
+        currentItem = seqEntry->GetNextSQItem();
+      }
+    }
+    
+    seqEntry = file->GetSeqEntry(0x3006,0x0010); //Referenced Frame of Reference Sequence
+    currentItem = seqEntry->GetFirstSQItem();
+    while (currentItem != NULL) {
+      valEntry = currentItem->GetValEntry(0x0020,0x0052);  //Frame of Reference UID
+      if (valEntry->GetValue() == currentFrameRefUID) { //search for the ROI Frame of Reference UID
+        break;
+      }else {
+         currentItem = seqEntry->GetNextSQItem();
+      }
+    }
+    if (currentItem == NULL) {
+      itkGenericExceptionMacro(<<exception1);
+    }
+    
+    gdcm::SeqEntry* seqEntry2 = currentItem->GetSeqEntry(0x3006,0x0012); //Referenced Study sequence
+    if (seqEntry2->GetNumberOfSQItems() < 1) {
+      itkGenericExceptionMacro(<<exception2);    
+    }
+    
+    valEntry = file->GetValEntry(0x0020,0x0010); //study ID
+    if ((valEntry == 0) || (valEntry->GetValue() == "")) { //(type 1 : mandatory attribute)
+      itkGenericExceptionMacro("RT-Structure-Set file must contain Study ID [0020|0010] !");    
+    }
+    
+    valEntry = file->GetValEntry(0x3006,0x002); //structure set label 
+    if ((valEntry == 0) || (valEntry->GetValue() == "")) { //(type 1 : mandatory attribute)
+      itkGenericExceptionMacro("RT-Structure-Set file must contain Structure Set Label [0006|0002] !");   
+    }
+    
+    seqEntry = file->GetSeqEntry(0x3006,0x0020); //Structure Set ROI sequence
+    if (seqEntry != 0) {
+      currentItem = seqEntry->GetFirstSQItem();
+      while (currentItem != NULL) {
+         valEntry = currentItem->GetValEntry(0x3006,0x0022); //Roi number
+         if ((valEntry == 0) || (valEntry->GetValue() == "")) { //(type 1 : mandatory attribute)
+           itkGenericExceptionMacro("All ROI in Structure Set Roi Sequence must contain Roi Number [3006|0022] !");   
+         }
+         currentItem = seqEntry->GetNextSQItem();
+      }
+    }
+    
+    seqEntry = file->GetSeqEntry(0x3006,0x0080); //ROI Observation sequence
+    if (seqEntry == 0) { //(type 1 : mandatory attribute)
+      itkGenericExceptionMacro("RT-Structure-Set file must contain ROI Observations Sequence [3006|0080] !");        
+    }
+    
+    seqEntry = file->GetSeqEntry(0x3006,0x0039); //ROI Contour sequence
+    if (seqEntry == 0) { //(type 1 : mandatory attribute)
+      itkGenericExceptionMacro("RT-Structure-Set file must contain ROI Contour Sequence [3006|0039] !");    
+    }
+    std::cout<<"..."<<file->GetFileName()<<" is a valid DICOM RT-Structure-Set file"<<std::endl;
+  }
+
+// -------------------------------------------------------------------------------------------------------
+
+int main(int argc, char *argv[])
+{
+   START_USAGE(usage)
+   "\n exExtractCSA :\n                                                       ",
+   "Extracts and displays the CSA tag(s) of gdcm-parsable Dicom file          ",
+   "                                                                          ",
+   "usage: exExtractCSA {filein=inputFileName|dirin=inputDirectoryName}       ",
+   "                   tmp=temporaryWorkFileName                              ",
+   "                       [extract=listOfElementsToExtract]                  ",
+   "                       [ { [noshadowseq] | [noshadow][noseq] } ] [debug]  ",
+   "       inputFileName : Name of the (single) file user wants to anonymize  ",
+   "       listOfElementsExtract : group-elem,g2-e2,... (in hexa, no space)   ",
+   "                                of Elements to extract                    ",
+   "                              default : 0029-1210,0029-1220               ",
+   "       noshadowseq: user doesn't want to load Private Sequences           ",
+   "       noshadow   : user doesn't want to load Private groups (odd number) ",
+   "       noseq      : user doesn't want to load Sequences                   ",
+   "       verbose    : developper wants to run the program in 'verbose mode' ",
+   "       debug      : developper wants to run the program in 'debug mode'   ",
+   FINISH_USAGE
+
+   // ----- Initialize Arguments Manager ------
+  
+   GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv);
+  
+   if (am->ArgMgrDefined("usage") || argc == 1) 
+   {
+      am->ArgMgrUsage(usage); // Display 'usage'
+      delete am;
+      return 0;
+   }
+   
+      if (am->ArgMgrDefined("debug"))
+      GDCM_NAME_SPACE::Debug::DebugOn();
+
+   bool verbose = am->ArgMgrDefined("verbose");
+   
+   const char *fileName = am->ArgMgrGetString("filein");
+   
+      /* if unused Param we give up */
+   if ( am->ArgMgrPrintUnusedLabels() )
+   {
+      am->ArgMgrUsage(usage);
+      delete am;
+      return 0;
+   }  
+   delete am;  // ------ we don't need Arguments Manager any longer ------
+
+// ============================================================
+//   Read the input image.
+// ============================================================ 
+
+   gdcm::File *f = gdcm::File::New( );
+
+   //f->SetLoadMode(gdcm::LD_NOSEQ | gdcm::LD_NOSHADOW);
+   f->SetFileName( fileName );
+   f->SetMaxSizeLoadEntry(0xffff);
+   bool res = f->Load();  
+
+   if( gdcm::Debug::GetDebugFlag())
+   {
+      std::cout << "---------------------------------------------" << std::endl;
+      f->Print();
+      std::cout << "---------------------------------------------" << std::endl;
+   }
+   if (!res) {
+       std::cerr << "Sorry, " << fileName << " not a gdcm-readable "
+           << "DICOM / ACR File"
+           << std::endl;
+      f->Delete();
+      return 1;
+   }
+   std::cout << " ... is readable " << std::endl;
+      
+   
+   TestDicomRTStructSetFile(f);
+   std::cout << " ... is readable " << std::endl;   
+
+   
+   
+   f->Delete();   
+return 0;
+}      
+