[ITK-users] [ITK] SimpleITK Serieswriter and DicomTags
Matias
matimontg at gmail.com
Sat Apr 1 02:48:08 EDT 2017
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] <ml-node+s7n38063h22 at n7.nabble.com> 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
>
>
>
> > 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.
> > _____________________________________
> > 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
> > _______________________________________________
> > 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
>
> 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
>
> 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
> <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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/insight-users/attachments/20170331/3e216a6d/attachment-0001.html>
More information about the Insight-users
mailing list