]> Creatis software - gdcm.git/commitdiff
ENH: add another version of Extract CSA Tag
authormalaterre <malaterre>
Tue, 11 Sep 2007 12:54:49 +0000 (12:54 +0000)
committermalaterre <malaterre>
Tue, 11 Sep 2007 12:54:49 +0000 (12:54 +0000)
Example/exExtractCSATag.cxx [new file with mode: 0644]

diff --git a/Example/exExtractCSATag.cxx b/Example/exExtractCSATag.cxx
new file mode 100644 (file)
index 0000000..9cca058
--- /dev/null
@@ -0,0 +1,493 @@
+/*=========================================================================
+                                                                                
+  Program:   gdcm
+  Module:    $RCSfile: exExtractCSATag.cxx,v $
+  Language:  C++
+  Date:      $Date: 2007/09/11 12:54:49 $
+  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.
+                                                                                
+=========================================================================*/
+#include "gdcmFile.h"
+#include "gdcmFileHelper.h"
+#include "gdcmCommon.h"
+#include "gdcmDebug.h"
+#include "gdcmDocEntry.h"
+#include "gdcmDataEntry.h"
+#include "gdcmSeqEntry.h"
+#include "gdcmSQItem.h"
+
+#include <iomanip>
+
+namespace gdcm
+{
+
+   static const char *lookupTable1[] = {
+      "UsedPatientWeight",
+      "NumberOfPrescans",
+      "TransmitterCalibration",
+      "PhaseGradientAmplitude",
+      "ReadoutGradientAmplitude",
+      "SelectionGradientAmplitude",
+      "GradientDelayTime",
+      "RfWatchdogMask",
+      "RfPowerErrorIndicator",
+      "SarWholeBody",
+      "Sed",
+      "SequenceFileOwner",
+      "Stim_mon_mode",
+      "Operation_mode_flag",
+      "dBdt_max",
+      "t_puls_max",
+      "dBdt_thresh",
+      "dBdt_limit",
+      "SW_korr_faktor",
+      "Stim_max_online",
+      "Stim_max_ges_norm_online",
+      "Stim_lim",
+      "Stim_faktor",
+      "CoilForGradient",
+      "CoilTuningReflection",
+      "CoilId",
+      "MiscSequenceParam",
+      "MrProtocolVersion",
+      "MrProtocol",
+      "DataFileName",
+      "RepresentativeImage",
+      "PositivePCSDirections",
+      "RelTablePosition",
+      "ReadoutOS",
+      "LongModelName",
+      "SliceArrayConcatenations",
+      "SliceResolution",
+      "MrEvaProtocol",
+      "AbsTablePosition",
+      "AutoAlignMatrix",
+      "MeasurementIndex",
+      "CoilString",
+      "PATModeText",
+      "PatReinPattern",
+      NULL
+   };
+
+   static const char *lookupTable2[] = {
+      "EchoLinePosition",
+      "EchoColumnPosition",
+      "EchoPartitionPosition",
+      "UsedChannelMask",
+      "Actual3DImaPartNumber",
+      "ICE_Dims",
+      "B_value",
+      "Filter1",
+      "Filter2",
+      "ProtocolSliceNumber",
+      "RealDwellTime",
+      "PixelFile",
+      "PixelFileName",
+      "SliceMeasurementDuration",
+      "SequenceMask",
+      "AcquisitionMatrixText",
+      "MeasuredFourierLines",
+      "FlowEncodingDirection",
+      "FlowVenc",
+      "PhaseEncodingDirectionPositive",
+      "NumberOfImagesInMosaic",
+      "DiffusionGradientDirection",
+      "ImageGroup",
+      "SliceNormalVector",
+      "DiffusionDirectionality",
+      "TimeAfterStart",
+      "FlipAngle",
+      "SequenceName",
+      "RepetitionTime",
+      "EchoTime",
+      "NumberOfAverages",
+      "VoxelThickness",
+      "VoxelPhaseFOV",
+      "VoxelReadoutFOV",
+      "VoxelPositionSag",
+      "VoxelPositionCor",
+      "VoxelPositionTra",
+      "VoxelNormalSag",
+      "VoxelNormalCor",
+      "VoxelNormalTra",
+      "VoxelInPlaneRot",
+      "ImagePositionPatient",
+      "ImageOrientationPatient",
+      "PixelSpacing",
+      "SliceLocation",
+      "SliceThickness",
+      "SpectrumTextRegionLabel",
+      "Comp_Algorithm",
+      "Comp_Blended",
+      "Comp_ManualAdjusted",
+      "Comp_AutoParam",
+      "Comp_AdjustedParam",
+      "Comp_JobID",
+      "FMRIStimulInfo",
+      "FlowEncodingDirectionString",
+      "RepetitionTimeEffective",
+    NULL
+   };
+
+   static const char *lookupTable3[] = {
+      "ImageNumber",
+      "ImageComments",
+      "ReferencedImageSequence",
+      "PatientOrientation",
+      "ScanningSequence",
+      "SequenceName",
+      "RepetitionTime",
+      "EchoTime",
+      "InversionTime",
+      "NumberOfAverages",
+      "ImagingFrequency",
+      "ImagedNucleus",
+      "EchoNumbers",
+      "MagneticFieldStrength",
+      "NumberOfPhaseEncodingSteps",
+      "EchoTrainLength",
+      "PercentSampling",
+      "PercentPhaseFieldOfView",
+      "TriggerTime",
+      "ReceivingCoil",
+      "TransmittingCoil",
+      "AcqusitionMatrix",
+      "PhaseEncodingDirection",
+      "FlipAngle",
+      "VariableFlipAngleFlag",
+      "SAR",
+      "dBdt",
+      "Rows",
+      "Columns",
+      "SliceThickness",
+      "ImagePositionPatient",
+      "ImageOrientationPatient",
+      "SliceLocation",
+      "EchoLinePosition",
+      "EchoColumnPosition",
+      "EchoPartitionPosition",
+      "Actual3DImaPartNumber",
+      "RealDwellTime",
+      "ProtocolSliceNumber",
+      "DataFile",
+      "DataFileName",
+      "ICE_Dims",
+      "PixelSpacing",
+      "SourceImageSequence",
+      "PixelBandwidth",
+      "SliceMeasurementDuration",
+      "SequenceMask",
+      "AcquisitionMatrixText",
+      "MeasuredFourierLines",
+      "CsiGridshiftVector",
+      NULL
+   };
+
+   /*
+    * What if SIEMENS decide to add another entry in this table, all the offsets are completely off ...
+    * Also we do not respect the ordering anymore.
+    * TODO: Need to check if elements always comes in the same order
+    */
+   unsigned int GetLookupCSAIndex(const char *csa_name, const char **lookuptable = lookupTable1)
+      {
+     const char **p = lookuptable;
+      while( *p && strcmp(*p, csa_name) != 0 )
+         {
+      ++p;
+         }
+    assert( strcmp(*p, csa_name) == 0 );
+    return p - lookuptable + 1;  // Start at 1 to avoid being on the 0000 position
+      }
+
+      // Looks like there is mapping in between syngodt and vr...
+      // O <=> UN
+      // 3 <=> DS
+      // 4 <=> FD
+      // 5 <=> FL
+      // 6 <=> IS
+      // 9 <=> UL
+      // 10 <=> US
+      // 16 <=> CS
+      // 19 <=> LO
+      // 20 <=> LT
+      // 22 <=> SH
+      // 25 <=> UI
+
+struct equ
+{ 
+   uint32_t syngodt;
+   char vr[2+1];
+};
+
+static equ mapping[] = {
+   {     0 , "UN" },
+   {     3 , "DS" },
+   {     4 , "FD" },
+   {     5 , "FL" },
+   {     6 , "IS" },
+  {   7 , "SL" },
+  {   8 , "SS" },
+   {     9 , "UL" },
+   {    10 , "US" },
+   {    16 , "CS" },
+   {    19 , "LO" },
+   {    20 , "LT" },
+   {    22 , "SH" },
+   {    23 , "ST" },
+   {    25 , "UI" },
+  {  27 , "UT" },
+};
+
+bool check_mapping(uint32_t syngodt, const char *vr)
+{
+  static const unsigned int max = sizeof(mapping) / sizeof(equ);
+  unsigned int s = 0;
+  const equ *p = mapping;
+  assert( syngodt <= mapping[max-1].syngodt );
+   while(p->syngodt < syngodt )
+      {
+    ++p;
+      }
+  assert( p->syngodt == syngodt ); // or else need to update mapping
+  const char* lvr = p->vr;
+  int check = strcmp(vr, lvr) == 0;
+  assert( check );
+  return true;
+}
+
+uint32_t readCSAHeader(std::istream &is)
+{
+   char dummy[4+1];
+   dummy[4] = 0;
+   is.read(dummy, 4);
+   std::cout << dummy << std::endl;
+   if( strcmp( dummy, "SV10" )  ) 
+      {
+      std::cerr << "Either not a SV10 header or filled with 0..." << std::endl;
+      return 1;
+      }
+   // wotsit ?
+   is.read(dummy, 4);
+   if( strcmp( dummy, "\4\3\2\1" )  ) 
+      {
+      std::cerr << "Either not a SV10 header or filled with 0..." << std::endl;
+      return 1;
+      }
+   std::cout << dummy << std::endl;
+   uint32_t n;
+   is.read((char*)&n, sizeof(n));
+   std::cout << n << std::endl;
+   uint32_t unused;
+   is.read((char*)&unused, sizeof(unused));
+   std::cout << unused << std::endl;
+   assert( unused == 77 ); // 'M' character...
+
+  return n;
+}
+
+DataEntry *readCSAElement(std::istream &is)
+{
+      char name[64+1];
+      name[64] = 0; // security
+      //std::cout << "Pos 0x" << std::hex << is.tellg() << std::dec << std::endl;
+      is.read(name, 64);
+      std::cout << "Name=" << name << std::endl;
+     unsigned int element = GetLookupCSAIndex(name,lookupTable2);
+      uint32_t vm;
+      is.read((char*)&vm, sizeof(vm));
+      std::cout << "vm=" << vm << std::endl;
+      char vr[4];
+      is.read(vr, 4);
+    assert( vr[2] == vr[3] && vr[2] == 0 );
+      std::cout << "vr=" << vr << std::endl;
+
+      DataEntry *de = DataEntry::New(0x0029, element, vr);
+
+      uint32_t syngodt;
+      is.read((char*)&syngodt, sizeof(syngodt));
+      check_mapping(syngodt, vr);
+      
+      std::cout << "syngodt=" << syngodt << std::endl;
+      uint32_t nitems;
+      is.read((char*)&nitems, sizeof(nitems));
+      std::cout << "nitems=" << nitems<< std::endl;
+      uint32_t xx;
+      is.read((char*)&xx, sizeof(xx));
+      //std::cout << "xx=" << xx<< std::endl;
+      assert( xx == 77 || xx == 205 );
+      for( uint32_t j = 0; j < nitems; ++j)
+         {
+         uint32_t item_xx[4];
+         is.read((char*)&item_xx, 4*sizeof(uint32_t));
+         std::cout << "item_xx=" << item_xx[0] << " " << item_xx[1] << " " << item_xx[2] << " " << item_xx[3] << std::endl;
+         //std::cout << "0x" << std::hex << is.tellg() << std::dec << std::endl;
+         assert( item_xx[2] == 77 || item_xx[2] == 205 );
+         uint32_t len = item_xx[1]; // 2nd element
+         std::cout << "len=" << len << std::endl;
+         assert( item_xx[0] == item_xx[1] && item_xx[1] == item_xx[3] );
+         char *val = new char[len+1];
+         val[len] = 0; // security
+         is.read(val,len);
+         // WARNING vr does not means anything AFAIK, simply print the value as if it was IS/DS or LO (ASCII)
+         std::cout << "val=" << val << std::endl;
+      if( !j )
+      de->SetString( std::string(val,len) );
+         delete[] val;
+         char dummy[4];
+         uint32_t dummy_len = (4 - len % 4) % 4;
+         is.read(dummy, dummy_len );
+         for(uint32_t d= 0; d < dummy_len; ++d)
+            {
+            // I think dummy should always be 0
+            if( dummy[d] )
+               {
+               std::cout << "dummy=" << (int)dummy[d] << std::endl;
+               }
+            }
+         }
+
+
+  return de;
+}
+
+int convertCSA(std::istream &is, File *f)
+{
+   f->RemoveEntry( f->GetDataEntry(0X0029,0x1010) );
+
+    SeqEntry *sq = SeqEntry::New(0x0029,0x1010);
+    SQItem *sqi = SQItem::New(1);
+//    DataEntry *e_0008_1150 = DataEntry::New(0x0008, 0x1150, "UI");
+//    e_0008_1150->SetString( "coucou" );
+//    sqi->AddEntry(e_0008_1150);
+//    e_0008_1150->Delete();
+//
+//    DataEntry *e_0008_1155 = DataEntry::New(0x0008, 0x1155, "UI");
+//    e_0008_1155->SetString( "mathieu" );
+//    sqi->AddEntry(e_0008_1155);
+//    e_0008_1155->Delete();
+
+
+
+  uint32_t n = readCSAHeader(is);
+
+   for(uint32_t i = 0; i < n; ++i)
+      {
+    DataEntry *de = readCSAElement(is);
+    sqi->AddEntry(de);
+    de->Delete();
+      }
+
+    sq->AddSQItem(sqi,1);
+    sqi->Delete();
+    //sq->Print( std::cout );
+   f->AddEntry( sq );
+    sq->Delete();
+   f->Print( std::cout );
+
+   gdcm::FileHelper *fh = gdcm::FileHelper::New(f);
+         fh->SetWriteTypeToDcmExplVR();
+         fh->Write("/tmp/csa2.dcm");
+
+   return 0;
+}
+} // end namespace gdcm
+
+int main(int argc, char *argv[])
+{  
+   gdcm::File *f;
+   if( argc < 5 )
+   {
+      std::cerr << "Usage :" << argv[0] << " input.dcm  group element outputfile" << std::endl;
+      std::cerr << "  Ex: " << argv[0] << " /tmp/bla.dcm 0029 2110 /tmp/out.raw" << std::endl;
+      return 1;
+   }
+   std::string fileName = argv[1];
+
+   std::cout << fileName << std::endl;
+// ============================================================
+//   Read the input image.
+// ============================================================
+
+   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;
+
+   // Find the dicom tag, and extract the string
+   uint16_t group, elem;
+   std::istringstream convert;
+   convert.str( argv[2] );
+   convert >> std::hex >> group;
+   convert.clear(); //important
+   convert.str( argv[3] );
+   convert >> std::hex >> elem;
+   std::cout << "Extracting tag: (0x" << std::hex << std::setw(4) << std::setfill('0')
+     << group << ",0x" << std::setw(4) << std::setfill('0') << elem << ")" << std::endl;
+   std::string dicom_tag_value = f->GetEntryString(group, elem);
+   if (dicom_tag_value == gdcm::GDCM_UNFOUND)
+   {
+     gdcm::DictEntry *dictEntry = f->GetPubDict()->GetEntry( group, elem);
+     std::cerr << "Image doesn't contain any tag: " << dictEntry->GetName() << std::endl;
+     f->Delete();
+     return 1;
+   }
+
+   gdcm::DocEntry *dicom_tag_doc = f->GetDocEntry(group, elem);
+   gdcm::DataEntry *dicom_tag = dynamic_cast<gdcm::DataEntry *>(dicom_tag_doc);
+   if( !dicom_tag )
+   {
+      std::cerr << "Sorry DataEntry only please" << std::endl;
+      f->Delete();
+      return 1;
+   }
+
+   // Write out the data as a file:
+   std::ofstream o(argv[4]);
+   if( !o )
+   {
+      std::cerr << "Problem opening file: " << argv[4] << std::endl;
+      f->Delete();
+      return 1;
+   }
+   o.write((char*)dicom_tag->GetBinArea(), dicom_tag->GetLength());
+   o.close();
+
+   std::istringstream is;
+   is.str( std::string( (char*)dicom_tag->GetBinArea(), dicom_tag->GetLength()) );
+
+   gdcm::convertCSA(is, f);
+
+   f->Delete();
+
+
+
+   return 0;
+}
+
+