[ITK-users] [ITK] SimpleITK Serieswriter and DicomTags

Lowekamp, Bradley (NIH/NLM/LHC) [C] blowekamp at mail.nih.gov
Wed Apr 5 08:57:15 EDT 2017


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] <zivrafael.yaniv at nih.gov<mailto:zivrafael.yaniv at 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ć <dzenanz at gmail.com<mailto:dzenanz at gmail.com>>
Date: Saturday, April 1, 2017 at 9:37 AM
To: Matias <matimontg at gmail.com<mailto:matimontg at gmail.com>>
Cc: Insight-users <insight-users at itk.org<mailto:insight-users at 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 <matimontg at gmail.com<mailto:matimontg at 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


> On Mar 30, 2017, at 8:49 AM, Matias <[hidden email]<http://user/SendEmail.jtp?type=node&node=38052&i=0>> wrote:
>
> 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
>
> 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
> _______________________________________________
> 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

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/insight-users/attachments/20170405/d962bf88/attachment-0001.html>


More information about the Insight-users mailing list