1

I need to generate a series of CT DICOM images (512x512, MONOCHROME) using the GDCM library. Because of the structure of the application that I am working on, it is ideal for me to separately prepare gdcm::Image and gdcm::File instances for each image and at the end pass them on to gdcmImageWriter using the SetFile() and SetImage() methods.

The gdcmImageWriter::write() fails to write DICOM images. I have already looked at the source code of the VTKGDCMImageWriter class and this GDCM example for hints. It appears that the problem originates from some incompatibilities between gdcm::Image and gdcm::File instances (for instance, both classes contain information about the Photometric Interpretation of a DICOM image) that I pass on to gdcmImageWriter, but I am not sure exactly what those are.

The following simplified C++ code reproduces the error I have been getting:

#include <gdcmFile.h>
#include <gdcmImage.h>
#include <gdcmTag.h>
#include "gdcmDataElement.h"
#include "gdcmByteValue.h"
#include "gdcmPixelFormat.h"
#include "gdcmImageWriter.h"
#include "gdcmAnonymizer.h"

#include <iostream>
#include <string>

InitializeGDCMImage(gdcm::Image*  imagePtr);
InitializeGDCMFile( gdcm::File*   filePtr );
WriteFile( gdcm::Image* imagePtr , gdcm::File* filePtr , std::string  fileName );

int main()
{
    std::string  fileName = "./TEST.dcm";

    // Will be deleted by gdcm::writer.
    gdcm::Image* imagePtr = new gdcm::Image;
    gdcm::File*  filePtr  = new gdcm::File;   

    InitializeGDCMImage(imagePtr);

    InitializeGDCMFile( filePtr );

    WriteFile( imagePtr , filePtr , fileName );

    return 0;
}

where,

void WriteFile( gdcm::Image* imagePtr , gdcm::File* filePtr , std::string fileName )
{
    gdcm::ImageWriter* writer = new gdcm::ImageWriter; 
    writer->SetFileName(  fileName.c_str() );
    writer->SetImage(    *imagePtr         );
    writer->SetFile(     *filePtr          );
    if( !writer->Write() ){
      std::cerr << "ERROR: Could not write to \"" << fileName <<  "\"" << std::endl;
    }
    delete writer;
}

WriteFile() sets gdcm::File and gdcm::Image and invokes write(). InitializeGDCMFile() modifies a few DICOM tags using gdcm::Anonymizer, and InitializeGDCMImage() sets the actual pixel values (skipped here for brevity).

void InitializeGDCMFile( gdcm::File* origianlFilePtr )
{
  gdcm::File* filePtr = new gdcm::File;
  gdcm::Anonymizer anon;
  anon.SetFile( *filePtr );  

  anon.Replace( gdcm::Tag(0x0028,0x0002) , "1" );                       //SamplesperPixel
  anon.Replace( gdcm::Tag(0x0028,0x0004) , "MONOCHROME2" );             //PhotometricInterpretation
  anon.Replace( gdcm::Tag(0x0028,0x0010) , "512" );                     //Rows
  anon.Replace( gdcm::Tag(0x0028,0x0011) , "512" );                     //Columns
  anon.Replace( gdcm::Tag(0x0028,0x0030) , "0.781\\0.781" );            //PixelSpacing

  anon.Replace( gdcm::Tag(0x0028,0x1050) , "0" );                        //WindowCenter
  anon.Replace( gdcm::Tag(0x0028,0x1051) , "100" );                      //WindowWidth
  anon.Replace( gdcm::Tag(0x0028,0x1052) , "0" );                        //RescaleIntercept
  anon.Replace( gdcm::Tag(0x0028,0x1053) , "1" );                        //RescaleSlope

  *origianlFilePtr = *filePtr;
}


void InitializeGDCMImage(gdcm::Image* imagePtr)
{
  imagePtr->SetPhotometricInterpretation( gdcm::PhotometricInterpretation::MONOCHROME2 );

  imagePtr->SetNumberOfDimensions(2);
  unsigned int dims[2]={512,512};
  imagePtr->SetDimensions( dims );

  imagePtr->SetSpacing( 0 , 1. );
  imagePtr->SetSpacing( 1 , 1. );

  imagePtr->SetIntercept(0.);
  imagePtr->SetSlope(1.);

  double dirCos[6]={1.,0.,0.,0.,1.,0.};
  imagePtr->SetDirectionCosines( dirCos );

  char *buffer = new char[512*512*sizeof(int16_t)];
  imagePtr->SetPixelFormat( gdcm::PixelFormat::INT16 );
  imagePtr->GetDataElement().SetByteValue( buffer , 512*512*sizeof(int16_t) );
  imagePtr->GetPixelFormat().SetSamplesPerPixel(1);
  delete[] buffer;
}
S.G.
  • 357
  • 2
  • 15
  • `*origianlFilePtr = *filePtr;` I think this is the problem. I don't think gdcm::File has operator=() implemented. – drescherjm Aug 25 '16 at 16:43
  • Also shouldn't `gdcm::Anonymizer` use the input file? And you are replacing things that should not be manipulated with `gdcm::Anonymizer`. `gdcm::Anonymizer` is about removing PHI (Protected health information) not setting dicom tags about the image. – drescherjm Aug 25 '16 at 16:48
  • Thanks @drescherjm for the comments. I just took a look at the header file of the gdcm::Image class. It doesn't seem that gdcm::Image class requires overloading the '=' operator? Not sure the base class it is derived from though. – S.G. Aug 25 '16 at 17:00
  • About the use of the `gdcm::Anonymizer' class, actually I am not sure. I am not much familiar with GDCM and it's documentation is scant. I used it because it is the class used in VTKGDCMImageWriter to generate/modify tags. VTKGDCMImageWriter has the capability to write a DICOM file ex-nihilo. – S.G. Aug 25 '16 at 17:06

0 Answers0