[Insight-users] Re: DICOM data reading & DICOM writing

Luis Ibanez luis.ibanez at kitware.com
Tue Jul 19 09:20:23 EDT 2005


Hi Martin,

You are right, writing DICOM files is a different
proposition than reading DICOM files...


The good news is that this has already been solved
in ITK thanks to the use of the GDCM library.



Several comments about your concerns:


1) When you write an ITK image using the GDCMImageIO
    object, it will use the right type from the actual
    image that you are writing.


2) You can read a DICOM series, do processing on it
    and write the result as another DICOM series.


3) You are right in the the output writer needs some
    header information from the input (e.g. Patient Name).
    You seem to be missing the following call

      seriesWriter->SetMetaDataDictionaryArray(
              reader->GetMetaDataDictionaryArray() );


    That is described in the ITK Software Guide :

         http://www.itk.org/ItkSoftwareGuide.pdf

    in the Chapter "Reading and Writing Images"


4) With the current structure of ITK + GDCM you should
    be able to read a DICOM series, rotate it using a
    ResampleImageFilter and a Transform and write the
    resulting image as another DICOM series.



Please read the IO Chapter of the ITK Software Guide
and let us know if you have further questions.



   Regards,


      Luis



--------------------
Martin SEISER wrote:

> Hi Luis,
> 
> thx for your help. Reading is doing well now. But for the writing part I have encountered some problems that cannont be solved this easily I think!;)
> 
> The problem lies within the following lines:
> 
> seriesWriter->SetInput(reader->GetOutput());
> seriesWriter->SetImageIO(dicomIO);
> nameGenerator->SetOutputDirectory(path.c_str());
> seriesWriter->SetFileNames(nameGenerator->GetOutputFileNames());
> 
> In my opinion, after reading a dicom series, the reader->GetOutput() return value is of type "itk::Image<PixelType, Dimension>" ,where typedef signed short PixelType and const unsigned int Dimension = 3.
> 
> Now lets think of a method the tries to write the information of an image of type itk::Image<PixelType, Dimension>" to a series of dicom files.
> 
> void saveDICOMData(ImageIOType::Pointer imageIO, ImageType::Pointer image, std::string& outputDirectory) {
> 
>   seriesWriter->SetInput(image); // does work
>   seriesWriter->SetImageIO(imageIO); // does work
>   nameGenerator->SetOutputDirectory(outputDirectory.c_str()); // does work
>   seriesWriter->SetFileNames(nameGenerator->GetOutputFileNames()); // does not work
> }
> 
> The problem I see here is, that the nameGenerator cannot generate the output filenames without any information about the input files! What I want is a total seperation of the reading / writing process.
> 
> DICOM data should be read in, transformed in any way possible, and written back. Transforming means change of pixel information, translation, scaling, .... As well as the reduction of the number of slices itself.
> 
> For example:
> 
> 1) read a series of dicom files with, lets say, 20 slices.
> 2) Rotate the image and scale it afterwards.
> 3) Write 10 DICOM slices back, which contain the image information.
> 
> One solution is to get an array which contains the single slices and write the slices one by one to harddisk.
> 
> But is there an easier way?
> 
> Would appreciate your help.
> 
> Best regars, Martin
> 
> ----- Original Message -----
> From: "Luis Ibanez" <luis.ibanez at kitware.com>
> To: "Martin SEISER" <m.seiser at 2die4.com>
> Subject: Re: DICOM data reading
> Date: Wed, 13 Jul 2005 11:49:53 -0400
> 
> 
>>
>>
>>Hi Martin,
>>
>>
>>Yes, the SeriesUID is unique for a given patient,
>>however in certain cases the same series may contain
>>multiple modalities.
>>
>>If what you want to do is to use the SeriesUID in order
>>to get the Patient information, that can easily be done
>>as illustrated in the ITK Software Guide
>>
>>         http://www.itk.org/ItkSoftwareGuide.pdf
>>
>>
>>in Sections:
>>
>>
>>  7.12.5 "Printing out DICOM tags from one slice"
>>  7.12.6 "Printing out DICOM tags from a serie"
>>
>>
>>in pdf-pages 330-337.
>>
>>
>>
>>
>>The corresponding source code examples are available
>>in the directory
>>
>>
>>       Insight/Examples/IO/
>>           DicomImageReadPrintTags.cxx
>>           DicomSeriesReadPrintTags.cxx
>>
>>
>>
>>Please read the documentation above and let us know
>>if you have any further questions,
>>
>>
>>
>>     Thanks
>>
>>
>>
>>       Luis
>>
>>
>>
>>
>>---------------------
>>Martin SEISER wrote:
>>
>>
>>>Hi luis,
>>>
>>>thx for your answer, has helped me a lot! But I already got a 
>>>special solution cause of the fact, that the series ID is not the 
>>>only criteria to choose when selecting a series. You also need to 
>>>select a series by using the patient id, or, if necessary, by 
>>>using a time tag, if working with time triggered series (4D).
>>>
>>>Is the seriesUID unique? And after getting it, can you get access 
>>>to the data (like patientid, sex, name, ...) for a special 
>>>seriesUID? So it can presented to the user as choosing criteria. 
>>>Would be simplify my program a lot!
>>>
>>>Thx for your help in advance,
>>>
>>>Best regards,
>>>
>>>Martin
>>>
>>>----- Original Message -----
>>>From: "Luis Ibanez" <luis.ibanez at kitware.com>
>>>To: "Martin SEISER" <m.seiser at 2die4.com>
>>>Subject: Re: DICOM data reading
>>>Date: Tue, 12 Jul 2005 18:52:37 -0400
>>>
>>>
>>>
>>>>Hi Martin,
>>>>
>>>>It is quite common to have multiple DICOM series in
>>>>the same directory.  The way to select the series is
>>>>therefore to make a first pass to your directory and
>>>>to collect the list of series that are present, along
>>>>with additional patient information such as name, sex
>>>>and age.
>>>>
>>>>
>>>>In a typical application, this list will be presented
>>>>to the user, who will select to read one of the series
>>>>from that list.
>>>>
>>>>Once you have a series ID, the series can be passed to
>>>>the GDCMSeriesFileNames in order to generate the file
>>>>names of only the slices that belong to the selected
>>>>series.
>>>>
>>>>All this is described in detail in the ITK Software Guide
>>>>
>>>>
>>>>     http://www.itk.org/ItkSoftwareGuide.pdf
>>>>
>>>>in Chapter 7, "Reading and Writing Images". In particular
>>>>in section 7.12.3, in pdf-page 324.
>>>>
>>>>
>>>>Note that for gathering all the series in a directory
>>>>you use the GDCMSeriesFileNames class and pass to it the
>>>>directory using the method
>>>>
>>>>               SetDirectory()
>>>>
>>>>Then you get the list of Series IDs with the method
>>>>
>>>>               GetSeriesUIDs()
>>>>
>>>>at this point you present this list to a User, probably
>>>>using a GUI, and let the user select the series that
>>>>she wants to read. Then you pass that series Id to the
>>>>same GDCMSeriesFileNames generator using the method:
>>>>
>>>>              GetFileNames( seriesUID )
>>>>
>>>>The list of filenames is finally passed to the
>>>>ImageSeriesReader, and at that point you can trigger
>>>>the process of reading all the slices.
>>>>
>>>>The source code example that describes this same process
>>>>is available in
>>>>
>>>>
>>>>         Insight/Examples/IO/
>>>>             DicomSeriesReadImageWrite2.cxx
>>>>
>>>>
>>>>
>>>>
>>>>For an example of how this is done in a GUI, please look
>>>>at the application developed by the ISIS Center at Georgetown
>>>>University, that is available in
>>>>
>>>>
>>>>       InsightApplications/
>>>>                 LiverTumorSegmentation
>>>>
>>>>
>>>>In the "File" menu of this application you will find an option
>>>>for "Load DICOM". This options does what has been described
>>>>above.
>>>>
>>>>
>>>>
>>>>Please let us know if you have further questions,
>>>>
>>>>
>>>>    Regards,
>>>>
>>>>
>>>>
>>>>       Luis
>>>>
>>>>
>>>>
>>>>--------------------------------
>>>>Martin SEISER wrote:
>>>>
>>>>
>>>>
>>>>>Dear Mr. Ibanez,
>>>>>
>>>>>my name is Martin Seiser and i am currently working for the 
>>>>>UMIT, the private medical informatics university, in Tyrol, 
>>>>>Austria. My task is to read and writes series of DICOM data. I 
>>>>>am using the 2.1.0 ITK api which offers a library to comforably 
>>>>>get access to dicom data, which does work well for a single 
>>>>>series. But there exists the possibility that there are 
>>>>>multiple series in one folder and the user should have the 
>>>>>possibility to choose, which data (chosen by patient ID or 
>>>>>study ID) to load. That doesnt work at the moment, cause i have 
>>>>>no clue if it works with my code. In my opinion I have to read 
>>>>>the folder file by file and check each DICOM file for 
>>>>>information used to choose series.
>>>>>
>>>>>Here you have my code to read a folder:
>>>>>
>>>>>int main(int argc, char* argv[]) {
>>>>>	typedef itk::Image<unsigned short,3> ImageType;
>>>>>	typedef itk::Image< unsigned char, 2 > Image2DType;
>>>>>	typedef itk::ImageSeriesReader<ImageType> SeriesReaderType;
>>>>>	typedef itk::ImageSeriesWriter<ImageType, Image2DType> SeriesWriterType;
>>>>>	typedef itk::ImageFileWriter<ImageType> WriterType;
>>>>>	typedef itk::GDCMImageIO ImageIOType;
>>>>>	typedef itk::GDCMSeriesFileNames NamesGeneratorType;
>>>>>	typedef std::vector<std::string> fileNamesContainer;
>>>>>	typedef itk::NumericSeriesFileNames NameGeneratorType;
>>>>>
>>>>>	if(argc < 4) {
>>>>>		std::cerr << "Usage: " << argv[0] << " DicomDirectory  format 
>>>>>extension  [seriesName]" << std::endl;
>>>>>		return EXIT_FAILURE;
>>>>>	}
>>>>>
>>>>>	ImageIOType::Pointer dicomIO = ImageIOType::New();
>>>>>
>>>>>	// Get the DICOM filenames from the directory
>>>>>	NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
>>>>>	nameGenerator->SetInputDirectory(argv[1]);
>>>>>
>>>>>	try {
>>>>>		fileNamesContainer fileNames;
>>>>>		fileNames = nameGenerator->GetInputFileNames();
>>>>>		SeriesReaderType::Pointer reader = SeriesReaderType::New();
>>>>>		reader->SetFileNames(fileNames);
>>>>>		reader->SetImageIO(dicomIO);
>>>>>
>>>>>		try {
>>>>>			reader->Update();
>>>>>		}
>>>>>		catch (itk::ExceptionObject &ex) {
>>>>>			std::cout << ex << std::endl;
>>>>>			return EXIT_FAILURE;
>>>>>		}
>>>>>
>>>>>		char buffer[100];
>>>>>
>>>>>		dicomIO->GetPatientName(buffer);
>>>>>		std::cout << "PatientName: " << buffer << std::endl;
>>>>>		dicomIO->GetPatientID(buffer);
>>>>>		std::cout << "PatientID: " << buffer << std::endl;
>>>>>		dicomIO->GetPatientSex(buffer);
>>>>>		std::cout << "PatientSex: " << buffer << std::endl;
>>>>>		dicomIO->GetPatientAge(buffer);
>>>>>		std::cout << "PatientAge: " << atoi(buffer) << std::endl;
>>>>>		dicomIO->GetStudyID(buffer);
>>>>>		std::cout << "StudyID: " << buffer << std::endl;
>>>>>		dicomIO->GetNumberOfSeriesInStudy(buffer);
>>>>>		std::cout << "NumberOfSeriesInStudy: " << atoi(buffer) << std::endl;
>>>>>		dicomIO->GetNumberOfStudyRelatedSeries(buffer);
>>>>>		std::cout << "NumberOfStudyRelatedSeries: " << atoi(buffer) << std::endl;
>>>>>	}
>>>>>	catch (itk::ExceptionObject &ex) {
>>>>>		std::cout << ex << std::endl;
>>>>>		return EXIT_FAILURE;
>>>>>	}
>>>>>	return EXIT_SUCCESS;
>>>>>}
>>>>>
>>>>>And if I call the getter-methods above i only get the data of 
>>>>>the first study read in!:(
>>>>>
>>>>>Would be very glad if you could help me,
>>>>>
>>>>>thx in advance
>>>>>
>>>>>Martin Seiser
>>>>>
>>>
>>>
>>>
> 
> 





More information about the Insight-users mailing list