Discussion:
[ITK-users] SimpleITK Serieswriter and DicomTags
Matias
2017-03-30 12:49:16 UTC
Permalink
Hi,

I've been dealing with ITK for years in C++ and now I would need to use
SimpleITK and C# as far as I can in a new proyect.

Is the SimpleITK SeriesWriter working for Dicom Files? Last time I tried to
use it I had problems with the DicomTags, these would not copy or there was
no method to copy the tags to the resulting slices.

Currently, I read a volume of slices, apply rotation and then I need to
write the resulting image as another set of slices AND keeping tag
information such as patient name, etc.

Thank you,

Matias.



--
View this message in context: http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050.html
Sent from the ITK - Users mailing list archive at Nabble.com.
_____________________________________
Powered by www.kitware.com

Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html

Kitware offers ITK Training Courses, for more information visit:
http://www.kitware.com/products/protraining.php

Please keep messages on-topic and check the ITK FAQ at:
http://www.itk.org/Wiki/ITK_FAQ

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/insight-users
Lowekamp, Bradley (NIH/NLM/LHC) [C]
2017-03-30 14:23:26 UTC
Permalink
Hello,

Writing correct DICOM continues to be a struggle with SimpleITK and ITK. It is generally recommended to directly use GDCM or DCMTK to write a proper DICOM series.

SimpleITK tries to keep things, well, simple and straight forward. But ITK ties to do some smart things, which get in the way for certain uses with SimpleITK. We are trying to document and develop a nominal set of DICOM output operations that work in SimpleITK.

Do you have working C++ code that works for your intended operation? Can you share a small section of code which does what you expect it C++?

Thank,
Brad
Post by Matias
Hi,
I've been dealing with ITK for years in C++ and now I would need to use
SimpleITK and C# as far as I can in a new proyect.
Is the SimpleITK SeriesWriter working for Dicom Files? Last time I tried to
use it I had problems with the DicomTags, these would not copy or there was
no method to copy the tags to the resulting slices.
Currently, I read a volume of slices, apply rotation and then I need to
write the resulting image as another set of slices AND keeping tag
information such as patient name, etc.
Thank you,
Matias.
--
View this message in context: http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050.html
Sent from the ITK - Users mailing list archive at Nabble.com.
_____________________________________
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
_______________________________________________
Community mailing list
http://public.kitware.com/mailman/listinfo/community
_____________________________________
Powered by www.kitware.com

Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html

Kitware offers ITK Training Courses, for more information visit:
http://www.kitware.com/products/protraining.php

Please keep messages on-topic and check the ITK FAQ at:
http://www.itk.org/Wiki/ITK_FAQ

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/insight-users
Matias
2017-03-30 16:14:33 UTC
Permalink
Yes, this is what I would need to migrate to C#:
It basically reads a dicom directory and performs rotation on the volume,
then writes the resulting images back to a directory, copying the tags from
the original images.

#include "itkImage.h"
#include "itkGDCMImageIO.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkImageSeriesReader.h"
#include "itkResampleImageFilter.h"
#include "itkEuler3DTransform.hxx"
#include "gdcmUIDGenerator.h"

#include "itkImageFileWriter.h"
#include "itkImageSeriesWriter.h"
#include "itkNumericSeriesFileNames.h"
#include "itkTranslationTransform.h"
#include "string.h";
#include <itkSliceIterator.h>

#include <iostream>
#include <string>
#include <fstream>



static void CopyDictionary(itk::MetaDataDictionary &fromDict,
itk::MetaDataDictionary &toDict);

int main(int argc, char* argv[])
{
if (argc < 8)
{
std::cerr << "Uso: " << std::endl;
std::cerr << argv[0] << " Directorio_A_Rotar DirectorioResultante Gamma
Beta Alfa CentroRotacionX CentroRotacionY CentroRotacionZ"
<< std::endl;
return EXIT_FAILURE;
}

typedef signed short PixelType;
const unsigned int Dimension = 3;
const unsigned int Dimension_Serie = 2;
typedef itk::Image< PixelType, Dimension > ImageType;
typedef itk::Image<PixelType, Dimension_Serie> ImageType_Serie;

typedef itk::ImageSeriesReader< ImageType > ReaderType;
ReaderType::Pointer reader = ReaderType::New();

typedef itk::GDCMImageIO ImageIOType;
ImageIOType::Pointer gdcmIO = ImageIOType::New();
reader->SetImageIO(gdcmIO);

typedef itk::GDCMSeriesFileNames NamesGeneratorType;
NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
nameGenerator->SetUseSeriesDetails(true);
nameGenerator->AddSeriesRestriction("0008|0021");
nameGenerator->SetDirectory(argv[1]);

try
{
std::cout << std::endl << "The directory: " << std::endl;
std::cout << std::endl << argv[1] << std::endl << std::endl;
std::cout << "Contains the following DICOM Series: ";
std::cout << std::endl << std::endl;

typedef std::vector< std::string > SeriesIdContainer;
const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();
SeriesIdContainer::const_iterator seriesItr = seriesUID.begin();
SeriesIdContainer::const_iterator seriesEnd = seriesUID.end();
while (seriesItr != seriesEnd)
{
std::cout << seriesItr->c_str() << std::endl;
++seriesItr;
}

std::string seriesIdentifier;

seriesIdentifier = seriesUID.begin()->c_str();


std::cout << std::endl << std::endl;
std::cout << "Now reading series: " << std::endl << std::endl;
std::cout << seriesIdentifier << std::endl;
std::cout << std::endl << std::endl;

typedef std::vector< std::string > FileNamesContainer;
FileNamesContainer fileNames;
fileNames = nameGenerator->GetFileNames(seriesIdentifier);

reader->SetFileNames(fileNames);

try
{
reader->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}

const ImageType * inputImage = reader->GetOutput();
/*int numerodedicoms = inputImage->GetLargestPossibleRegion().GetSize()[2];
int dicomcentral = numerodedicoms / 2;
std::cout << "Dimenion " << dicomcentral << std::endl;*/
//itk::EncapsulateMetaData<std::string>(dictionary,
"0020|0032","-208\\-236\\66");

typedef itk::ResampleImageFilter<ImageType, ImageType> FilterType;
FilterType::Pointer FiltroResample = FilterType::New();
FiltroResample->SetInput(reader->GetOutput());

typedef itk::LinearInterpolateImageFunction<ImageType, double >
InterpolatorType;
InterpolatorType::Pointer interpolator = InterpolatorType::New();
FiltroResample->SetInterpolator(interpolator);
FiltroResample->SetOutputDirection(inputImage->GetDirection());
FiltroResample->SetOutputOrigin(inputImage->GetOrigin());

ImageType::SizeType inputSize =
inputImage->GetLargestPossibleRegion().GetSize();
FiltroResample->SetSize(inputSize);

const ImageType::SpacingType& inputSpacing = inputImage->GetSpacing();
FiltroResample->SetOutputSpacing(inputSpacing);

FiltroResample->SetDefaultPixelValue(-1000); //Cambiar por un parametro

typedef itk::Euler3DTransform< double > TransformType; //Transform
TransformType::Pointer transform = TransformType::New();
double alfa, beta, gamma, centro_rotacion_X, centro_rotacion_Y,
centro_rotacion_Z;
gamma = atof(argv[3]);
beta= atof(argv[4]);
alfa = atof(argv[5]);
centro_rotacion_X = atof(argv[6]);
centro_rotacion_Y = atof(argv[7]);
centro_rotacion_Z = atof(argv[8]);
transform->SetRotation(gamma, beta, alfa); //Radianes en el siguiente orden
en ITK: Gamma, Beta, Alfa | Ibarra
//double centro[3] = { -14.8371, -54.9443, 175.75 }; //XmmPromedio,
YmmPromedio, Z Central (mm): Leer directorio y tomar la del medio
double centro[3] = { centro_rotacion_X, centro_rotacion_Y,
centro_rotacion_Z }; //XmmPromedio, YmmPromedio, Z Central (mm): Leer
directorio y tomar la del medio
transform->SetCenter(centro);
std::cout << "Centro: " << std::endl << std::endl;
std::cout << transform->GetCenter() << std::endl;

FiltroResample->SetTransform(transform);
//FiltroResample->SetMetaDataDictionary(dictionary);
try
{
FiltroResample->Update();
}
catch (itk::ExceptionObject &ex)
{
return EXIT_FAILURE;
}



ReaderType::DictionaryRawPointer inputDict =
(*(reader->GetMetaDataDictionaryArray()))[0];
ReaderType::DictionaryArrayType outputArray;
//std::cout << "array: " << std::endl << outputArray[0] << std::endl;
// To keep the new series in the same study as the original we need
// to keep the same study UID. But we need new series and frame of
// reference UID's.
gdcm::UIDGenerator suid;
//std::string seriesUID = suid.Generate();
gdcm::UIDGenerator fuid;
std::string frameOfReferenceUID = fuid.Generate();

std::string studyUID;
std::string sopClassUID;
itk::ExposeMetaData<std::string>(*inputDict, "0020|000d", studyUID);
itk::ExposeMetaData<std::string>(*inputDict, "0008|0016", sopClassUID);
gdcmIO->KeepOriginalUIDOn();

using namespace std;
double myArray_Z[70]; //Cambiar esto por un argumento que especifica la
cantidad de imagenes.
double myArray_X[70]; //Cambiar esto por un argumento que especifica la
cantidad de imagenes.
double myArray_Y[70]; //Cambiar esto por un argumento que especifica la
cantidad de imagenes.

ifstream file("file.txt");
if (file.is_open())
{
for (int i = 0; i < 70; ++i) //Recordar cambiar por el argumento que
especifica cantidad de imagenes
{
file >> myArray_Z[i];
}
}
std::cout << "valor primer Z array: " << std::endl << std::endl;
std::cout << myArray_Z[0] << std::endl;

for (unsigned int f = 0; f < inputSize[2]; f++)
{
// Create a new dictionary for this slice
ReaderType::DictionaryRawPointer dict = new ReaderType::DictionaryType;

// Copy the dictionary from the first slice
CopyDictionary(*inputDict, *dict);

// Set the UID's for the study, series, SOP and frame of reference
itk::EncapsulateMetaData<std::string>(*dict, "0020|000d", studyUID);
//itk::EncapsulateMetaData<std::string>(*dict, "0020|000e", seriesUID);
itk::EncapsulateMetaData<std::string>(*dict, "0020|0052",
frameOfReferenceUID);

gdcm::UIDGenerator sopuid;
std::string sopInstanceUID = sopuid.Generate();

itk::EncapsulateMetaData<std::string>(*dict, "0008|0018", sopInstanceUID);
itk::EncapsulateMetaData<std::string>(*dict, "0002|0003", sopInstanceUID);

// Change fields that are slice specific
std::ostringstream value;
value.str("");
value << f + 1;

// Image Number
itk::EncapsulateMetaData<std::string>(*dict, "0020|0013", value.str());

// Series Description - Append new description to current series
// description
std::string oldSeriesDesc;
itk::ExposeMetaData<std::string>(*inputDict, "0008|103e", oldSeriesDesc);

value.str("");
value << oldSeriesDesc
<< ": Resampled with pixel spacing "
<< inputSpacing[0] << ", "
<< inputSpacing[1] << ", "
<< inputSpacing[2];
// This is an long string and there is a 64 character limit in the
// standard
unsigned lengthDesc = value.str().length();

std::string seriesDesc(value.str(), 0,
lengthDesc > 64 ? 64
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|103e", seriesDesc);

// Series Number
value.str("");
value << 1001;
itk::EncapsulateMetaData<std::string>(*dict, "0020|0011", value.str());

// Derivation Description - How this image was derived
value.str("");
for (int i = 0; i < argc; i++)
{
value << argv[i] << " ";
}

lengthDesc = value.str().length();
std::string derivationDesc(value.str(), 0,
lengthDesc > 1024 ? 1024
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|2111", derivationDesc);

// Image Position Patient: This is calculated by computing the
// physical coordinate of the first pixel in each slice.
ImageType::PointType position;
ImageType::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = myArray_Z[f];
FiltroResample->GetOutput()->TransformIndexToPhysicalPoint(index, position);

//El origen que calculamos en el proyecto no se toca. (Origen = origen -
average)

//Cambiamos el ImageOrientationPatient SOLAMENTE si el valor original en la
imagen es: 1\0\0\0\1\0. En el caso que se cambia el signo, se debe cambiar
el signo del origen
//value.str("");
//value << -1 << "\\" << 0 << "\\" << 0 << "\\" << 0 << "\\" << -1 << "\\"
<< 0; //PASAR ESTO POR ARGUMENTO!!!
//itk::EncapsulateMetaData<std::string>(*dict, "0020|0037", value.str());

value.str("");
value << -235.1629 << "\\" << -195.0557 << "\\" << myArray_Z[f]; //PASAR
ESTO POR ARGUMENTO!!! El origen - Centro
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032", value.str());


// Slice Location: For now, we store the z component of the Image
// Position Patient.
value.str("");
value << position[2];
itk::EncapsulateMetaData<std::string>(*dict, "0020|1041", value.str());

// Slice Thickness: For now, we store the z spacing
value.str("");
value << inputSpacing[2];
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
value.str());
// Spacing Between Slices
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
value.str());

// Save the dictionary
outputArray.push_back(dict);
}


typedef itk::ImageFileWriter< ImageType > WriterType;
WriterType::Pointer writer = WriterType::New();

typedef itk::ImageSeriesWriter< ImageType, ImageType_Serie >
SeriesWriterType;
SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();
seriesWriter->SetInput(FiltroResample->GetOutput());

writer->SetFileName(argv[2]);
writer->SetInput(FiltroResample->GetOutput());

itksys::SystemTools::MakeDirectory("Test"); //PASAR ESTO POR ARGUMENTO!!
typedef itk::NumericSeriesFileNames OutputNamesGeneratorType;
OutputNamesGeneratorType::Pointer outputNames =
OutputNamesGeneratorType::New();
std::string seriesFormat("Test"); //PASAR ESTO POR ARGUMENTO!!
seriesFormat = seriesFormat + "/" + "IM%d.dcm";
outputNames->SetSeriesFormat(seriesFormat.c_str());
outputNames->SetStartIndex(1);
outputNames->SetEndIndex(inputSize[2]);

seriesWriter->SetImageIO(gdcmIO);
seriesWriter->SetFileNames(outputNames->GetFileNames());
seriesWriter->SetMetaDataDictionaryArray(&outputArray);

std::cout << "Escribiendo la imagen como..." << std::endl << std::endl;
std::cout << argv[2] << std::endl << std::endl;

try
{
writer->Update();
seriesWriter->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}


}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}

return EXIT_SUCCESS;

}

void CopyDictionary(itk::MetaDataDictionary &fromDict,
itk::MetaDataDictionary &toDict)
{
typedef itk::MetaDataDictionary DictionaryType;

DictionaryType::ConstIterator itr = fromDict.Begin();
DictionaryType::ConstIterator end = fromDict.End();
typedef itk::MetaDataObject< std::string > MetaDataStringType;

while (itr != end)
{
itk::MetaDataObjectBase::Pointer entry = itr->second;

MetaDataStringType::Pointer entryvalue =
dynamic_cast<MetaDataStringType *>(entry.GetPointer());
if (entryvalue)
{
std::string tagkey = itr->first;
std::string tagvalue = entryvalue->GetMetaDataObjectValue();
itk::EncapsulateMetaData<std::string>(toDict, tagkey, tagvalue);
}
++itr;
}
}


El jue., 30 de mar. de 2017 a la(s) 11:25, Lowekamp, Bradley (NIH/NLM/LHC)
Post by Lowekamp, Bradley (NIH/NLM/LHC) [C]
Hello,
Writing correct DICOM continues to be a struggle with SimpleITK and ITK.
It is generally recommended to directly use GDCM or DCMTK to write a proper
DICOM series.
SimpleITK tries to keep things, well, simple and straight forward. But ITK
ties to do some smart things, which get in the way for certain uses with
SimpleITK. We are trying to document and develop a nominal set of DICOM
output operations that work in SimpleITK.
Do you have working C++ code that works for your intended operation? Can
you share a small section of code which does what you expect it C++?
Thank,
Brad
On Mar 30, 2017, at 8:49 AM, Matias <[hidden email]
Hi,
I've been dealing with ITK for years in C++ and now I would need to use
SimpleITK and C# as far as I can in a new proyect.
Is the SimpleITK SeriesWriter working for Dicom Files? Last time I tried
to
use it I had problems with the DicomTags, these would not copy or there
was
no method to copy the tags to the resulting slices.
Currently, I read a volume of slices, apply rotation and then I need to
write the resulting image as another set of slices AND keeping tag
information such as patient name, etc.
Thank you,
Matias.
--
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050.html
Sent from the ITK - Users mailing list archive at Nabble.com.
_____________________________________
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
_______________________________________________
Community mailing list
[hidden email] <http:///user/SendEmail.jtp?type=node&node=38052&i=1>
http://public.kitware.com/mailman/listinfo/community
_____________________________________
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
------------------------------
If you reply to this email, your message will be added to the discussion
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38052.html
To unsubscribe from SimpleITK Serieswriter and DicomTags, click here
<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=unsubscribe_by_code&node=38050&code=bWF0aW1vbnRnQGdtYWlsLmNvbXwzODA1MHwtMTk0NzIxNTA4Mw==>
.
NAML
<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
--
Matias




--
View this message in context: http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38056.html
Sent from the ITK - Users mailing list archive at Nabble.com.
Yaniv, Ziv Rafael (NIH/NLM/LHC) [C]
2017-03-31 22:17:37 UTC
Permalink
Hello Matias,

Please take a look at the following github pull request (https://github.com/SimpleITK/SimpleITK/pull/134), this branch should provide the functionality you are looking for. See the Python example script included in the commit for the usage of the DICOM series writing.

hope this helps
Ziv


From: Matias <***@gmail.com>
Date: Thursday, March 30, 2017 at 12:14 PM
To: "insight-***@itk.org" <insight-***@itk.org>
Subject: Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags

Yes, this is what I would need to migrate to C#:
It basically reads a dicom directory and performs rotation on the volume, then writes the resulting images back to a directory, copying the tags from the original images.

#include "itkImage.h"
#include "itkGDCMImageIO.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkImageSeriesReader.h"
#include "itkResampleImageFilter.h"
#include "itkEuler3DTransform.hxx"
#include "gdcmUIDGenerator.h"

#include "itkImageFileWriter.h"
#include "itkImageSeriesWriter.h"
#include "itkNumericSeriesFileNames.h"
#include "itkTranslationTransform.h"
#include "string.h";
#include <itkSliceIterator.h>

#include <iostream>
#include <string>
#include <fstream>



static void CopyDictionary(itk::MetaDataDictionary &fromDict,
itk::MetaDataDictionary &toDict);

int main(int argc, char* argv[])
{
if (argc < 8)
{
std::cerr << "Uso: " << std::endl;
std::cerr << argv[0] << " Directorio_A_Rotar DirectorioResultante Gamma Beta Alfa CentroRotacionX CentroRotacionY CentroRotacionZ"
<< std::endl;
return EXIT_FAILURE;
}

typedef signed short PixelType;
const unsigned int Dimension = 3;
const unsigned int Dimension_Serie = 2;
typedef itk::Image< PixelType, Dimension > ImageType;
typedef itk::Image<PixelType, Dimension_Serie> ImageType_Serie;

typedef itk::ImageSeriesReader< ImageType > ReaderType;
ReaderType::Pointer reader = ReaderType::New();

typedef itk::GDCMImageIO ImageIOType;
ImageIOType::Pointer gdcmIO = ImageIOType::New();
reader->SetImageIO(gdcmIO);

typedef itk::GDCMSeriesFileNames NamesGeneratorType;
NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
nameGenerator->SetUseSeriesDetails(true);
nameGenerator->AddSeriesRestriction("0008|0021");
nameGenerator->SetDirectory(argv[1]);

try
{
std::cout << std::endl << "The directory: " << std::endl;
std::cout << std::endl << argv[1] << std::endl << std::endl;
std::cout << "Contains the following DICOM Series: ";
std::cout << std::endl << std::endl;

typedef std::vector< std::string > SeriesIdContainer;
const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();
SeriesIdContainer::const_iterator seriesItr = seriesUID.begin();
SeriesIdContainer::const_iterator seriesEnd = seriesUID.end();
while (seriesItr != seriesEnd)
{
std::cout << seriesItr->c_str() << std::endl;
++seriesItr;
}

std::string seriesIdentifier;

seriesIdentifier = seriesUID.begin()->c_str();


std::cout << std::endl << std::endl;
std::cout << "Now reading series: " << std::endl << std::endl;
std::cout << seriesIdentifier << std::endl;
std::cout << std::endl << std::endl;

typedef std::vector< std::string > FileNamesContainer;
FileNamesContainer fileNames;
fileNames = nameGenerator->GetFileNames(seriesIdentifier);

reader->SetFileNames(fileNames);

try
{
reader->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}

const ImageType * inputImage = reader->GetOutput();
/*int numerodedicoms = inputImage->GetLargestPossibleRegion().GetSize()[2];
int dicomcentral = numerodedicoms / 2;
std::cout << "Dimenion " << dicomcentral << std::endl;*/
//itk::EncapsulateMetaData<std::string>(dictionary, "0020|0032","-208\\-236\\66");

typedef itk::ResampleImageFilter<ImageType, ImageType> FilterType;
FilterType::Pointer FiltroResample = FilterType::New();
FiltroResample->SetInput(reader->GetOutput());

typedef itk::LinearInterpolateImageFunction<ImageType, double > InterpolatorType;
InterpolatorType::Pointer interpolator = InterpolatorType::New();
FiltroResample->SetInterpolator(interpolator);
FiltroResample->SetOutputDirection(inputImage->GetDirection());
FiltroResample->SetOutputOrigin(inputImage->GetOrigin());

ImageType::SizeType inputSize = inputImage->GetLargestPossibleRegion().GetSize();
FiltroResample->SetSize(inputSize);

const ImageType::SpacingType& inputSpacing = inputImage->GetSpacing();
FiltroResample->SetOutputSpacing(inputSpacing);

FiltroResample->SetDefaultPixelValue(-1000); //Cambiar por un parametro

typedef itk::Euler3DTransform< double > TransformType; //Transform
TransformType::Pointer transform = TransformType::New();
double alfa, beta, gamma, centro_rotacion_X, centro_rotacion_Y, centro_rotacion_Z;
gamma = atof(argv[3]);
beta= atof(argv[4]);
alfa = atof(argv[5]);
centro_rotacion_X = atof(argv[6]);
centro_rotacion_Y = atof(argv[7]);
centro_rotacion_Z = atof(argv[8]);
transform->SetRotation(gamma, beta, alfa); //Radianes en el siguiente orden en ITK: Gamma, Beta, Alfa | Ibarra
//double centro[3] = { -14.8371, -54.9443, 175.75 }; //XmmPromedio, YmmPromedio, Z Central (mm): Leer directorio y tomar la del medio
double centro[3] = { centro_rotacion_X, centro_rotacion_Y, centro_rotacion_Z }; //XmmPromedio, YmmPromedio, Z Central (mm): Leer directorio y tomar la del medio
transform->SetCenter(centro);
std::cout << "Centro: " << std::endl << std::endl;
std::cout << transform->GetCenter() << std::endl;

FiltroResample->SetTransform(transform);
//FiltroResample->SetMetaDataDictionary(dictionary);
try
{
FiltroResample->Update();
}
catch (itk::ExceptionObject &ex)
{
return EXIT_FAILURE;
}



ReaderType::DictionaryRawPointer inputDict = (*(reader->GetMetaDataDictionaryArray()))[0];
ReaderType::DictionaryArrayType outputArray;
//std::cout << "array: " << std::endl << outputArray[0] << std::endl;
// To keep the new series in the same study as the original we need
// to keep the same study UID. But we need new series and frame of
// reference UID's.
gdcm::UIDGenerator suid;
//std::string seriesUID = suid.Generate();
gdcm::UIDGenerator fuid;
std::string frameOfReferenceUID = fuid.Generate();

std::string studyUID;
std::string sopClassUID;
itk::ExposeMetaData<std::string>(*inputDict, "0020|000d", studyUID);
itk::ExposeMetaData<std::string>(*inputDict, "0008|0016", sopClassUID);
gdcmIO->KeepOriginalUIDOn();

using namespace std;
double myArray_Z[70]; //Cambiar esto por un argumento que especifica la cantidad de imagenes.
double myArray_X[70]; //Cambiar esto por un argumento que especifica la cantidad de imagenes.
double myArray_Y[70]; //Cambiar esto por un argumento que especifica la cantidad de imagenes.

ifstream file("file.txt");
if (file.is_open())
{
for (int i = 0; i < 70; ++i) //Recordar cambiar por el argumento que especifica cantidad de imagenes
{
file >> myArray_Z[i];
}
}
std::cout << "valor primer Z array: " << std::endl << std::endl;
std::cout << myArray_Z[0] << std::endl;

for (unsigned int f = 0; f < inputSize[2]; f++)
{
// Create a new dictionary for this slice
ReaderType::DictionaryRawPointer dict = new ReaderType::DictionaryType;

// Copy the dictionary from the first slice
CopyDictionary(*inputDict, *dict);

// Set the UID's for the study, series, SOP and frame of reference
itk::EncapsulateMetaData<std::string>(*dict, "0020|000d", studyUID);
//itk::EncapsulateMetaData<std::string>(*dict, "0020|000e", seriesUID);
itk::EncapsulateMetaData<std::string>(*dict, "0020|0052", frameOfReferenceUID);

gdcm::UIDGenerator sopuid;
std::string sopInstanceUID = sopuid.Generate();

itk::EncapsulateMetaData<std::string>(*dict, "0008|0018", sopInstanceUID);
itk::EncapsulateMetaData<std::string>(*dict, "0002|0003", sopInstanceUID);

// Change fields that are slice specific
std::ostringstream value;
value.str("");
value << f + 1;

// Image Number
itk::EncapsulateMetaData<std::string>(*dict, "0020|0013", value.str());

// Series Description - Append new description to current series
// description
std::string oldSeriesDesc;
itk::ExposeMetaData<std::string>(*inputDict, "0008|103e", oldSeriesDesc);

value.str("");
value << oldSeriesDesc
<< ": Resampled with pixel spacing "
<< inputSpacing[0] << ", "
<< inputSpacing[1] << ", "
<< inputSpacing[2];
// This is an long string and there is a 64 character limit in the
// standard
unsigned lengthDesc = value.str().length();

std::string seriesDesc(value.str(), 0,
lengthDesc > 64 ? 64
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|103e", seriesDesc);

// Series Number
value.str("");
value << 1001;
itk::EncapsulateMetaData<std::string>(*dict, "0020|0011", value.str());

// Derivation Description - How this image was derived
value.str("");
for (int i = 0; i < argc; i++)
{
value << argv[i] << " ";
}

lengthDesc = value.str().length();
std::string derivationDesc(value.str(), 0,
lengthDesc > 1024 ? 1024
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|2111", derivationDesc);

// Image Position Patient: This is calculated by computing the
// physical coordinate of the first pixel in each slice.
ImageType::PointType position;
ImageType::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = myArray_Z[f];
FiltroResample->GetOutput()->TransformIndexToPhysicalPoint(index, position);

//El origen que calculamos en el proyecto no se toca. (Origen = origen - average)

//Cambiamos el ImageOrientationPatient SOLAMENTE si el valor original en la imagen es: 1\0\0\0\1\0. En el caso que se cambia el signo, se debe cambiar el signo del origen
//value.str("");
//value << -1 << "\\" << 0 << "\\" << 0 << "\\" << 0 << "\\" << -1 << "\\" << 0; //PASAR ESTO POR ARGUMENTO!!!
//itk::EncapsulateMetaData<std::string>(*dict, "0020|0037", value.str());

value.str("");
value << -235.1629 << "\\" << -195.0557 << "\\" << myArray_Z[f]; //PASAR ESTO POR ARGUMENTO!!! El origen - Centro
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032", value.str());


// Slice Location: For now, we store the z component of the Image
// Position Patient.
value.str("");
value << position[2];
itk::EncapsulateMetaData<std::string>(*dict, "0020|1041", value.str());

// Slice Thickness: For now, we store the z spacing
value.str("");
value << inputSpacing[2];
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
value.str());
// Spacing Between Slices
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
value.str());

// Save the dictionary
outputArray.push_back(dict);
}


typedef itk::ImageFileWriter< ImageType > WriterType;
WriterType::Pointer writer = WriterType::New();

typedef itk::ImageSeriesWriter< ImageType, ImageType_Serie > SeriesWriterType;
SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();
seriesWriter->SetInput(FiltroResample->GetOutput());

writer->SetFileName(argv[2]);
writer->SetInput(FiltroResample->GetOutput());

itksys::SystemTools::MakeDirectory("Test"); //PASAR ESTO POR ARGUMENTO!!
typedef itk::NumericSeriesFileNames OutputNamesGeneratorType;
OutputNamesGeneratorType::Pointer outputNames = OutputNamesGeneratorType::New();
std::string seriesFormat("Test"); //PASAR ESTO POR ARGUMENTO!!
seriesFormat = seriesFormat + "/" + "IM%d.dcm";
outputNames->SetSeriesFormat(seriesFormat.c_str());
outputNames->SetStartIndex(1);
outputNames->SetEndIndex(inputSize[2]);

seriesWriter->SetImageIO(gdcmIO);
seriesWriter->SetFileNames(outputNames->GetFileNames());
seriesWriter->SetMetaDataDictionaryArray(&outputArray);

std::cout << "Escribiendo la imagen como..." << std::endl << std::endl;
std::cout << argv[2] << std::endl << std::endl;

try
{
writer->Update();
seriesWriter->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}


}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}

return EXIT_SUCCESS;

}

void CopyDictionary(itk::MetaDataDictionary &fromDict, itk::MetaDataDictionary &toDict)
{
typedef itk::MetaDataDictionary DictionaryType;

DictionaryType::ConstIterator itr = fromDict.Begin();
DictionaryType::ConstIterator end = fromDict.End();
typedef itk::MetaDataObject< std::string > MetaDataStringType;

while (itr != end)
{
itk::MetaDataObjectBase::Pointer entry = itr->second;

MetaDataStringType::Pointer entryvalue =
dynamic_cast<MetaDataStringType *>(entry.GetPointer());
if (entryvalue)
{
std::string tagkey = itr->first;
std::string tagvalue = entryvalue->GetMetaDataObjectValue();
itk::EncapsulateMetaData<std::string>(toDict, tagkey, tagvalue);
}
++itr;
}
}


El jue., 30 de mar. de 2017 a la(s) 11:25, Lowekamp, Bradley (NIH/NLM/LHC) [C] [via ITK - Users] <[hidden email]<file:////user/SendEmail.jtp%3ftype=node&node=38056&i=0>> escribió:
Hello,

Writing correct DICOM continues to be a struggle with SimpleITK and ITK. It is generally recommended to directly use GDCM or DCMTK to write a proper DICOM series.

SimpleITK tries to keep things, well, simple and straight forward. But ITK ties to do some smart things, which get in the way for certain uses with SimpleITK. We are trying to document and develop a nominal set of DICOM output operations that work in SimpleITK.

Do you have working C++ code that works for your intended operation? Can you share a small section of code which does what you expect it C++?

Thank,
Brad
Post by Matias
Hi,
I've been dealing with ITK for years in C++ and now I would need to use
SimpleITK and C# as far as I can in a new proyect.
Is the SimpleITK SeriesWriter working for Dicom Files? Last time I tried to
use it I had problems with the DicomTags, these would not copy or there was
no method to copy the tags to the resulting slices.
Currently, I read a volume of slices, apply rotation and then I need to
write the resulting image as another set of slices AND keeping tag
information such as patient name, etc.
Thank you,
Matias.
--
View this message in context: http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050.html
Sent from the ITK - Users mailing list archive at Nabble.com.
_____________________________________
Powered by www.kitware.com<http://www.kitware.com>
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
_______________________________________________
Community mailing list
[hidden email]<http://user/SendEmail.jtp?type=node&node=38052&i=1>
http://public.kitware.com/mailman/listinfo/community
_____________________________________
Powered by www.kitware.com<http://www.kitware.com>

Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html

Kitware offers ITK Training Courses, for more information visit:
http://www.kitware.com/products/protraining.php

Please keep messages on-topic and check the ITK FAQ at:
http://www.itk.org/Wiki/ITK_FAQ

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/insight-users

________________________________
If you reply to this email, your message will be added to the discussion below:
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38052.html
To unsubscribe from SimpleITK Serieswriter and DicomTags, click here.
NAML<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
--
Matias

________________________________
View this message in context: Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags<http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38056.html>
Sent from the ITK - Users mailing list archive<http://itk-users.7.n7.nabble.com/> at Nabble.com.
Matias
2017-04-01 06:48:08 UTC
Permalink
Thanks Yaniv. So how do I get this branch? I simply download the latest
version of SimpleITK?

El vie., 31 de mar. de 2017 a la(s) 19:18, Yaniv, Ziv Rafael (NIH/NLM/LHC)
Post by Yaniv, Ziv Rafael (NIH/NLM/LHC) [C]
Hello Matias,
Please take a look at the following github pull request (
https://github.com/SimpleITK/SimpleITK/pull/134), this branch should
provide the functionality you are looking for. See the Python example
script included in the commit for the usage of the DICOM series writing.
hope this helps
Ziv
*From: *Matias <[hidden email]
<http:///user/SendEmail.jtp?type=node&node=38063&i=0>>
*Date: *Thursday, March 30, 2017 at 12:14 PM
*To: *"[hidden email]
<http:///user/SendEmail.jtp?type=node&node=38063&i=1>" <[hidden email]
<http:///user/SendEmail.jtp?type=node&node=38063&i=2>>
*Subject: *Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags
It basically reads a dicom directory and performs rotation on the volume,
then writes the resulting images back to a directory, copying the tags from
the original images.
#include "itkImage.h"
#include "itkGDCMImageIO.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkImageSeriesReader.h"
#include "itkResampleImageFilter.h"
#include "itkEuler3DTransform.hxx"
#include "gdcmUIDGenerator.h"
#include "itkImageFileWriter.h"
#include "itkImageSeriesWriter.h"
#include "itkNumericSeriesFileNames.h"
#include "itkTranslationTransform.h"
#include "string.h";
#include <itkSliceIterator.h>
#include <iostream>
#include <string>
#include <fstream>
static void CopyDictionary(itk::MetaDataDictionary &fromDict,
itk::MetaDataDictionary &toDict);
int main(int argc, char* argv[])
{
if (argc < 8)
{
std::cerr << "Uso: " << std::endl;
std::cerr << argv[0] << " Directorio_A_Rotar DirectorioResultante Gamma
Beta Alfa CentroRotacionX CentroRotacionY CentroRotacionZ"
<< std::endl;
return EXIT_FAILURE;
}
typedef signed short PixelType;
const unsigned int Dimension = 3;
const unsigned int Dimension_Serie = 2;
typedef itk::Image< PixelType, Dimension > ImageType;
typedef itk::Image<PixelType, Dimension_Serie> ImageType_Serie;
typedef itk::ImageSeriesReader< ImageType > ReaderType;
ReaderType::Pointer reader = ReaderType::New();
typedef itk::GDCMImageIO ImageIOType;
ImageIOType::Pointer gdcmIO = ImageIOType::New();
reader->SetImageIO(gdcmIO);
typedef itk::GDCMSeriesFileNames NamesGeneratorType;
NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
nameGenerator->SetUseSeriesDetails(true);
nameGenerator->AddSeriesRestriction("0008|0021");
nameGenerator->SetDirectory(argv[1]);
try
{
std::cout << std::endl << "The directory: " << std::endl;
std::cout << std::endl << argv[1] << std::endl << std::endl;
std::cout << "Contains the following DICOM Series: ";
std::cout << std::endl << std::endl;
typedef std::vector< std::string > SeriesIdContainer;
const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();
SeriesIdContainer::const_iterator seriesItr = seriesUID.begin();
SeriesIdContainer::const_iterator seriesEnd = seriesUID.end();
while (seriesItr != seriesEnd)
{
std::cout << seriesItr->c_str() << std::endl;
++seriesItr;
}
std::string seriesIdentifier;
seriesIdentifier = seriesUID.begin()->c_str();
std::cout << std::endl << std::endl;
std::cout << "Now reading series: " << std::endl << std::endl;
std::cout << seriesIdentifier << std::endl;
std::cout << std::endl << std::endl;
typedef std::vector< std::string > FileNamesContainer;
FileNamesContainer fileNames;
fileNames = nameGenerator->GetFileNames(seriesIdentifier);
reader->SetFileNames(fileNames);
try
{
reader->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}
const ImageType * inputImage = reader->GetOutput();
/*int numerodedicoms = inputImage->GetLargestPossibleRegion().GetSize()[2];
int dicomcentral = numerodedicoms / 2;
std::cout << "Dimenion " << dicomcentral << std::endl;*/
//itk::EncapsulateMetaData<std::string>(dictionary,
"0020|0032","-208\\-236\\66");
typedef itk::ResampleImageFilter<ImageType, ImageType> FilterType;
FilterType::Pointer FiltroResample = FilterType::New();
FiltroResample->SetInput(reader->GetOutput());
typedef itk::LinearInterpolateImageFunction<ImageType, double > InterpolatorType;
InterpolatorType::Pointer interpolator = InterpolatorType::New();
FiltroResample->SetInterpolator(interpolator);
FiltroResample->SetOutputDirection(inputImage->GetDirection());
FiltroResample->SetOutputOrigin(inputImage->GetOrigin());
ImageType::SizeType inputSize =
inputImage->GetLargestPossibleRegion().GetSize();
FiltroResample->SetSize(inputSize);
const ImageType::SpacingType& inputSpacing = inputImage->GetSpacing();
FiltroResample->SetOutputSpacing(inputSpacing);
FiltroResample->SetDefaultPixelValue(-1000); //Cambiar por un parametro
typedef itk::Euler3DTransform< double > TransformType; //Transform
TransformType::Pointer transform = TransformType::New();
double alfa, beta, gamma, centro_rotacion_X, centro_rotacion_Y, centro_rotacion_Z;
gamma = atof(argv[3]);
beta= atof(argv[4]);
alfa = atof(argv[5]);
centro_rotacion_X = atof(argv[6]);
centro_rotacion_Y = atof(argv[7]);
centro_rotacion_Z = atof(argv[8]);
transform->SetRotation(gamma, beta, alfa); //Radianes en el siguiente
orden en ITK: Gamma, Beta, Alfa | Ibarra
//double centro[3] = { -14.8371, -54.9443, 175.75 }; //XmmPromedio,
YmmPromedio, Z Central (mm): Leer directorio y tomar la del medio
double centro[3] = { centro_rotacion_X, centro_rotacion_Y,
centro_rotacion_Z }; //XmmPromedio, YmmPromedio, Z Central (mm): Leer
directorio y tomar la del medio
transform->SetCenter(centro);
std::cout << "Centro: " << std::endl << std::endl;
std::cout << transform->GetCenter() << std::endl;
FiltroResample->SetTransform(transform);
//FiltroResample->SetMetaDataDictionary(dictionary);
try
{
FiltroResample->Update();
}
catch (itk::ExceptionObject &ex)
{
return EXIT_FAILURE;
}
ReaderType::DictionaryRawPointer inputDict =
(*(reader->GetMetaDataDictionaryArray()))[0];
ReaderType::DictionaryArrayType outputArray;
//std::cout << "array: " << std::endl << outputArray[0] << std::endl;
// To keep the new series in the same study as the original we need
// to keep the same study UID. But we need new series and frame of
// reference UID's.
gdcm::UIDGenerator suid;
//std::string seriesUID = suid.Generate();
gdcm::UIDGenerator fuid;
std::string frameOfReferenceUID = fuid.Generate();
std::string studyUID;
std::string sopClassUID;
itk::ExposeMetaData<std::string>(*inputDict, "0020|000d", studyUID);
itk::ExposeMetaData<std::string>(*inputDict, "0008|0016", sopClassUID);
gdcmIO->KeepOriginalUIDOn();
using namespace std;
double myArray_Z[70]; //Cambiar esto por un argumento que especifica la
cantidad de imagenes.
double myArray_X[70]; //Cambiar esto por un argumento que especifica la
cantidad de imagenes.
double myArray_Y[70]; //Cambiar esto por un argumento que especifica la
cantidad de imagenes.
ifstream file("file.txt");
if (file.is_open())
{
for (int i = 0; i < 70; ++i) //Recordar cambiar por el argumento que
especifica cantidad de imagenes
{
file >> myArray_Z[i];
}
}
std::cout << "valor primer Z array: " << std::endl << std::endl;
std::cout << myArray_Z[0] << std::endl;
for (unsigned int f = 0; f < inputSize[2]; f++)
{
// Create a new dictionary for this slice
ReaderType::DictionaryRawPointer dict = new ReaderType::DictionaryType;
// Copy the dictionary from the first slice
CopyDictionary(*inputDict, *dict);
// Set the UID's for the study, series, SOP and frame of reference
itk::EncapsulateMetaData<std::string>(*dict, "0020|000d", studyUID);
//itk::EncapsulateMetaData<std::string>(*dict, "0020|000e", seriesUID);
itk::EncapsulateMetaData<std::string>(*dict, "0020|0052",
frameOfReferenceUID);
gdcm::UIDGenerator sopuid;
std::string sopInstanceUID = sopuid.Generate();
itk::EncapsulateMetaData<std::string>(*dict, "0008|0018", sopInstanceUID);
itk::EncapsulateMetaData<std::string>(*dict, "0002|0003", sopInstanceUID);
// Change fields that are slice specific
std::ostringstream value;
value.str("");
value << f + 1;
// Image Number
itk::EncapsulateMetaData<std::string>(*dict, "0020|0013", value.str());
// Series Description - Append new description to current series
// description
std::string oldSeriesDesc;
itk::ExposeMetaData<std::string>(*inputDict, "0008|103e", oldSeriesDesc);
value.str("");
value << oldSeriesDesc
<< ": Resampled with pixel spacing "
<< inputSpacing[0] << ", "
<< inputSpacing[1] << ", "
<< inputSpacing[2];
// This is an long string and there is a 64 character limit in the
// standard
unsigned lengthDesc = value.str().length();
std::string seriesDesc(value.str(), 0,
lengthDesc > 64 ? 64
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|103e", seriesDesc);
// Series Number
value.str("");
value << 1001;
itk::EncapsulateMetaData<std::string>(*dict, "0020|0011", value.str());
// Derivation Description - How this image was derived
value.str("");
for (int i = 0; i < argc; i++)
{
value << argv[i] << " ";
}
lengthDesc = value.str().length();
std::string derivationDesc(value.str(), 0,
lengthDesc > 1024 ? 1024
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|2111", derivationDesc);
// Image Position Patient: This is calculated by computing the
// physical coordinate of the first pixel in each slice.
ImageType::PointType position;
ImageType::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = myArray_Z[f];
FiltroResample->GetOutput()->TransformIndexToPhysicalPoint(index, position);
//El origen que calculamos en el proyecto no se toca. (Origen = origen - average)
//Cambiamos el ImageOrientationPatient SOLAMENTE si el valor original en
la imagen es: 1\0\0\0\1\0. En el caso que se cambia el signo, se debe
cambiar el signo del origen
//value.str("");
//value << -1 << "\\" << 0 << "\\" << 0 << "\\" << 0 << "\\" << -1 << "\\"
<< 0; //PASAR ESTO POR ARGUMENTO!!!
//itk::EncapsulateMetaData<std::string>(*dict, "0020|0037", value.str());
value.str("");
value << -235.1629 << "\\" << -195.0557 << "\\" << myArray_Z[f]; //PASAR
ESTO POR ARGUMENTO!!! El origen - Centro
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032", value.str());
// Slice Location: For now, we store the z component of the Image
// Position Patient.
value.str("");
value << position[2];
itk::EncapsulateMetaData<std::string>(*dict, "0020|1041", value.str());
// Slice Thickness: For now, we store the z spacing
value.str("");
value << inputSpacing[2];
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
value.str());
// Spacing Between Slices
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
value.str());
// Save the dictionary
outputArray.push_back(dict);
}
typedef itk::ImageFileWriter< ImageType > WriterType;
WriterType::Pointer writer = WriterType::New();
typedef itk::ImageSeriesWriter< ImageType, ImageType_Serie >
SeriesWriterType;
SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();
seriesWriter->SetInput(FiltroResample->GetOutput());
writer->SetFileName(argv[2]);
writer->SetInput(FiltroResample->GetOutput());
itksys::SystemTools::MakeDirectory("Test"); //PASAR ESTO POR ARGUMENTO!!
typedef itk::NumericSeriesFileNames OutputNamesGeneratorType;
OutputNamesGeneratorType::Pointer outputNames =
OutputNamesGeneratorType::New();
std::string seriesFormat("Test"); //PASAR ESTO POR ARGUMENTO!!
seriesFormat = seriesFormat + "/" + "IM%d.dcm";
outputNames->SetSeriesFormat(seriesFormat.c_str());
outputNames->SetStartIndex(1);
outputNames->SetEndIndex(inputSize[2]);
seriesWriter->SetImageIO(gdcmIO);
seriesWriter->SetFileNames(outputNames->GetFileNames());
seriesWriter->SetMetaDataDictionaryArray(&outputArray);
std::cout << "Escribiendo la imagen como..." << std::endl << std::endl;
std::cout << argv[2] << std::endl << std::endl;
try
{
writer->Update();
seriesWriter->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
void CopyDictionary(itk::MetaDataDictionary &fromDict,
itk::MetaDataDictionary &toDict)
{
typedef itk::MetaDataDictionary DictionaryType;
DictionaryType::ConstIterator itr = fromDict.Begin();
DictionaryType::ConstIterator end = fromDict.End();
typedef itk::MetaDataObject< std::string > MetaDataStringType;
while (itr != end)
{
itk::MetaDataObjectBase::Pointer entry = itr->second;
MetaDataStringType::Pointer entryvalue =
dynamic_cast<MetaDataStringType *>(entry.GetPointer());
if (entryvalue)
{
std::string tagkey = itr->first;
std::string tagvalue = entryvalue->GetMetaDataObjectValue();
itk::EncapsulateMetaData<std::string>(toDict, tagkey, tagvalue);
}
++itr;
}
}
El jue., 30 de mar. de 2017 a la(s) 11:25, Lowekamp, Bradley (NIH/NLM/LHC)
Hello,
Writing correct DICOM continues to be a struggle with SimpleITK and ITK.
It is generally recommended to directly use GDCM or DCMTK to write a proper
DICOM series.
SimpleITK tries to keep things, well, simple and straight forward. But ITK
ties to do some smart things, which get in the way for certain uses with
SimpleITK. We are trying to document and develop a nominal set of DICOM
output operations that work in SimpleITK.
Do you have working C++ code that works for your intended operation? Can
you share a small section of code which does what you expect it C++?
Thank,
Brad
On Mar 30, 2017, at 8:49 AM, Matias <[hidden email]
Hi,
I've been dealing with ITK for years in C++ and now I would need to use
SimpleITK and C# as far as I can in a new proyect.
Is the SimpleITK SeriesWriter working for Dicom Files? Last time I tried
to
use it I had problems with the DicomTags, these would not copy or there
was
no method to copy the tags to the resulting slices.
Currently, I read a volume of slices, apply rotation and then I need to
write the resulting image as another set of slices AND keeping tag
information such as patient name, etc.
Thank you,
Matias.
--
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050.html
Sent from the ITK - Users mailing list archive at Nabble.com.
_____________________________________
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
_______________________________________________
Community mailing list
[hidden email] <http://user/SendEmail.jtp?type=node&node=38052&i=1>
http://public.kitware.com/mailman/listinfo/community
_____________________________________
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
------------------------------
*If you reply to this email, your message will be added to the discussion
below:*
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38052.html
To unsubscribe from SimpleITK Serieswriter and DicomTags, click here.
NAML
<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
--
Matias
------------------------------
View this message in context: Re: [ITK-users] [ITK] SimpleITK
Serieswriter and DicomTags
<http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38056.html>
Sent from the ITK - Users mailing list archive
<http://itk-users.7.n7.nabble.com/> at Nabble.com.
_____________________________________
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38063.html
To unsubscribe from SimpleITK Serieswriter and DicomTags, click here
<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=unsubscribe_by_code&node=38050&code=bWF0aW1vbnRnQGdtYWlsLmNvbXwzODA1MHwtMTk0NzIxNTA4Mw==>
.
NAML
<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
--
Matias




--
View this message in context: http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38064.html
Sent from the ITK - Users mailing list archive at Nabble.com.
Dženan Zukić
2017-04-01 13:37:05 UTC
Permalink
Hi Matias,

you should use branch dicomWrite from Ziv's fork
<https://github.com/zivy/SimpleITK/tree/dicomWrite>.

Regards,
DÅŸenan
Post by Matias
Thanks Yaniv. So how do I get this branch? I simply download the latest
version of SimpleITK?
El vie., 31 de mar. de 2017 a la(s) 19:18, Yaniv, Ziv Rafael (NIH/NLM/LHC)
[C] [via ITK - Users] <[hidden email]
Post by Yaniv, Ziv Rafael (NIH/NLM/LHC) [C]
Hello Matias,
Please take a look at the following github pull request (
https://github.com/SimpleITK/SimpleITK/pull/134), this branch should
provide the functionality you are looking for. See the Python example
script included in the commit for the usage of the DICOM series writing.
hope this helps
Ziv
*From: *Matias <[hidden email]
<http:///user/SendEmail.jtp?type=node&node=38063&i=0>>
*Date: *Thursday, March 30, 2017 at 12:14 PM
*To: *"[hidden email]
<http:///user/SendEmail.jtp?type=node&node=38063&i=1>" <[hidden email]
<http:///user/SendEmail.jtp?type=node&node=38063&i=2>>
*Subject: *Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags
It basically reads a dicom directory and performs rotation on the volume,
then writes the resulting images back to a directory, copying the tags from
the original images.
#include "itkImage.h"
#include "itkGDCMImageIO.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkImageSeriesReader.h"
#include "itkResampleImageFilter.h"
#include "itkEuler3DTransform.hxx"
#include "gdcmUIDGenerator.h"
#include "itkImageFileWriter.h"
#include "itkImageSeriesWriter.h"
#include "itkNumericSeriesFileNames.h"
#include "itkTranslationTransform.h"
#include "string.h";
#include <itkSliceIterator.h>
#include <iostream>
#include <string>
#include <fstream>
static void CopyDictionary(itk::MetaDataDictionary &fromDict,
itk::MetaDataDictionary &toDict);
int main(int argc, char* argv[])
{
if (argc < 8)
{
std::cerr << "Uso: " << std::endl;
std::cerr << argv[0] << " Directorio_A_Rotar DirectorioResultante Gamma
Beta Alfa CentroRotacionX CentroRotacionY CentroRotacionZ"
<< std::endl;
return EXIT_FAILURE;
}
typedef signed short PixelType;
const unsigned int Dimension = 3;
const unsigned int Dimension_Serie = 2;
typedef itk::Image< PixelType, Dimension > ImageType;
typedef itk::Image<PixelType, Dimension_Serie> ImageType_Serie;
typedef itk::ImageSeriesReader< ImageType > ReaderType;
ReaderType::Pointer reader = ReaderType::New();
typedef itk::GDCMImageIO ImageIOType;
ImageIOType::Pointer gdcmIO = ImageIOType::New();
reader->SetImageIO(gdcmIO);
typedef itk::GDCMSeriesFileNames NamesGeneratorType;
NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
nameGenerator->SetUseSeriesDetails(true);
nameGenerator->AddSeriesRestriction("0008|0021");
nameGenerator->SetDirectory(argv[1]);
try
{
std::cout << std::endl << "The directory: " << std::endl;
std::cout << std::endl << argv[1] << std::endl << std::endl;
std::cout << "Contains the following DICOM Series: ";
std::cout << std::endl << std::endl;
typedef std::vector< std::string > SeriesIdContainer;
const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();
SeriesIdContainer::const_iterator seriesItr = seriesUID.begin();
SeriesIdContainer::const_iterator seriesEnd = seriesUID.end();
while (seriesItr != seriesEnd)
{
std::cout << seriesItr->c_str() << std::endl;
++seriesItr;
}
std::string seriesIdentifier;
seriesIdentifier = seriesUID.begin()->c_str();
std::cout << std::endl << std::endl;
std::cout << "Now reading series: " << std::endl << std::endl;
std::cout << seriesIdentifier << std::endl;
std::cout << std::endl << std::endl;
typedef std::vector< std::string > FileNamesContainer;
FileNamesContainer fileNames;
fileNames = nameGenerator->GetFileNames(seriesIdentifier);
reader->SetFileNames(fileNames);
try
{
reader->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}
const ImageType * inputImage = reader->GetOutput();
/*int numerodedicoms = inputImage->GetLargestPossibleRegion().
GetSize()[2];
int dicomcentral = numerodedicoms / 2;
std::cout << "Dimenion " << dicomcentral << std::endl;*/
//itk::EncapsulateMetaData<std::string>(dictionary,
"0020|0032","-208\\-236\\66");
typedef itk::ResampleImageFilter<ImageType, ImageType> FilterType;
FilterType::Pointer FiltroResample = FilterType::New();
FiltroResample->SetInput(reader->GetOutput());
typedef itk::LinearInterpolateImageFunction<ImageType, double > InterpolatorType;
InterpolatorType::Pointer interpolator = InterpolatorType::New();
FiltroResample->SetInterpolator(interpolator);
FiltroResample->SetOutputDirection(inputImage->GetDirection());
FiltroResample->SetOutputOrigin(inputImage->GetOrigin());
ImageType::SizeType inputSize = inputImage->GetLargestPossibleRegion().
GetSize();
FiltroResample->SetSize(inputSize);
const ImageType::SpacingType& inputSpacing = inputImage->GetSpacing();
FiltroResample->SetOutputSpacing(inputSpacing);
FiltroResample->SetDefaultPixelValue(-1000); //Cambiar por un parametro
typedef itk::Euler3DTransform< double > TransformType; //Transform
TransformType::Pointer transform = TransformType::New();
double alfa, beta, gamma, centro_rotacion_X, centro_rotacion_Y, centro_rotacion_Z;
gamma = atof(argv[3]);
beta= atof(argv[4]);
alfa = atof(argv[5]);
centro_rotacion_X = atof(argv[6]);
centro_rotacion_Y = atof(argv[7]);
centro_rotacion_Z = atof(argv[8]);
transform->SetRotation(gamma, beta, alfa); //Radianes en el siguiente
orden en ITK: Gamma, Beta, Alfa | Ibarra
//double centro[3] = { -14.8371, -54.9443, 175.75 }; //XmmPromedio,
YmmPromedio, Z Central (mm): Leer directorio y tomar la del medio
double centro[3] = { centro_rotacion_X, centro_rotacion_Y,
centro_rotacion_Z }; //XmmPromedio, YmmPromedio, Z Central (mm): Leer
directorio y tomar la del medio
transform->SetCenter(centro);
std::cout << "Centro: " << std::endl << std::endl;
std::cout << transform->GetCenter() << std::endl;
FiltroResample->SetTransform(transform);
//FiltroResample->SetMetaDataDictionary(dictionary);
try
{
FiltroResample->Update();
}
catch (itk::ExceptionObject &ex)
{
return EXIT_FAILURE;
}
ReaderType::DictionaryRawPointer inputDict = (*(reader->
GetMetaDataDictionaryArray()))[0];
ReaderType::DictionaryArrayType outputArray;
//std::cout << "array: " << std::endl << outputArray[0] << std::endl;
// To keep the new series in the same study as the original we need
// to keep the same study UID. But we need new series and frame of
// reference UID's.
gdcm::UIDGenerator suid;
//std::string seriesUID = suid.Generate();
gdcm::UIDGenerator fuid;
std::string frameOfReferenceUID = fuid.Generate();
std::string studyUID;
std::string sopClassUID;
itk::ExposeMetaData<std::string>(*inputDict, "0020|000d", studyUID);
itk::ExposeMetaData<std::string>(*inputDict, "0008|0016", sopClassUID);
gdcmIO->KeepOriginalUIDOn();
using namespace std;
double myArray_Z[70]; //Cambiar esto por un argumento que especifica la
cantidad de imagenes.
double myArray_X[70]; //Cambiar esto por un argumento que especifica la
cantidad de imagenes.
double myArray_Y[70]; //Cambiar esto por un argumento que especifica la
cantidad de imagenes.
ifstream file("file.txt");
if (file.is_open())
{
for (int i = 0; i < 70; ++i) //Recordar cambiar por el argumento que
especifica cantidad de imagenes
{
file >> myArray_Z[i];
}
}
std::cout << "valor primer Z array: " << std::endl << std::endl;
std::cout << myArray_Z[0] << std::endl;
for (unsigned int f = 0; f < inputSize[2]; f++)
{
// Create a new dictionary for this slice
ReaderType::DictionaryRawPointer dict = new ReaderType::DictionaryType;
// Copy the dictionary from the first slice
CopyDictionary(*inputDict, *dict);
// Set the UID's for the study, series, SOP and frame of reference
itk::EncapsulateMetaData<std::string>(*dict, "0020|000d", studyUID);
//itk::EncapsulateMetaData<std::string>(*dict, "0020|000e", seriesUID);
itk::EncapsulateMetaData<std::string>(*dict, "0020|0052",
frameOfReferenceUID);
gdcm::UIDGenerator sopuid;
std::string sopInstanceUID = sopuid.Generate();
itk::EncapsulateMetaData<std::string>(*dict, "0008|0018",
sopInstanceUID);
itk::EncapsulateMetaData<std::string>(*dict, "0002|0003",
sopInstanceUID);
// Change fields that are slice specific
std::ostringstream value;
value.str("");
value << f + 1;
// Image Number
itk::EncapsulateMetaData<std::string>(*dict, "0020|0013", value.str());
// Series Description - Append new description to current series
// description
std::string oldSeriesDesc;
itk::ExposeMetaData<std::string>(*inputDict, "0008|103e", oldSeriesDesc);
value.str("");
value << oldSeriesDesc
<< ": Resampled with pixel spacing "
<< inputSpacing[0] << ", "
<< inputSpacing[1] << ", "
<< inputSpacing[2];
// This is an long string and there is a 64 character limit in the
// standard
unsigned lengthDesc = value.str().length();
std::string seriesDesc(value.str(), 0,
lengthDesc > 64 ? 64
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|103e", seriesDesc);
// Series Number
value.str("");
value << 1001;
itk::EncapsulateMetaData<std::string>(*dict, "0020|0011", value.str());
// Derivation Description - How this image was derived
value.str("");
for (int i = 0; i < argc; i++)
{
value << argv[i] << " ";
}
lengthDesc = value.str().length();
std::string derivationDesc(value.str(), 0,
lengthDesc > 1024 ? 1024
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|2111",
derivationDesc);
// Image Position Patient: This is calculated by computing the
// physical coordinate of the first pixel in each slice.
ImageType::PointType position;
ImageType::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = myArray_Z[f];
FiltroResample->GetOutput()->TransformIndexToPhysicalPoint(index, position);
//El origen que calculamos en el proyecto no se toca. (Origen = origen - average)
//Cambiamos el ImageOrientationPatient SOLAMENTE si el valor original en
la imagen es: 1\0\0\0\1\0. En el caso que se cambia el signo, se debe
cambiar el signo del origen
//value.str("");
//value << -1 << "\\" << 0 << "\\" << 0 << "\\" << 0 << "\\" << -1 <<
"\\" << 0; //PASAR ESTO POR ARGUMENTO!!!
//itk::EncapsulateMetaData<std::string>(*dict, "0020|0037", value.str());
value.str("");
value << -235.1629 << "\\" << -195.0557 << "\\" << myArray_Z[f]; //PASAR
ESTO POR ARGUMENTO!!! El origen - Centro
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032", value.str());
// Slice Location: For now, we store the z component of the Image
// Position Patient.
value.str("");
value << position[2];
itk::EncapsulateMetaData<std::string>(*dict, "0020|1041", value.str());
// Slice Thickness: For now, we store the z spacing
value.str("");
value << inputSpacing[2];
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
value.str());
// Spacing Between Slices
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
value.str());
// Save the dictionary
outputArray.push_back(dict);
}
typedef itk::ImageFileWriter< ImageType > WriterType;
WriterType::Pointer writer = WriterType::New();
typedef itk::ImageSeriesWriter< ImageType, ImageType_Serie >
SeriesWriterType;
SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();
seriesWriter->SetInput(FiltroResample->GetOutput());
writer->SetFileName(argv[2]);
writer->SetInput(FiltroResample->GetOutput());
itksys::SystemTools::MakeDirectory("Test"); //PASAR ESTO POR ARGUMENTO!!
typedef itk::NumericSeriesFileNames OutputNamesGeneratorType;
OutputNamesGeneratorType::Pointer outputNames =
OutputNamesGeneratorType::New();
std::string seriesFormat("Test"); //PASAR ESTO POR ARGUMENTO!!
seriesFormat = seriesFormat + "/" + "IM%d.dcm";
outputNames->SetSeriesFormat(seriesFormat.c_str());
outputNames->SetStartIndex(1);
outputNames->SetEndIndex(inputSize[2]);
seriesWriter->SetImageIO(gdcmIO);
seriesWriter->SetFileNames(outputNames->GetFileNames());
seriesWriter->SetMetaDataDictionaryArray(&outputArray);
std::cout << "Escribiendo la imagen como..." << std::endl << std::endl;
std::cout << argv[2] << std::endl << std::endl;
try
{
writer->Update();
seriesWriter->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
void CopyDictionary(itk::MetaDataDictionary &fromDict,
itk::MetaDataDictionary &toDict)
{
typedef itk::MetaDataDictionary DictionaryType;
DictionaryType::ConstIterator itr = fromDict.Begin();
DictionaryType::ConstIterator end = fromDict.End();
typedef itk::MetaDataObject< std::string > MetaDataStringType;
while (itr != end)
{
itk::MetaDataObjectBase::Pointer entry = itr->second;
MetaDataStringType::Pointer entryvalue =
dynamic_cast<MetaDataStringType *>(entry.GetPointer());
if (entryvalue)
{
std::string tagkey = itr->first;
std::string tagvalue = entryvalue->GetMetaDataObjectValue();
itk::EncapsulateMetaData<std::string>(toDict, tagkey, tagvalue);
}
++itr;
}
}
El jue., 30 de mar. de 2017 a la(s) 11:25, Lowekamp, Bradley
Hello,
Writing correct DICOM continues to be a struggle with SimpleITK and ITK.
It is generally recommended to directly use GDCM or DCMTK to write a proper
DICOM series.
SimpleITK tries to keep things, well, simple and straight forward. But
ITK ties to do some smart things, which get in the way for certain uses
with SimpleITK. We are trying to document and develop a nominal set of
DICOM output operations that work in SimpleITK.
Do you have working C++ code that works for your intended operation? Can
you share a small section of code which does what you expect it C++?
Thank,
Brad
On Mar 30, 2017, at 8:49 AM, Matias <[hidden email]
Hi,
I've been dealing with ITK for years in C++ and now I would need to use
SimpleITK and C# as far as I can in a new proyect.
Is the SimpleITK SeriesWriter working for Dicom Files? Last time I
tried to
use it I had problems with the DicomTags, these would not copy or there
was
no method to copy the tags to the resulting slices.
Currently, I read a volume of slices, apply rotation and then I need to
write the resulting image as another set of slices AND keeping tag
information such as patient name, etc.
Thank you,
Matias.
--
View this message in context: http://itk-users.7.n7.nabble.
com/SimpleITK-Serieswriter-and-DicomTags-tp38050.html
Sent from the ITK - Users mailing list archive at Nabble.com.
_____________________________________
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
_______________________________________________
Community mailing list
[hidden email] <http://user/SendEmail.jtp?type=node&node=38052&i=1>
http://public.kitware.com/mailman/listinfo/community
_____________________________________
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
------------------------------
*If you reply to this email, your message will be added to the discussion
below:*
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-
and-DicomTags-tp38050p38052.html
To unsubscribe from SimpleITK Serieswriter and DicomTags, click here.
NAML
<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
--
Matias
------------------------------
View this message in context: Re: [ITK-users] [ITK] SimpleITK
Serieswriter and DicomTags
<http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38056.html>
Sent from the ITK - Users mailing list archive
<http://itk-users.7.n7.nabble.com/> at Nabble.com.
_____________________________________
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-
and-DicomTags-tp38050p38063.html
To unsubscribe from SimpleITK Serieswriter and DicomTags, click here.
NAML
<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
--
Matias
------------------------------
View this message in context: Re: [ITK-users] [ITK] SimpleITK
Serieswriter and DicomTags
<http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38064.html>
Sent from the ITK - Users mailing list archive
<http://itk-users.7.n7.nabble.com/> at Nabble.com.
_____________________________________
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
Yaniv, Ziv Rafael (NIH/NLM/LHC) [C]
2017-04-02 13:58:47 UTC
Permalink
Hi Matias,

We should get it into the main SimpleITK repository shortly (after testing etc..). For now please follow DÅŸenan’s recommendation (clone my forked repository, checkout the dicomWrite branch and build SimpleITK from that branch).

regards
Ziv

From: DÅŸenan Zukić <***@gmail.com>
Date: Saturday, April 1, 2017 at 9:37 AM
To: Matias <***@gmail.com>
Cc: Insight-users <insight-***@itk.org>
Subject: Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags

Hi Matias,

you should use branch dicomWrite from Ziv's fork<https://github.com/zivy/SimpleITK/tree/dicomWrite>.

Regards,
DÅŸenan

On Sat, Apr 1, 2017 at 2:48 AM, Matias <***@gmail.com<mailto:***@gmail.com>> wrote:
Thanks Yaniv. So how do I get this branch? I simply download the latest version of SimpleITK?
El vie., 31 de mar. de 2017 a la(s) 19:18, Yaniv, Ziv Rafael (NIH/NLM/LHC) [C] [via ITK - Users] <[hidden email]<http://user/SendEmail.jtp?type=node&node=38064&i=0>> escribió:
Hello Matias,

Please take a look at the following github pull request (https://github.com/SimpleITK/SimpleITK/pull/134), this branch should provide the functionality you are looking for. See the Python example script included in the commit for the usage of the DICOM series writing.

hope this helps
Ziv


From: Matias <[hidden email]<http://user/SendEmail.jtp?type=node&node=38063&i=0>>

Date: Thursday, March 30, 2017 at 12:14 PM
To: "[hidden email]<http://user/SendEmail.jtp?type=node&node=38063&i=1>" <[hidden email]<http://user/SendEmail.jtp?type=node&node=38063&i=2>>

Subject: Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags

Yes, this is what I would need to migrate to C#:
It basically reads a dicom directory and performs rotation on the volume, then writes the resulting images back to a directory, copying the tags from the original images.

#include "itkImage.h"
#include "itkGDCMImageIO.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkImageSeriesReader.h"
#include "itkResampleImageFilter.h"
#include "itkEuler3DTransform.hxx"
#include "gdcmUIDGenerator.h"

#include "itkImageFileWriter.h"
#include "itkImageSeriesWriter.h"
#include "itkNumericSeriesFileNames.h"
#include "itkTranslationTransform.h"
#include "string.h";
#include <itkSliceIterator.h>

#include <iostream>
#include <string>
#include <fstream>



static void CopyDictionary(itk::MetaDataDictionary &fromDict,
itk::MetaDataDictionary &toDict);

int main(int argc, char* argv[])
{
if (argc < 8)
{
std::cerr << "Uso: " << std::endl;
std::cerr << argv[0] << " Directorio_A_Rotar DirectorioResultante Gamma Beta Alfa CentroRotacionX CentroRotacionY CentroRotacionZ"
<< std::endl;
return EXIT_FAILURE;
}

typedef signed short PixelType;
const unsigned int Dimension = 3;
const unsigned int Dimension_Serie = 2;
typedef itk::Image< PixelType, Dimension > ImageType;
typedef itk::Image<PixelType, Dimension_Serie> ImageType_Serie;

typedef itk::ImageSeriesReader< ImageType > ReaderType;
ReaderType::Pointer reader = ReaderType::New();

typedef itk::GDCMImageIO ImageIOType;
ImageIOType::Pointer gdcmIO = ImageIOType::New();
reader->SetImageIO(gdcmIO);

typedef itk::GDCMSeriesFileNames NamesGeneratorType;
NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
nameGenerator->SetUseSeriesDetails(true);
nameGenerator->AddSeriesRestriction("0008|0021");
nameGenerator->SetDirectory(argv[1]);

try
{
std::cout << std::endl << "The directory: " << std::endl;
std::cout << std::endl << argv[1] << std::endl << std::endl;
std::cout << "Contains the following DICOM Series: ";
std::cout << std::endl << std::endl;

typedef std::vector< std::string > SeriesIdContainer;
const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();
SeriesIdContainer::const_iterator seriesItr = seriesUID.begin();
SeriesIdContainer::const_iterator seriesEnd = seriesUID.end();
while (seriesItr != seriesEnd)
{
std::cout << seriesItr->c_str() << std::endl;
++seriesItr;
}

std::string seriesIdentifier;

seriesIdentifier = seriesUID.begin()->c_str();


std::cout << std::endl << std::endl;
std::cout << "Now reading series: " << std::endl << std::endl;
std::cout << seriesIdentifier << std::endl;
std::cout << std::endl << std::endl;

typedef std::vector< std::string > FileNamesContainer;
FileNamesContainer fileNames;
fileNames = nameGenerator->GetFileNames(seriesIdentifier);

reader->SetFileNames(fileNames);

try
{
reader->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}

const ImageType * inputImage = reader->GetOutput();
/*int numerodedicoms = inputImage->GetLargestPossibleRegion().GetSize()[2];
int dicomcentral = numerodedicoms / 2;
std::cout << "Dimenion " << dicomcentral << std::endl;*/
//itk::EncapsulateMetaData<std::string>(dictionary, "0020|0032","-208\\-236\\66");

typedef itk::ResampleImageFilter<ImageType, ImageType> FilterType;
FilterType::Pointer FiltroResample = FilterType::New();
FiltroResample->SetInput(reader->GetOutput());

typedef itk::LinearInterpolateImageFunction<ImageType, double > InterpolatorType;
InterpolatorType::Pointer interpolator = InterpolatorType::New();
FiltroResample->SetInterpolator(interpolator);
FiltroResample->SetOutputDirection(inputImage->GetDirection());
FiltroResample->SetOutputOrigin(inputImage->GetOrigin());

ImageType::SizeType inputSize = inputImage->GetLargestPossibleRegion().GetSize();
FiltroResample->SetSize(inputSize);

const ImageType::SpacingType& inputSpacing = inputImage->GetSpacing();
FiltroResample->SetOutputSpacing(inputSpacing);

FiltroResample->SetDefaultPixelValue(-1000); //Cambiar por un parametro

typedef itk::Euler3DTransform< double > TransformType; //Transform
TransformType::Pointer transform = TransformType::New();
double alfa, beta, gamma, centro_rotacion_X, centro_rotacion_Y, centro_rotacion_Z;
gamma = atof(argv[3]);
beta= atof(argv[4]);
alfa = atof(argv[5]);
centro_rotacion_X = atof(argv[6]);
centro_rotacion_Y = atof(argv[7]);
centro_rotacion_Z = atof(argv[8]);
transform->SetRotation(gamma, beta, alfa); //Radianes en el siguiente orden en ITK: Gamma, Beta, Alfa | Ibarra
//double centro[3] = { -14.8371, -54.9443, 175.75 }; //XmmPromedio, YmmPromedio, Z Central (mm): Leer directorio y tomar la del medio
double centro[3] = { centro_rotacion_X, centro_rotacion_Y, centro_rotacion_Z }; //XmmPromedio, YmmPromedio, Z Central (mm): Leer directorio y tomar la del medio
transform->SetCenter(centro);
std::cout << "Centro: " << std::endl << std::endl;
std::cout << transform->GetCenter() << std::endl;

FiltroResample->SetTransform(transform);
//FiltroResample->SetMetaDataDictionary(dictionary);
try
{
FiltroResample->Update();
}
catch (itk::ExceptionObject &ex)
{
return EXIT_FAILURE;
}



ReaderType::DictionaryRawPointer inputDict = (*(reader->GetMetaDataDictionaryArray()))[0];
ReaderType::DictionaryArrayType outputArray;
//std::cout << "array: " << std::endl << outputArray[0] << std::endl;
// To keep the new series in the same study as the original we need
// to keep the same study UID. But we need new series and frame of
// reference UID's.
gdcm::UIDGenerator suid;
//std::string seriesUID = suid.Generate();
gdcm::UIDGenerator fuid;
std::string frameOfReferenceUID = fuid.Generate();

std::string studyUID;
std::string sopClassUID;
itk::ExposeMetaData<std::string>(*inputDict, "0020|000d", studyUID);
itk::ExposeMetaData<std::string>(*inputDict, "0008|0016", sopClassUID);
gdcmIO->KeepOriginalUIDOn();

using namespace std;
double myArray_Z[70]; //Cambiar esto por un argumento que especifica la cantidad de imagenes.
double myArray_X[70]; //Cambiar esto por un argumento que especifica la cantidad de imagenes.
double myArray_Y[70]; //Cambiar esto por un argumento que especifica la cantidad de imagenes.

ifstream file("file.txt");
if (file.is_open())
{
for (int i = 0; i < 70; ++i) //Recordar cambiar por el argumento que especifica cantidad de imagenes
{
file >> myArray_Z[i];
}
}
std::cout << "valor primer Z array: " << std::endl << std::endl;
std::cout << myArray_Z[0] << std::endl;

for (unsigned int f = 0; f < inputSize[2]; f++)
{
// Create a new dictionary for this slice
ReaderType::DictionaryRawPointer dict = new ReaderType::DictionaryType;

// Copy the dictionary from the first slice
CopyDictionary(*inputDict, *dict);

// Set the UID's for the study, series, SOP and frame of reference
itk::EncapsulateMetaData<std::string>(*dict, "0020|000d", studyUID);
//itk::EncapsulateMetaData<std::string>(*dict, "0020|000e", seriesUID);
itk::EncapsulateMetaData<std::string>(*dict, "0020|0052", frameOfReferenceUID);

gdcm::UIDGenerator sopuid;
std::string sopInstanceUID = sopuid.Generate();

itk::EncapsulateMetaData<std::string>(*dict, "0008|0018", sopInstanceUID);
itk::EncapsulateMetaData<std::string>(*dict, "0002|0003", sopInstanceUID);

// Change fields that are slice specific
std::ostringstream value;
value.str("");
value << f + 1;

// Image Number
itk::EncapsulateMetaData<std::string>(*dict, "0020|0013", value.str());

// Series Description - Append new description to current series
// description
std::string oldSeriesDesc;
itk::ExposeMetaData<std::string>(*inputDict, "0008|103e", oldSeriesDesc);

value.str("");
value << oldSeriesDesc
<< ": Resampled with pixel spacing "
<< inputSpacing[0] << ", "
<< inputSpacing[1] << ", "
<< inputSpacing[2];
// This is an long string and there is a 64 character limit in the
// standard
unsigned lengthDesc = value.str().length();

std::string seriesDesc(value.str(), 0,
lengthDesc > 64 ? 64
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|103e", seriesDesc);

// Series Number
value.str("");
value << 1001;
itk::EncapsulateMetaData<std::string>(*dict, "0020|0011", value.str());

// Derivation Description - How this image was derived
value.str("");
for (int i = 0; i < argc; i++)
{
value << argv[i] << " ";
}

lengthDesc = value.str().length();
std::string derivationDesc(value.str(), 0,
lengthDesc > 1024 ? 1024
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|2111", derivationDesc);

// Image Position Patient: This is calculated by computing the
// physical coordinate of the first pixel in each slice.
ImageType::PointType position;
ImageType::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = myArray_Z[f];
FiltroResample->GetOutput()->TransformIndexToPhysicalPoint(index, position);

//El origen que calculamos en el proyecto no se toca. (Origen = origen - average)

//Cambiamos el ImageOrientationPatient SOLAMENTE si el valor original en la imagen es: 1\0\0\0\1\0. En el caso que se cambia el signo, se debe cambiar el signo del origen
//value.str("");
//value << -1 << "\\" << 0 << "\\" << 0 << "\\" << 0 << "\\" << -1 << "\\" << 0; //PASAR ESTO POR ARGUMENTO!!!
//itk::EncapsulateMetaData<std::string>(*dict, "0020|0037", value.str());

value.str("");
value << -235.1629 << "\\" << -195.0557 << "\\" << myArray_Z[f]; //PASAR ESTO POR ARGUMENTO!!! El origen - Centro
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032", value.str());


// Slice Location: For now, we store the z component of the Image
// Position Patient.
value.str("");
value << position[2];
itk::EncapsulateMetaData<std::string>(*dict, "0020|1041", value.str());

// Slice Thickness: For now, we store the z spacing
value.str("");
value << inputSpacing[2];
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
value.str());
// Spacing Between Slices
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
value.str());

// Save the dictionary
outputArray.push_back(dict);
}


typedef itk::ImageFileWriter< ImageType > WriterType;
WriterType::Pointer writer = WriterType::New();

typedef itk::ImageSeriesWriter< ImageType, ImageType_Serie > SeriesWriterType;
SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();
seriesWriter->SetInput(FiltroResample->GetOutput());

writer->SetFileName(argv[2]);
writer->SetInput(FiltroResample->GetOutput());

itksys::SystemTools::MakeDirectory("Test"); //PASAR ESTO POR ARGUMENTO!!
typedef itk::NumericSeriesFileNames OutputNamesGeneratorType;
OutputNamesGeneratorType::Pointer outputNames = OutputNamesGeneratorType::New();
std::string seriesFormat("Test"); //PASAR ESTO POR ARGUMENTO!!
seriesFormat = seriesFormat + "/" + "IM%d.dcm";
outputNames->SetSeriesFormat(seriesFormat.c_str());
outputNames->SetStartIndex(1);
outputNames->SetEndIndex(inputSize[2]);

seriesWriter->SetImageIO(gdcmIO);
seriesWriter->SetFileNames(outputNames->GetFileNames());
seriesWriter->SetMetaDataDictionaryArray(&outputArray);

std::cout << "Escribiendo la imagen como..." << std::endl << std::endl;
std::cout << argv[2] << std::endl << std::endl;

try
{
writer->Update();
seriesWriter->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}


}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}

return EXIT_SUCCESS;

}

void CopyDictionary(itk::MetaDataDictionary &fromDict, itk::MetaDataDictionary &toDict)
{
typedef itk::MetaDataDictionary DictionaryType;

DictionaryType::ConstIterator itr = fromDict.Begin();
DictionaryType::ConstIterator end = fromDict.End();
typedef itk::MetaDataObject< std::string > MetaDataStringType;

while (itr != end)
{
itk::MetaDataObjectBase::Pointer entry = itr->second;

MetaDataStringType::Pointer entryvalue =
dynamic_cast<MetaDataStringType *>(entry.GetPointer());
if (entryvalue)
{
std::string tagkey = itr->first;
std::string tagvalue = entryvalue->GetMetaDataObjectValue();
itk::EncapsulateMetaData<std::string>(toDict, tagkey, tagvalue);
}
++itr;
}
}


El jue., 30 de mar. de 2017 a la(s) 11:25, Lowekamp, Bradley (NIH/NLM/LHC) [C] [via ITK - Users] <[hidden email]> escribió:
Hello,

Writing correct DICOM continues to be a struggle with SimpleITK and ITK. It is generally recommended to directly use GDCM or DCMTK to write a proper DICOM series.

SimpleITK tries to keep things, well, simple and straight forward. But ITK ties to do some smart things, which get in the way for certain uses with SimpleITK. We are trying to document and develop a nominal set of DICOM output operations that work in SimpleITK.

Do you have working C++ code that works for your intended operation? Can you share a small section of code which does what you expect it C++?

Thank,
Brad
Post by Matias
Hi,
I've been dealing with ITK for years in C++ and now I would need to use
SimpleITK and C# as far as I can in a new proyect.
Is the SimpleITK SeriesWriter working for Dicom Files? Last time I tried to
use it I had problems with the DicomTags, these would not copy or there was
no method to copy the tags to the resulting slices.
Currently, I read a volume of slices, apply rotation and then I need to
write the resulting image as another set of slices AND keeping tag
information such as patient name, etc.
Thank you,
Matias.
--
View this message in context: http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050.html
Sent from the ITK - Users mailing list archive at Nabble.com.
_____________________________________
Powered by www.kitware.com<http://www.kitware.com>
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
_______________________________________________
Community mailing list
[hidden email]<http://user/SendEmail.jtp?type=node&node=38052&i=1>
http://public.kitware.com/mailman/listinfo/community
_____________________________________
Powered by www.kitware.com<http://www.kitware.com>

Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html

Kitware offers ITK Training Courses, for more information visit:
http://www.kitware.com/products/protraining.php

Please keep messages on-topic and check the ITK FAQ at:
http://www.itk.org/Wiki/ITK_FAQ

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/insight-users
________________________________
If you reply to this email, your message will be added to the discussion below:
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38052.html
To unsubscribe from SimpleITK Serieswriter and DicomTags, click here.
NAML<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
--
Matias

________________________________
View this message in context: Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags<http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38056.html>

Sent from the ITK - Users mailing list archive<http://itk-users.7.n7.nabble.com/> at Nabble.com.

_____________________________________
Powered by www.kitware.com<http://www.kitware.com>

Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html

Kitware offers ITK Training Courses, for more information visit:
http://www.kitware.com/products/protraining.php

Please keep messages on-topic and check the ITK FAQ at:
http://www.itk.org/Wiki/ITK_FAQ

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/insight-users

If you reply to this email, your message will be added to the discussion below:
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38063.html
To unsubscribe from SimpleITK Serieswriter and DicomTags, click here.
NAML<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
--
Matias

________________________________
View this message in context: Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags<http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38064.html>
Sent from the ITK - Users mailing list archive<http://itk-users.7.n7.nabble.com/> at Nabble.com.

_____________________________________
Powered by www.kitware.com<http://www.kitware.com>

Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html

Kitware offers ITK Training Courses, for more information visit:
http://www.kitware.com/products/protraining.php

Please keep messages on-topic and check the ITK FAQ at:
http://www.itk.org/Wiki/ITK_FAQ

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/insight-users
Lowekamp, Bradley (NIH/NLM/LHC) [C]
2017-04-05 12:57:15 UTC
Permalink
Hello Matias,

Ziv's patch was merged into SimpleITK’s master branch yesterday. The CDash builds[1] compiled the update and created binaries which are linked in the golden boxes. I believe you want CSharp for window 64[2].

Enjoy!
Brad

[1] https://open.cdash.org/index.php?project=SimpleITK
[2] https://open.cdash.org/viewFiles.php?buildid=4839224

On Apr 2, 2017, at 9:58 AM, Yaniv, Ziv Rafael (NIH/NLM/LHC) [C] <***@nih.gov<mailto:***@nih.gov>> wrote:

Hi Matias,

We should get it into the main SimpleITK repository shortly (after testing etc..). For now please follow DÅŸenan’s recommendation (clone my forked repository, checkout the dicomWrite branch and build SimpleITK from that branch).

regards
Ziv

From: DÅŸenan Zukić <***@gmail.com<mailto:***@gmail.com>>
Date: Saturday, April 1, 2017 at 9:37 AM
To: Matias <***@gmail.com<mailto:***@gmail.com>>
Cc: Insight-users <insight-***@itk.org<mailto:insight-***@itk.org>>
Subject: Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags

Hi Matias,

you should use branch dicomWrite from Ziv's fork<https://github.com/zivy/SimpleITK/tree/dicomWrite>.

Regards,
DÅŸenan

On Sat, Apr 1, 2017 at 2:48 AM, Matias <***@gmail.com<mailto:***@gmail.com>> wrote:
Thanks Yaniv. So how do I get this branch? I simply download the latest version of SimpleITK?
El vie., 31 de mar. de 2017 a la(s) 19:18, Yaniv, Ziv Rafael (NIH/NLM/LHC) [C] [via ITK - Users] <[hidden email]<http://user/SendEmail.jtp?type=node&node=38064&i=0>> escribió:
Hello Matias,

Please take a look at the following github pull request (https://github.com/SimpleITK/SimpleITK/pull/134), this branch should provide the functionality you are looking for. See the Python example script included in the commit for the usage of the DICOM series writing.

hope this helps
Ziv


From: Matias <[hidden email]<http://user/SendEmail.jtp?type=node&node=38063&i=0>>

Date: Thursday, March 30, 2017 at 12:14 PM
To: "[hidden email]<http://user/SendEmail.jtp?type=node&node=38063&i=1>" <[hidden email]<http://user/SendEmail.jtp?type=node&node=38063&i=2>>

Subject: Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags

Yes, this is what I would need to migrate to C#:
It basically reads a dicom directory and performs rotation on the volume, then writes the resulting images back to a directory, copying the tags from the original images.

#include "itkImage.h"
#include "itkGDCMImageIO.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkImageSeriesReader.h"
#include "itkResampleImageFilter.h"
#include "itkEuler3DTransform.hxx"
#include "gdcmUIDGenerator.h"

#include "itkImageFileWriter.h"
#include "itkImageSeriesWriter.h"
#include "itkNumericSeriesFileNames.h"
#include "itkTranslationTransform.h"
#include "string.h";
#include <itkSliceIterator.h>

#include <iostream>
#include <string>
#include <fstream>



static void CopyDictionary(itk::MetaDataDictionary &fromDict,
itk::MetaDataDictionary &toDict);

int main(int argc, char* argv[])
{
if (argc < 8)
{
std::cerr << "Uso: " << std::endl;
std::cerr << argv[0] << " Directorio_A_Rotar DirectorioResultante Gamma Beta Alfa CentroRotacionX CentroRotacionY CentroRotacionZ"
<< std::endl;
return EXIT_FAILURE;
}

typedef signed short PixelType;
const unsigned int Dimension = 3;
const unsigned int Dimension_Serie = 2;
typedef itk::Image< PixelType, Dimension > ImageType;
typedef itk::Image<PixelType, Dimension_Serie> ImageType_Serie;

typedef itk::ImageSeriesReader< ImageType > ReaderType;
ReaderType::Pointer reader = ReaderType::New();

typedef itk::GDCMImageIO ImageIOType;
ImageIOType::Pointer gdcmIO = ImageIOType::New();
reader->SetImageIO(gdcmIO);

typedef itk::GDCMSeriesFileNames NamesGeneratorType;
NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
nameGenerator->SetUseSeriesDetails(true);
nameGenerator->AddSeriesRestriction("0008|0021");
nameGenerator->SetDirectory(argv[1]);

try
{
std::cout << std::endl << "The directory: " << std::endl;
std::cout << std::endl << argv[1] << std::endl << std::endl;
std::cout << "Contains the following DICOM Series: ";
std::cout << std::endl << std::endl;

typedef std::vector< std::string > SeriesIdContainer;
const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();
SeriesIdContainer::const_iterator seriesItr = seriesUID.begin();
SeriesIdContainer::const_iterator seriesEnd = seriesUID.end();
while (seriesItr != seriesEnd)
{
std::cout << seriesItr->c_str() << std::endl;
++seriesItr;
}

std::string seriesIdentifier;

seriesIdentifier = seriesUID.begin()->c_str();


std::cout << std::endl << std::endl;
std::cout << "Now reading series: " << std::endl << std::endl;
std::cout << seriesIdentifier << std::endl;
std::cout << std::endl << std::endl;

typedef std::vector< std::string > FileNamesContainer;
FileNamesContainer fileNames;
fileNames = nameGenerator->GetFileNames(seriesIdentifier);

reader->SetFileNames(fileNames);

try
{
reader->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}

const ImageType * inputImage = reader->GetOutput();
/*int numerodedicoms = inputImage->GetLargestPossibleRegion().GetSize()[2];
int dicomcentral = numerodedicoms / 2;
std::cout << "Dimenion " << dicomcentral << std::endl;*/
//itk::EncapsulateMetaData<std::string>(dictionary, "0020|0032","-208\\-236\\66");

typedef itk::ResampleImageFilter<ImageType, ImageType> FilterType;
FilterType::Pointer FiltroResample = FilterType::New();
FiltroResample->SetInput(reader->GetOutput());

typedef itk::LinearInterpolateImageFunction<ImageType, double > InterpolatorType;
InterpolatorType::Pointer interpolator = InterpolatorType::New();
FiltroResample->SetInterpolator(interpolator);
FiltroResample->SetOutputDirection(inputImage->GetDirection());
FiltroResample->SetOutputOrigin(inputImage->GetOrigin());

ImageType::SizeType inputSize = inputImage->GetLargestPossibleRegion().GetSize();
FiltroResample->SetSize(inputSize);

const ImageType::SpacingType& inputSpacing = inputImage->GetSpacing();
FiltroResample->SetOutputSpacing(inputSpacing);

FiltroResample->SetDefaultPixelValue(-1000); //Cambiar por un parametro

typedef itk::Euler3DTransform< double > TransformType; //Transform
TransformType::Pointer transform = TransformType::New();
double alfa, beta, gamma, centro_rotacion_X, centro_rotacion_Y, centro_rotacion_Z;
gamma = atof(argv[3]);
beta= atof(argv[4]);
alfa = atof(argv[5]);
centro_rotacion_X = atof(argv[6]);
centro_rotacion_Y = atof(argv[7]);
centro_rotacion_Z = atof(argv[8]);
transform->SetRotation(gamma, beta, alfa); //Radianes en el siguiente orden en ITK: Gamma, Beta, Alfa | Ibarra
//double centro[3] = { -14.8371, -54.9443, 175.75 }; //XmmPromedio, YmmPromedio, Z Central (mm): Leer directorio y tomar la del medio
double centro[3] = { centro_rotacion_X, centro_rotacion_Y, centro_rotacion_Z }; //XmmPromedio, YmmPromedio, Z Central (mm): Leer directorio y tomar la del medio
transform->SetCenter(centro);
std::cout << "Centro: " << std::endl << std::endl;
std::cout << transform->GetCenter() << std::endl;

FiltroResample->SetTransform(transform);
//FiltroResample->SetMetaDataDictionary(dictionary);
try
{
FiltroResample->Update();
}
catch (itk::ExceptionObject &ex)
{
return EXIT_FAILURE;
}



ReaderType::DictionaryRawPointer inputDict = (*(reader->GetMetaDataDictionaryArray()))[0];
ReaderType::DictionaryArrayType outputArray;
//std::cout << "array: " << std::endl << outputArray[0] << std::endl;
// To keep the new series in the same study as the original we need
// to keep the same study UID. But we need new series and frame of
// reference UID's.
gdcm::UIDGenerator suid;
//std::string seriesUID = suid.Generate();
gdcm::UIDGenerator fuid;
std::string frameOfReferenceUID = fuid.Generate();

std::string studyUID;
std::string sopClassUID;
itk::ExposeMetaData<std::string>(*inputDict, "0020|000d", studyUID);
itk::ExposeMetaData<std::string>(*inputDict, "0008|0016", sopClassUID);
gdcmIO->KeepOriginalUIDOn();

using namespace std;
double myArray_Z[70]; //Cambiar esto por un argumento que especifica la cantidad de imagenes.
double myArray_X[70]; //Cambiar esto por un argumento que especifica la cantidad de imagenes.
double myArray_Y[70]; //Cambiar esto por un argumento que especifica la cantidad de imagenes.

ifstream file("file.txt");
if (file.is<http://file.is>_open())
{
for (int i = 0; i < 70; ++i) //Recordar cambiar por el argumento que especifica cantidad de imagenes
{
file >> myArray_Z[i];
}
}
std::cout << "valor primer Z array: " << std::endl << std::endl;
std::cout << myArray_Z[0] << std::endl;

for (unsigned int f = 0; f < inputSize[2]; f++)
{
// Create a new dictionary for this slice
ReaderType::DictionaryRawPointer dict = new ReaderType::DictionaryType;

// Copy the dictionary from the first slice
CopyDictionary(*inputDict, *dict);

// Set the UID's for the study, series, SOP and frame of reference
itk::EncapsulateMetaData<std::string>(*dict, "0020|000d", studyUID);
//itk::EncapsulateMetaData<std::string>(*dict, "0020|000e", seriesUID);
itk::EncapsulateMetaData<std::string>(*dict, "0020|0052", frameOfReferenceUID);

gdcm::UIDGenerator sopuid;
std::string sopInstanceUID = sopuid.Generate();

itk::EncapsulateMetaData<std::string>(*dict, "0008|0018", sopInstanceUID);
itk::EncapsulateMetaData<std::string>(*dict, "0002|0003", sopInstanceUID);

// Change fields that are slice specific
std::ostringstream value;
value.str("");
value << f + 1;

// Image Number
itk::EncapsulateMetaData<std::string>(*dict, "0020|0013", value.str());

// Series Description - Append new description to current series
// description
std::string oldSeriesDesc;
itk::ExposeMetaData<std::string>(*inputDict, "0008|103e", oldSeriesDesc);

value.str("");
value << oldSeriesDesc
<< ": Resampled with pixel spacing "
<< inputSpacing[0] << ", "
<< inputSpacing[1] << ", "
<< inputSpacing[2];
// This is an long string and there is a 64 character limit in the
// standard
unsigned lengthDesc = value.str().length();

std::string seriesDesc(value.str(), 0,
lengthDesc > 64 ? 64
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|103e", seriesDesc);

// Series Number
value.str("");
value << 1001;
itk::EncapsulateMetaData<std::string>(*dict, "0020|0011", value.str());

// Derivation Description - How this image was derived
value.str("");
for (int i = 0; i < argc; i++)
{
value << argv[i] << " ";
}

lengthDesc = value.str().length();
std::string derivationDesc(value.str(), 0,
lengthDesc > 1024 ? 1024
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|2111", derivationDesc);

// Image Position Patient: This is calculated by computing the
// physical coordinate of the first pixel in each slice.
ImageType::PointType position;
ImageType::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = myArray_Z[f];
FiltroResample->GetOutput()->TransformIndexToPhysicalPoint(index, position);

//El origen que calculamos en el proyecto no se toca. (Origen = origen - average)

//Cambiamos el ImageOrientationPatient SOLAMENTE si el valor original en la imagen es: 1\0\0\0\1\0. En el caso que se cambia el signo, se debe cambiar el signo del origen
//value.str("");
//value << -1 << "\\" << 0 << "\\" << 0 << "\\" << 0 << "\\" << -1 << "\\" << 0; //PASAR ESTO POR ARGUMENTO!!!
//itk::EncapsulateMetaData<std::string>(*dict, "0020|0037", value.str());

value.str("");
value << -235.1629 << "\\" << -195.0557 << "\\" << myArray_Z[f]; //PASAR ESTO POR ARGUMENTO!!! El origen - Centro
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032", value.str());


// Slice Location: For now, we store the z component of the Image
// Position Patient.
value.str("");
value << position[2];
itk::EncapsulateMetaData<std::string>(*dict, "0020|1041", value.str());

// Slice Thickness: For now, we store the z spacing
value.str("");
value << inputSpacing[2];
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
value.str());
// Spacing Between Slices
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
value.str());

// Save the dictionary
outputArray.push_back(dict);
}


typedef itk::ImageFileWriter< ImageType > WriterType;
WriterType::Pointer writer = WriterType::New();

typedef itk::ImageSeriesWriter< ImageType, ImageType_Serie > SeriesWriterType;
SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();
seriesWriter->SetInput(FiltroResample->GetOutput());

writer->SetFileName(argv[2]);
writer->SetInput(FiltroResample->GetOutput());

itksys::SystemTools::MakeDirectory("Test"); //PASAR ESTO POR ARGUMENTO!!
typedef itk::NumericSeriesFileNames OutputNamesGeneratorType;
OutputNamesGeneratorType::Pointer outputNames = OutputNamesGeneratorType::New();
std::string seriesFormat("Test"); //PASAR ESTO POR ARGUMENTO!!
seriesFormat = seriesFormat + "/" + "IM%d.dcm";
outputNames->SetSeriesFormat(seriesFormat.c_str());
outputNames->SetStartIndex(1);
outputNames->SetEndIndex(inputSize[2]);

seriesWriter->SetImageIO(gdcmIO);
seriesWriter->SetFileNames(outputNames->GetFileNames());
seriesWriter->SetMetaDataDictionaryArray(&outputArray);

std::cout << "Escribiendo la imagen como..." << std::endl << std::endl;
std::cout << argv[2] << std::endl << std::endl;

try
{
writer->Update();
seriesWriter->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}


}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}

return EXIT_SUCCESS;

}

void CopyDictionary(itk::MetaDataDictionary &fromDict, itk::MetaDataDictionary &toDict)
{
typedef itk::MetaDataDictionary DictionaryType;

DictionaryType::ConstIterator itr = fromDict.Begin();
DictionaryType::ConstIterator end = fromDict.End();
typedef itk::MetaDataObject< std::string > MetaDataStringType;

while (itr != end)
{
itk::MetaDataObjectBase::Pointer entry = itr->second;

MetaDataStringType::Pointer entryvalue =
dynamic_cast<MetaDataStringType *>(entry.GetPointer());
if (entryvalue)
{
std::string tagkey = itr->first;
std::string tagvalue = entryvalue->GetMetaDataObjectValue();
itk::EncapsulateMetaData<std::string>(toDict, tagkey, tagvalue);
}
++itr;
}
}


El jue., 30 de mar. de 2017 a la(s) 11:25, Lowekamp, Bradley (NIH/NLM/LHC) [C] [via ITK - Users] <[hidden email]> escribió:
Hello,

Writing correct DICOM continues to be a struggle with SimpleITK and ITK. It is generally recommended to directly use GDCM or DCMTK to write a proper DICOM series.

SimpleITK tries to keep things, well, simple and straight forward. But ITK ties to do some smart things, which get in the way for certain uses with SimpleITK. We are trying to document and develop a nominal set of DICOM output operations that work in SimpleITK.

Do you have working C++ code that works for your intended operation? Can you share a small section of code which does what you expect it C++?

Thank,
Brad
Post by Matias
Hi,
I've been dealing with ITK for years in C++ and now I would need to use
SimpleITK and C# as far as I can in a new proyect.
Is the SimpleITK SeriesWriter working for Dicom Files? Last time I tried to
use it I had problems with the DicomTags, these would not copy or there was
no method to copy the tags to the resulting slices.
Currently, I read a volume of slices, apply rotation and then I need to
write the resulting image as another set of slices AND keeping tag
information such as patient name, etc.
Thank you,
Matias.
--
View this message in context: http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050.html
Sent from the ITK - Users mailing list archive at Nabble.com<http://nabble.com>.
_____________________________________
Powered by www.kitware.com<http://www.kitware.com/>
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
_______________________________________________
Community mailing list
[hidden email]<http://user/SendEmail.jtp?type=node&node=38052&i=1>
http://public.kitware.com/mailman/listinfo/community
_____________________________________
Powered by www.kitware.com<http://www.kitware.com/>

Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html

Kitware offers ITK Training Courses, for more information visit:
http://www.kitware.com/products/protraining.php

Please keep messages on-topic and check the ITK FAQ at:
http://www.itk.org/Wiki/ITK_FAQ

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/insight-users
________________________________
If you reply to this email, your message will be added to the discussion below:
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38052.html
To unsubscribe from SimpleITK Serieswriter and DicomTags, click here.
NAML<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
--
Matias

________________________________
View this message in context: Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags<http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38056.html>

Sent from the ITK - Users mailing list archive<http://itk-users.7.n7.nabble.com/> at Nabble.com<http://nabble.com>.

_____________________________________
Powered by www.kitware.com<http://www.kitware.com/>

Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html

Kitware offers ITK Training Courses, for more information visit:
http://www.kitware.com/products/protraining.php

Please keep messages on-topic and check the ITK FAQ at:
http://www.itk.org/Wiki/ITK_FAQ

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/insight-users

If you reply to this email, your message will be added to the discussion below:
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38063.html
To unsubscribe from SimpleITK Serieswriter and DicomTags, click here.
NAML<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
--
Matias

________________________________
View this message in context: Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags<http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38064.html>
Sent from the ITK - Users mailing list archive<http://itk-users.7.n7.nabble.com/> at Nabble.com<http://nabble.com>.

_____________________________________
Powered by www.kitware.com<http://www.kitware.com/>

Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html

Kitware offers ITK Training Courses, for more information visit:
http://www.kitware.com/products/protraining.php

Please keep messages on-topic and check the ITK FAQ at:
http://www.itk.org/Wiki/ITK_FAQ

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/insight-users

_____________________________________
Powered by www.kitware.com<http://www.kitware.com>

Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html

Kitware offers ITK Training Courses, for more information visit:
http://www.kitware.com/products/protraining.php

Please keep messages on-topic and check the ITK FAQ at:
http://www.itk.org/Wiki/ITK_FAQ

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/insight-users
Matias
2017-04-05 13:22:09 UTC
Permalink
Awesome, thanks!

El mié., 5 de abr. de 2017 a la(s) 09:57, Lowekamp, Bradley (NIH/NLM/LHC)
Post by Yaniv, Ziv Rafael (NIH/NLM/LHC) [C]
Hello Matias,
Ziv's patch was merged into SimpleITK’s master branch yesterday. The CDash
builds[1] compiled the update and created binaries which are linked in the
golden boxes. I believe you want CSharp for window 64[2].
Enjoy!
Brad
[1] https://open.cdash.org/index.php?project=SimpleITK
[2] https://open.cdash.org/viewFiles.php?buildid=4839224
On Apr 2, 2017, at 9:58 AM, Yaniv, Ziv Rafael (NIH/NLM/LHC) [C] <[hidden
Hi Matias,
We should get it into the main SimpleITK repository shortly (after testing
etc..). For now please follow DÅŸenan’s recommendation (clone my forked
repository, checkout the dicomWrite branch and build SimpleITK from that
branch).
regards
Ziv
*From: *DÅŸenan Zukić <[hidden email]
<http:///user/SendEmail.jtp?type=node&node=38072&i=1>>
*Date: *Saturday, April 1, 2017 at 9:37 AM
*To: *Matias <[hidden email]
<http:///user/SendEmail.jtp?type=node&node=38072&i=2>>
*Cc: *Insight-users <[hidden email]
<http:///user/SendEmail.jtp?type=node&node=38072&i=3>>
*Subject: *Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags
Hi Matias,
you should use branch dicomWrite from Ziv's fork
<https://github.com/zivy/SimpleITK/tree/dicomWrite>.
Regards,
DÅŸenan
On Sat, Apr 1, 2017 at 2:48 AM, Matias <[hidden email]
Thanks Yaniv. So how do I get this branch? I simply download the latest
version of SimpleITK?
El vie., 31 de mar. de 2017 a la(s) 19:18, Yaniv, Ziv Rafael (NIH/NLM/LHC)
[C] [via ITK - Users] <[hidden email]
Hello Matias,
Please take a look at the following github pull request (
https://github.com/SimpleITK/SimpleITK/pull/134), this branch should
provide the functionality you are looking for. See the Python example
script included in the commit for the usage of the DICOM series writing.
hope this helps
Ziv
*From: *Matias <[hidden email]
<http://user/SendEmail.jtp?type=node&node=38063&i=0>>
*Date: *Thursday, March 30, 2017 at 12:14 PM
*To: *"[hidden email] <http://user/SendEmail.jtp?type=node&node=38063&i=1>"
<[hidden email] <http://user/SendEmail.jtp?type=node&node=38063&i=2>>
*Subject: *Re: [ITK-users] [ITK] SimpleITK Serieswriter and DicomTags
It basically reads a dicom directory and performs rotation on the volume,
then writes the resulting images back to a directory, copying the tags from
the original images.
#include "itkImage.h"
#include "itkGDCMImageIO.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkImageSeriesReader.h"
#include "itkResampleImageFilter.h"
#include "itkEuler3DTransform.hxx"
#include "gdcmUIDGenerator.h"
#include "itkImageFileWriter.h"
#include "itkImageSeriesWriter.h"
#include "itkNumericSeriesFileNames.h"
#include "itkTranslationTransform.h"
#include "string.h";
#include <itkSliceIterator.h>
#include <iostream>
#include <string>
#include <fstream>
static void CopyDictionary(itk::MetaDataDictionary &fromDict,
itk::MetaDataDictionary &toDict);
int main(int argc, char* argv[])
{
if (argc < 8)
{
std::cerr << "Uso: " << std::endl;
std::cerr << argv[0] << " Directorio_A_Rotar DirectorioResultante Gamma
Beta Alfa CentroRotacionX CentroRotacionY CentroRotacionZ"
<< std::endl;
return EXIT_FAILURE;
}
typedef signed short PixelType;
const unsigned int Dimension = 3;
const unsigned int Dimension_Serie = 2;
typedef itk::Image< PixelType, Dimension > ImageType;
typedef itk::Image<PixelType, Dimension_Serie> ImageType_Serie;
typedef itk::ImageSeriesReader< ImageType > ReaderType;
ReaderType::Pointer reader = ReaderType::New();
typedef itk::GDCMImageIO ImageIOType;
ImageIOType::Pointer gdcmIO = ImageIOType::New();
reader->SetImageIO(gdcmIO);
typedef itk::GDCMSeriesFileNames NamesGeneratorType;
NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
nameGenerator->SetUseSeriesDetails(true);
nameGenerator->AddSeriesRestriction("0008|0021");
nameGenerator->SetDirectory(argv[1]);
try
{
std::cout << std::endl << "The directory: " << std::endl;
std::cout << std::endl << argv[1] << std::endl << std::endl;
std::cout << "Contains the following DICOM Series: ";
std::cout << std::endl << std::endl;
typedef std::vector< std::string > SeriesIdContainer;
const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();
SeriesIdContainer::const_iterator seriesItr = seriesUID.begin();
SeriesIdContainer::const_iterator seriesEnd = seriesUID.end();
while (seriesItr != seriesEnd)
{
std::cout << seriesItr->c_str() << std::endl;
++seriesItr;
}
std::string seriesIdentifier;
seriesIdentifier = seriesUID.begin()->c_str();
std::cout << std::endl << std::endl;
std::cout << "Now reading series: " << std::endl << std::endl;
std::cout << seriesIdentifier << std::endl;
std::cout << std::endl << std::endl;
typedef std::vector< std::string > FileNamesContainer;
FileNamesContainer fileNames;
fileNames = nameGenerator->GetFileNames(seriesIdentifier);
reader->SetFileNames(fileNames);
try
{
reader->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}
const ImageType * inputImage = reader->GetOutput();
/*int numerodedicoms = inputImage->GetLargestPossibleRegion().GetSize()[2];
int dicomcentral = numerodedicoms / 2;
std::cout << "Dimenion " << dicomcentral << std::endl;*/
//itk::EncapsulateMetaData<std::string>(dictionary,
"0020|0032","-208\\-236\\66");
typedef itk::ResampleImageFilter<ImageType, ImageType> FilterType;
FilterType::Pointer FiltroResample = FilterType::New();
FiltroResample->SetInput(reader->GetOutput());
typedef itk::LinearInterpolateImageFunction<ImageType, double > InterpolatorType;
InterpolatorType::Pointer interpolator = InterpolatorType::New();
FiltroResample->SetInterpolator(interpolator);
FiltroResample->SetOutputDirection(inputImage->GetDirection());
FiltroResample->SetOutputOrigin(inputImage->GetOrigin());
ImageType::SizeType inputSize =
inputImage->GetLargestPossibleRegion().GetSize();
FiltroResample->SetSize(inputSize);
const ImageType::SpacingType& inputSpacing = inputImage->GetSpacing();
FiltroResample->SetOutputSpacing(inputSpacing);
FiltroResample->SetDefaultPixelValue(-1000); //Cambiar por un parametro
typedef itk::Euler3DTransform< double > TransformType; //Transform
TransformType::Pointer transform = TransformType::New();
double alfa, beta, gamma, centro_rotacion_X, centro_rotacion_Y, centro_rotacion_Z;
gamma = atof(argv[3]);
beta= atof(argv[4]);
alfa = atof(argv[5]);
centro_rotacion_X = atof(argv[6]);
centro_rotacion_Y = atof(argv[7]);
centro_rotacion_Z = atof(argv[8]);
transform->SetRotation(gamma, beta, alfa); //Radianes en el siguiente
orden en ITK: Gamma, Beta, Alfa | Ibarra
//double centro[3] = { -14.8371, -54.9443, 175.75 }; //XmmPromedio,
YmmPromedio, Z Central (mm): Leer directorio y tomar la del medio
double centro[3] = { centro_rotacion_X, centro_rotacion_Y,
centro_rotacion_Z }; //XmmPromedio, YmmPromedio, Z Central (mm): Leer
directorio y tomar la del medio
transform->SetCenter(centro);
std::cout << "Centro: " << std::endl << std::endl;
std::cout << transform->GetCenter() << std::endl;
FiltroResample->SetTransform(transform);
//FiltroResample->SetMetaDataDictionary(dictionary);
try
{
FiltroResample->Update();
}
catch (itk::ExceptionObject &ex)
{
return EXIT_FAILURE;
}
ReaderType::DictionaryRawPointer inputDict =
(*(reader->GetMetaDataDictionaryArray()))[0];
ReaderType::DictionaryArrayType outputArray;
//std::cout << "array: " << std::endl << outputArray[0] << std::endl;
// To keep the new series in the same study as the original we need
// to keep the same study UID. But we need new series and frame of
// reference UID's.
gdcm::UIDGenerator suid;
//std::string seriesUID = suid.Generate();
gdcm::UIDGenerator fuid;
std::string frameOfReferenceUID = fuid.Generate();
std::string studyUID;
std::string sopClassUID;
itk::ExposeMetaData<std::string>(*inputDict, "0020|000d", studyUID);
itk::ExposeMetaData<std::string>(*inputDict, "0008|0016", sopClassUID);
gdcmIO->KeepOriginalUIDOn();
using namespace std;
double myArray_Z[70]; //Cambiar esto por un argumento que especifica la
cantidad de imagenes.
double myArray_X[70]; //Cambiar esto por un argumento que especifica la
cantidad de imagenes.
double myArray_Y[70]; //Cambiar esto por un argumento que especifica la
cantidad de imagenes.
ifstream file("file.txt");
if (file.is_open())
{
for (int i = 0; i < 70; ++i) //Recordar cambiar por el argumento que
especifica cantidad de imagenes
{
file >> myArray_Z[i];
}
}
std::cout << "valor primer Z array: " << std::endl << std::endl;
std::cout << myArray_Z[0] << std::endl;
for (unsigned int f = 0; f < inputSize[2]; f++)
{
// Create a new dictionary for this slice
ReaderType::DictionaryRawPointer dict = new ReaderType::DictionaryType;
// Copy the dictionary from the first slice
CopyDictionary(*inputDict, *dict);
// Set the UID's for the study, series, SOP and frame of reference
itk::EncapsulateMetaData<std::string>(*dict, "0020|000d", studyUID);
//itk::EncapsulateMetaData<std::string>(*dict, "0020|000e", seriesUID);
itk::EncapsulateMetaData<std::string>(*dict, "0020|0052",
frameOfReferenceUID);
gdcm::UIDGenerator sopuid;
std::string sopInstanceUID = sopuid.Generate();
itk::EncapsulateMetaData<std::string>(*dict, "0008|0018", sopInstanceUID);
itk::EncapsulateMetaData<std::string>(*dict, "0002|0003", sopInstanceUID);
// Change fields that are slice specific
std::ostringstream value;
value.str("");
value << f + 1;
// Image Number
itk::EncapsulateMetaData<std::string>(*dict, "0020|0013", value.str());
// Series Description - Append new description to current series
// description
std::string oldSeriesDesc;
itk::ExposeMetaData<std::string>(*inputDict, "0008|103e", oldSeriesDesc);
value.str("");
value << oldSeriesDesc
<< ": Resampled with pixel spacing "
<< inputSpacing[0] << ", "
<< inputSpacing[1] << ", "
<< inputSpacing[2];
// This is an long string and there is a 64 character limit in the
// standard
unsigned lengthDesc = value.str().length();
std::string seriesDesc(value.str(), 0,
lengthDesc > 64 ? 64
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|103e", seriesDesc);
// Series Number
value.str("");
value << 1001;
itk::EncapsulateMetaData<std::string>(*dict, "0020|0011", value.str());
// Derivation Description - How this image was derived
value.str("");
for (int i = 0; i < argc; i++)
{
value << argv[i] << " ";
}
lengthDesc = value.str().length();
std::string derivationDesc(value.str(), 0,
lengthDesc > 1024 ? 1024
: lengthDesc);
itk::EncapsulateMetaData<std::string>(*dict, "0008|2111", derivationDesc);
// Image Position Patient: This is calculated by computing the
// physical coordinate of the first pixel in each slice.
ImageType::PointType position;
ImageType::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = myArray_Z[f];
FiltroResample->GetOutput()->TransformIndexToPhysicalPoint(index, position);
//El origen que calculamos en el proyecto no se toca. (Origen = origen - average)
//Cambiamos el ImageOrientationPatient SOLAMENTE si el valor original en
la imagen es: 1\0\0\0\1\0. En el caso que se cambia el signo, se debe
cambiar el signo del origen
//value.str("");
//value << -1 << "\\" << 0 << "\\" << 0 << "\\" << 0 << "\\" << -1 << "\\"
<< 0; //PASAR ESTO POR ARGUMENTO!!!
//itk::EncapsulateMetaData<std::string>(*dict, "0020|0037", value.str());
value.str("");
value << -235.1629 << "\\" << -195.0557 << "\\" << myArray_Z[f]; //PASAR
ESTO POR ARGUMENTO!!! El origen - Centro
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032", value.str());
// Slice Location: For now, we store the z component of the Image
// Position Patient.
value.str("");
value << position[2];
itk::EncapsulateMetaData<std::string>(*dict, "0020|1041", value.str());
// Slice Thickness: For now, we store the z spacing
value.str("");
value << inputSpacing[2];
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
value.str());
// Spacing Between Slices
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
value.str());
// Save the dictionary
outputArray.push_back(dict);
}
typedef itk::ImageFileWriter< ImageType > WriterType;
WriterType::Pointer writer = WriterType::New();
typedef itk::ImageSeriesWriter< ImageType, ImageType_Serie >
SeriesWriterType;
SeriesWriterType::Pointer seriesWriter = SeriesWriterType::New();
seriesWriter->SetInput(FiltroResample->GetOutput());
writer->SetFileName(argv[2]);
writer->SetInput(FiltroResample->GetOutput());
itksys::SystemTools::MakeDirectory("Test"); //PASAR ESTO POR ARGUMENTO!!
typedef itk::NumericSeriesFileNames OutputNamesGeneratorType;
OutputNamesGeneratorType::Pointer outputNames =
OutputNamesGeneratorType::New();
std::string seriesFormat("Test"); //PASAR ESTO POR ARGUMENTO!!
seriesFormat = seriesFormat + "/" + "IM%d.dcm";
outputNames->SetSeriesFormat(seriesFormat.c_str());
outputNames->SetStartIndex(1);
outputNames->SetEndIndex(inputSize[2]);
seriesWriter->SetImageIO(gdcmIO);
seriesWriter->SetFileNames(outputNames->GetFileNames());
seriesWriter->SetMetaDataDictionaryArray(&outputArray);
std::cout << "Escribiendo la imagen como..." << std::endl << std::endl;
std::cout << argv[2] << std::endl << std::endl;
try
{
writer->Update();
seriesWriter->Update();
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}
}
catch (itk::ExceptionObject &ex)
{
std::cout << ex << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
void CopyDictionary(itk::MetaDataDictionary &fromDict,
itk::MetaDataDictionary &toDict)
{
typedef itk::MetaDataDictionary DictionaryType;
DictionaryType::ConstIterator itr = fromDict.Begin();
DictionaryType::ConstIterator end = fromDict.End();
typedef itk::MetaDataObject< std::string > MetaDataStringType;
while (itr != end)
{
itk::MetaDataObjectBase::Pointer entry = itr->second;
MetaDataStringType::Pointer entryvalue =
dynamic_cast<MetaDataStringType *>(entry.GetPointer());
if (entryvalue)
{
std::string tagkey = itr->first;
std::string tagvalue = entryvalue->GetMetaDataObjectValue();
itk::EncapsulateMetaData<std::string>(toDict, tagkey, tagvalue);
}
++itr;
}
}
El jue., 30 de mar. de 2017 a la(s) 11:25, Lowekamp, Bradley (NIH/NLM/LHC)
Hello,
Writing correct DICOM continues to be a struggle with SimpleITK and ITK.
It is generally recommended to directly use GDCM or DCMTK to write a proper
DICOM series.
SimpleITK tries to keep things, well, simple and straight forward. But ITK
ties to do some smart things, which get in the way for certain uses with
SimpleITK. We are trying to document and develop a nominal set of DICOM
output operations that work in SimpleITK.
Do you have working C++ code that works for your intended operation? Can
you share a small section of code which does what you expect it C++?
Thank,
Brad
On Mar 30, 2017, at 8:49 AM, Matias <[hidden email]
Hi,
I've been dealing with ITK for years in C++ and now I would need to use
SimpleITK and C# as far as I can in a new proyect.
Is the SimpleITK SeriesWriter working for Dicom Files? Last time I tried
to
use it I had problems with the DicomTags, these would not copy or there
was
no method to copy the tags to the resulting slices.
Currently, I read a volume of slices, apply rotation and then I need to
write the resulting image as another set of slices AND keeping tag
information such as patient name, etc.
Thank you,
Matias.
--
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050.html
Sent from the ITK - Users mailing list archive at Nabble.com
<http://nabble.com>.
_____________________________________
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
_______________________________________________
Community mailing list
[hidden email] <http://user/SendEmail.jtp?type=node&node=38052&i=1>
http://public.kitware.com/mailman/listinfo/community
_____________________________________
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
------------------------------
*If you reply to this email, your message will be added to the discussion
below:*
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38052.html
To unsubscribe from SimpleITK Serieswriter and DicomTags, click here.
NAML
<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
--
Matias
------------------------------
View this message in context: Re: [ITK-users] [ITK] SimpleITK
Serieswriter and DicomTags
<http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38056.html>
Sent from the ITK - Users mailing list archive
<http://itk-users.7.n7.nabble.com/> at Nabble.com <http://nabble.com>.
_____________________________________
Powered by www.kitware.com
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
http://www.kitware.com/products/protraining.php
http://www.itk.org/Wiki/ITK_FAQ
http://public.kitware.com/mailman/listinfo/insight-users
*If you reply to this email, your message will be added to the discussion
below:*
http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38063.html
To unsubscribe from SimpleITK Serieswriter and DicomTags, click here.
NAML
<http://itk-users.7.n7.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
--
Matias
------------------------------
View this message in context: Re: [ITK-users] [ITK] SimpleITK
Serieswriter and DicomTags
<http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38064.html>
Sent from the ITK - Users mailing list archive
<http://itk-users.7.n7.nabble.com/> at
--
Matias




--
View this message in context: http://itk-users.7.n7.nabble.com/SimpleITK-Serieswriter-and-DicomTags-tp38050p38073.html
Sent from the ITK - Users mailing list archive at Nabble.com.

Loading...