0
votes

I been trying to fix this very weird problem since 1 or 2 weeks ago.

I am trying to read DICOM images using ITK and afterwards do some processing.

Problem is, i want to read the images independently of the pixel type. For this, i have to find out the pixel type and instantiate the itkImage on runtime.

Therefore, when i read the image file, i have to convert it from itkImage to itkImageBase (in the itkImage.h it is declared as class itkImage : public itkImageBase).

Unfortunately, after i cast it from one type to another inside an if block, i cannot access the value stored on this variable anywhere outside this if block. Here is the code:

*Sorry about the variables and method names in portuguese. Here is a little help:

leitor means reader

tipoPixel means pixelType

abreImagem(templated method) means openImage

iniciaAbrirImagem means initiateOpenImage

//here is io.h
#ifndef IO_H
#define IO_H

#include "itkImageSeriesReader.h"
#include "itkImageFileWriter.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkGDCMImageIO.h"
#include "itkMetaDataDictionary.h"
#include "itkImageBase.h"
#include "iobase.h"

typedef itk::GDCMImageIO GDCM;
typedef itk::Image<float, 3> TipoImagemIO;
typedef itk::MetaDataDictionary TipoDicionario;
typedef itk::MetaDataObject<std::string> MetaDataString;
typedef itk::ImageBase<3> ImageBase; //Typedef for the imagebase

class IO : public IOBase
{
private:

    ImageBase* imagemB; //This is the variable giving me some trouble
    ImageBase* imagemB2;

    GDCM::Pointer gdcm;

    std::string tipoPixel;
public:
    IO();
    template<typename TLeitor>void abreImagem(std::string s, TLeitor leitor);
    void abreDiretorio(std::string s);
    void iniciaGravarImagem(std::string s, ImageBase* imgNova);
    ImageBase* GetOutput();
    void extraiTags();
    void iniciaAbrirImagem(std::string s);
    template<typename TGravador, typename TImagem>void gravaImagem(TGravador gravador, TImagem img, std::string s);
};
#endif  


//here is io.cpp
#include "io.h"
#include "vtkKWImage.h"
#include "vtkKWImageIO.h"
#include "imagem.h"
#include <typeinfo>

IO::IO()
{
imagemB = 0;
imagemB2 = 0;
gdcm = GDCM::New();
}

template<typename TLeitor>
void IO::abreImagem(std::string s, TLeitor leitor)
{
leitor->SetImageIO(gdcm);
leitor->SetFileName(s);

try
{
    leitor->Update();
}
catch(itk::ExceptionObject &ex)
{
    std::cerr<<ex<<std::endl;
    exit(1);
}

try
{
    imagemB = static_cast<ImageBase*>(leitor->GetOutput());
}
catch(std::bad_cast &ex)
{
    std::cout<<"EXCECAO";
    exit(1);
}
std::cout<<imagemB->GetNameOfClass(); //This one is ok
}

void IO::iniciaAbrirImagem(std::string s)
{
extraiTipoDimensoes(s); 
tipoPixel = GetTipo();  

if(tipoPixel.compare("short") == 0)
{
    typedef itk::Image<short, 3> itkImg;
    typedef itk::ImageSeriesReader<itkImg> TipoLeitor;
    TipoLeitor::Pointer leitor = TipoLeitor::New();

    abreImagem<TipoLeitor::Pointer>(s, leitor);

std::cerr<<"Trying to call a method inside IF: "<<imagemB->GetNameOfClass()<<std::endl;  //This one is ok too
}
//...doing the same things for unsigned short, int, float, double, etc...
std::cerr<<"trying to call a method outside IF: ";  
std::cerr<<imagemB->GetNameOfClass()<<std::endl; //Here i get this weird segmentation fault
}

ImageBase* IO::GetOutput()
{
std::cerr<<"JUST ENTERED GETOUTPUT()";  
std::cout<<imagemB->GetNameOfClass()<<std::endl; //If i remove the last method call of this variable, i get a segfault here
std::cerr<<std::endl<<"HOORAY, ITS GETTING OUT OF GETOUPUT"<<std::endl;
return imagemB;
}

As you can see (or atleast i hope the code is clear enough so you can see it), i declared a pointer to itk::ImageBase<3> and initiated it with value 0 on the class constructor (already tried without initializing, initializing with null, nothing works...).

Afterwards, i call some methods from other class to find out the pixel type of the input image. Then, i enter and if block where i instantiate a itk::ImageFileReader and an itkImage with the same pixel type as the input image.

Then, i send the variable of the type TipoLeitor (or ReaderType, as you wish) to the templated function, where i actually read the image file inside the try/catch block. Then, on the next try i cast the output of the reader (an itkImage) to itkImageBase and put it in the imagemB variable.

If i try to call some random method of that class, like GetNameOfClass inside the templated method, thats ok, everything goes as expected. If i do the same inside the if block where the templated method was called, thats ok too. But it doesn't work if i try to do the same inside the function, after the if block. The same happens if i try to do this on GetOutput() method.

It is like the variable imagemB is initialized inside the if block, the, when it exits the block it is set to uninitialized (does this word even exists).

There's no detailed error message, just a "Segmentation fault".

Thanks for the help and sorry about the poor english and the long text.

2
Is leitor a smart pointer ?Mahesh
Yes it is. Declared it as TipoLeitor::Pointer.Gustavo
Smart pointer does de-allocation all by itself with out explicitly calling delete on it when falls out of scope. Does TipoLeitor::Pointer falls under this type is what I meant ?Mahesh
Yes it will do that. But after i get its output and put it into imagemB, it can delete itself... i won't need the reader anymore.Gustavo

2 Answers

1
votes

When you say "read the images independently of the pixel type", if you're talking about the pixel type of the image on disk, you don't need to go through that: the ImageSeriesReader will internally cast from the pixel type on disk to the pixel type of the image you put as a template of the ImageSeriesReader. Note that the template of the ImageSeriesReader is the type of the image in output, not the input.

If you really want to have the output type controlled at run time you can use a template function:

template<typename OutputPixelType> void my_process() {
}

and use it in:

switch (type)
  {
  case 1:
    my_process<unsigned char>(parseResult);
    break;
  case 2:
    my_process<short int>(parseResult);
    break;
  ...
  }

Full example here http://hg.orfeo-toolbox.org/OTB-Applications/file/1c193d45e483/Utils/otbConvert.cxx

0
votes

The ImageBase class is abstract, and does not have a full implementation suitable for holding an image. You must instantiate one (or many) of the templated types to hold an actual image.