Discussion:
[ITK-users] Writing a DICOM file while preserving input image properties
Sarthak P
2017-03-08 20:11:59 UTC
Permalink
Hello All,

I am trying to write a DICOM image but I want to preserve the properties
from the input image (origin, direction, spacing, etc.). The ITK examples
do not show how to do this properly and anything I have done with the dicom
tags hasn't worked. Any help would be much appreciated.

Here is what I have so far:

//////////
const std::string dataDir = argv[1];
const std::string inputFile = dataDir + "/inputImage.nii.gz";
const std::string outputDir = dataDir + "/test/";

using ImageTypeToRead = itk::Image< float, 3 >;
using ImageTypeToWrite = itk::Image< short, 3 >;
auto inputImage = cbica::ReadImageWithOrientFix< itk::Image< float, 3 >
(inputFile);
auto imageToWrite = inputImage;

auto dicomIO = itk::GDCMImageIO::New();

auto seriesWriter = itk::ImageSeriesWriter< ImageTypeToWrite,
itk::Image<ImageTypeToWrite::PixelType, 2> >::New();

auto namesGenerator = itk::NumericSeriesFileNames::New();
auto start = imageToWrite->GetLargestPossibleRegion().GetIndex();
auto size = imageToWrite->GetLargestPossibleRegion().GetSize();
namesGenerator->SetSeriesFormat((outputDir + "/image%03d.dcm").c_str());
namesGenerator->SetStartIndex(start[2]);
namesGenerator->SetEndIndex(start[2] + size[2] - 1);
namesGenerator->SetIncrementIndex(1);

auto castFilter = itk::CastImageFilter<ImageTypeToRead,
ImageTypeToWrite>::New();
castFilter->SetInput(imageToWrite);
castFilter->Update();

seriesWriter->SetInput(castFilter->GetOutput());
seriesWriter->SetImageIO(dicomIO);
seriesWriter->SetFileNames(namesGenerator->GetFileNames());

typename itk::ImageSeriesReader< ImageTypeToRead >::DictionaryArrayType
outputArray;

// this doesn't work at all - was kind of hoping it would do the heavy
lifting for me
//dicomIO->SetOrigin(0, imageToWrite->GetOrigin()[0]);
//dicomIO->SetOrigin(1, imageToWrite->GetOrigin()[1]);
//dicomIO->SetOrigin(2, imageToWrite->GetOrigin()[2]);
//dicomIO->SetSpacing(0, imageToWrite->GetSpacing()[0]);
//dicomIO->SetSpacing(1, imageToWrite->GetSpacing()[1]);
//dicomIO->SetSpacing(2, imageToWrite->GetSpacing()[2]);
//dicomIO->SetDimensions(0,
imageToWrite->GetLargestPossibleRegion().GetSize()[0]);
//dicomIO->SetDimensions(1,
imageToWrite->GetLargestPossibleRegion().GetSize()[1]);
//dicomIO->SetDimensions(2,
imageToWrite->GetLargestPossibleRegion().GetSize()[2]);
// this doesn't work at all

for (size_t i = 0; i <
imageToWrite->GetLargestPossibleRegion().GetSize()[2]; i++)
{
auto dict = new itk::ImageSeriesReader< ImageTypeToRead
::DictionaryType;
typename ImageTypeToWrite::PointType position;
typename ImageTypeToWrite::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = i;
imageToWrite->TransformIndexToPhysicalPoint(index, position);
// tags extracted from dicom lookup http://dicomlookup.com/lookup.asp
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2])); // patient position
itk::EncapsulateMetaData<std::string>(*dict, "0018|5100",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "2020|0010",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|5101",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
std::to_string(imageToWrite->GetSpacing()[2])); // Slice Thickness
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
std::to_string(imageToWrite->GetSpacing()[2])); // Spacing Between Slices
itk::EncapsulateMetaData<std::string>(*dict, "0008|0008",
"DERIVED\\SECONDARY"); // Image Type
itk::EncapsulateMetaData<std::string>(*dict, "0008|0064", "DV"); //
Conversion Type

outputArray.push_back(dict);
}

seriesWriter->SetMetaDataDictionaryArray(&outputArray); // no dictionary
information present without seriesReader

try
{
seriesWriter->Write();
}
catch (itk::ExceptionObject &e)
{
std::cerr << "Error occurred while trying to write the image '" <<
outputDir << "': " << e.what() << "\n";
exit(EXIT_FAILURE);
}

//////////

Thanks a ton,
Sarthak
Matt McCormick
2017-03-09 14:20:49 UTC
Permalink
Hi Sarthak,

DICOM export requires improved typing to produce a valid set of tags.
This work has been started here:

https://github.com/KitwareMedical/ITKDICOM

but the implementation is in initial stages. I would be happy to
provide guidance if you would like to move it forward.

Thanks,
Matt
Post by Sarthak P
Hello All,
I am trying to write a DICOM image but I want to preserve the properties
from the input image (origin, direction, spacing, etc.). The ITK examples do
not show how to do this properly and anything I have done with the dicom
tags hasn't worked. Any help would be much appreciated.
//////////
const std::string dataDir = argv[1];
const std::string inputFile = dataDir + "/inputImage.nii.gz";
const std::string outputDir = dataDir + "/test/";
using ImageTypeToRead = itk::Image< float, 3 >;
using ImageTypeToWrite = itk::Image< short, 3 >;
auto inputImage = cbica::ReadImageWithOrientFix< itk::Image< float, 3 >
(inputFile);
auto imageToWrite = inputImage;
auto dicomIO = itk::GDCMImageIO::New();
auto seriesWriter = itk::ImageSeriesWriter< ImageTypeToWrite,
itk::Image<ImageTypeToWrite::PixelType, 2> >::New();
auto namesGenerator = itk::NumericSeriesFileNames::New();
auto start = imageToWrite->GetLargestPossibleRegion().GetIndex();
auto size = imageToWrite->GetLargestPossibleRegion().GetSize();
namesGenerator->SetSeriesFormat((outputDir + "/image%03d.dcm").c_str());
namesGenerator->SetStartIndex(start[2]);
namesGenerator->SetEndIndex(start[2] + size[2] - 1);
namesGenerator->SetIncrementIndex(1);
auto castFilter = itk::CastImageFilter<ImageTypeToRead,
ImageTypeToWrite>::New();
castFilter->SetInput(imageToWrite);
castFilter->Update();
seriesWriter->SetInput(castFilter->GetOutput());
seriesWriter->SetImageIO(dicomIO);
seriesWriter->SetFileNames(namesGenerator->GetFileNames());
typename itk::ImageSeriesReader< ImageTypeToRead >::DictionaryArrayType
outputArray;
// this doesn't work at all - was kind of hoping it would do the heavy
lifting for me
//dicomIO->SetOrigin(0, imageToWrite->GetOrigin()[0]);
//dicomIO->SetOrigin(1, imageToWrite->GetOrigin()[1]);
//dicomIO->SetOrigin(2, imageToWrite->GetOrigin()[2]);
//dicomIO->SetSpacing(0, imageToWrite->GetSpacing()[0]);
//dicomIO->SetSpacing(1, imageToWrite->GetSpacing()[1]);
//dicomIO->SetSpacing(2, imageToWrite->GetSpacing()[2]);
//dicomIO->SetDimensions(0,
imageToWrite->GetLargestPossibleRegion().GetSize()[0]);
//dicomIO->SetDimensions(1,
imageToWrite->GetLargestPossibleRegion().GetSize()[1]);
//dicomIO->SetDimensions(2,
imageToWrite->GetLargestPossibleRegion().GetSize()[2]);
// this doesn't work at all
for (size_t i = 0; i <
imageToWrite->GetLargestPossibleRegion().GetSize()[2]; i++)
{
auto dict = new itk::ImageSeriesReader< ImageTypeToRead
::DictionaryType;
typename ImageTypeToWrite::PointType position;
typename ImageTypeToWrite::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = i;
imageToWrite->TransformIndexToPhysicalPoint(index, position);
// tags extracted from dicom lookup http://dicomlookup.com/lookup.asp
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2])); // patient position
itk::EncapsulateMetaData<std::string>(*dict, "0018|5100",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "2020|0010",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|5101",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
std::to_string(imageToWrite->GetSpacing()[2])); // Slice Thickness
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
std::to_string(imageToWrite->GetSpacing()[2])); // Spacing Between Slices
itk::EncapsulateMetaData<std::string>(*dict, "0008|0008",
"DERIVED\\SECONDARY"); // Image Type
itk::EncapsulateMetaData<std::string>(*dict, "0008|0064", "DV"); //
Conversion Type
outputArray.push_back(dict);
}
seriesWriter->SetMetaDataDictionaryArray(&outputArray); // no dictionary
information present without seriesReader
try
{
seriesWriter->Write();
}
catch (itk::ExceptionObject &e)
{
std::cerr << "Error occurred while trying to write the image '" <<
outputDir << "': " << e.what() << "\n";
exit(EXIT_FAILURE);
}
//////////
Thanks a ton,
Sarthak
_____________________________________
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
_____________________________________
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
Sarthak P
2017-03-09 14:30:52 UTC
Permalink
Hi Matt,

Thanks for the response.

I don't think I am having issues with writing into the tags since I am able
to read the correct information I am writing (for instance, the tag
"0020|0032" is always populated with the physical coordinate of the
specific slice in a correct manner both during writing and reading). In an
example, the slice thickness should be "2" and the separation between the
dicom slices is "2", which is correct. But when ITK is reading this
collection, it keeps the slice thickness at "1". I am seeing the same
behavior in other applications as well (ITK-SNAP, etc.).

Could there be some tag I am missing to write? Since my last post, I tried
writing only to the tag "0020|0032"; the output dictionary array gets
populated properly but the file is still not written as expected. I am
using ITK 4.11, BTW.

Best,
Sarthak
Post by Matt McCormick
Hi Sarthak,
DICOM export requires improved typing to produce a valid set of tags.
https://github.com/KitwareMedical/ITKDICOM
but the implementation is in initial stages. I would be happy to
provide guidance if you would like to move it forward.
Thanks,
Matt
Post by Sarthak P
Hello All,
I am trying to write a DICOM image but I want to preserve the properties
from the input image (origin, direction, spacing, etc.). The ITK
examples do
Post by Sarthak P
not show how to do this properly and anything I have done with the dicom
tags hasn't worked. Any help would be much appreciated.
//////////
const std::string dataDir = argv[1];
const std::string inputFile = dataDir + "/inputImage.nii.gz";
const std::string outputDir = dataDir + "/test/";
using ImageTypeToRead = itk::Image< float, 3 >;
using ImageTypeToWrite = itk::Image< short, 3 >;
auto inputImage = cbica::ReadImageWithOrientFix< itk::Image< float, 3 >
(inputFile);
auto imageToWrite = inputImage;
auto dicomIO = itk::GDCMImageIO::New();
auto seriesWriter = itk::ImageSeriesWriter< ImageTypeToWrite,
itk::Image<ImageTypeToWrite::PixelType, 2> >::New();
auto namesGenerator = itk::NumericSeriesFileNames::New();
auto start = imageToWrite->GetLargestPossibleRegion().GetIndex();
auto size = imageToWrite->GetLargestPossibleRegion().GetSize();
namesGenerator->SetSeriesFormat((outputDir +
"/image%03d.dcm").c_str());
Post by Sarthak P
namesGenerator->SetStartIndex(start[2]);
namesGenerator->SetEndIndex(start[2] + size[2] - 1);
namesGenerator->SetIncrementIndex(1);
auto castFilter = itk::CastImageFilter<ImageTypeToRead,
ImageTypeToWrite>::New();
castFilter->SetInput(imageToWrite);
castFilter->Update();
seriesWriter->SetInput(castFilter->GetOutput());
seriesWriter->SetImageIO(dicomIO);
seriesWriter->SetFileNames(namesGenerator->GetFileNames());
typename itk::ImageSeriesReader< ImageTypeToRead >::DictionaryArrayType
outputArray;
// this doesn't work at all - was kind of hoping it would do the heavy
lifting for me
//dicomIO->SetOrigin(0, imageToWrite->GetOrigin()[0]);
//dicomIO->SetOrigin(1, imageToWrite->GetOrigin()[1]);
//dicomIO->SetOrigin(2, imageToWrite->GetOrigin()[2]);
//dicomIO->SetSpacing(0, imageToWrite->GetSpacing()[0]);
//dicomIO->SetSpacing(1, imageToWrite->GetSpacing()[1]);
//dicomIO->SetSpacing(2, imageToWrite->GetSpacing()[2]);
//dicomIO->SetDimensions(0,
imageToWrite->GetLargestPossibleRegion().GetSize()[0]);
//dicomIO->SetDimensions(1,
imageToWrite->GetLargestPossibleRegion().GetSize()[1]);
//dicomIO->SetDimensions(2,
imageToWrite->GetLargestPossibleRegion().GetSize()[2]);
// this doesn't work at all
for (size_t i = 0; i <
imageToWrite->GetLargestPossibleRegion().GetSize()[2]; i++)
{
auto dict = new itk::ImageSeriesReader< ImageTypeToRead
::DictionaryType;
typename ImageTypeToWrite::PointType position;
typename ImageTypeToWrite::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = i;
imageToWrite->TransformIndexToPhysicalPoint(index, position);
// tags extracted from dicom lookup http://dicomlookup.com/lookup.
asp
Post by Sarthak P
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2])); // patient position
itk::EncapsulateMetaData<std::string>(*dict, "0018|5100",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "2020|0010",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|5101",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
std::to_string(imageToWrite->GetSpacing()[2])); // Slice Thickness
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
std::to_string(imageToWrite->GetSpacing()[2])); // Spacing Between
Slices
Post by Sarthak P
itk::EncapsulateMetaData<std::string>(*dict, "0008|0008",
"DERIVED\\SECONDARY"); // Image Type
itk::EncapsulateMetaData<std::string>(*dict, "0008|0064", "DV"); //
Conversion Type
outputArray.push_back(dict);
}
seriesWriter->SetMetaDataDictionaryArray(&outputArray); // no
dictionary
Post by Sarthak P
information present without seriesReader
try
{
seriesWriter->Write();
}
catch (itk::ExceptionObject &e)
{
std::cerr << "Error occurred while trying to write the image '" <<
outputDir << "': " << e.what() << "\n";
exit(EXIT_FAILURE);
}
//////////
Thanks a ton,
Sarthak
_____________________________________
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
Matt McCormick
2017-03-09 14:47:03 UTC
Permalink
HI Sarthak,

The slice thickness is different from the spacing between slices. In
DICOM, slice thickness is related to the point spread function of the
imaging system and slice spacing is related to digital sampling.

Hope this helps,
Matt
Post by Sarthak P
Hi Matt,
Thanks for the response.
I don't think I am having issues with writing into the tags since I am able
to read the correct information I am writing (for instance, the tag
"0020|0032" is always populated with the physical coordinate of the specific
slice in a correct manner both during writing and reading). In an example,
the slice thickness should be "2" and the separation between the dicom
slices is "2", which is correct. But when ITK is reading this collection, it
keeps the slice thickness at "1". I am seeing the same behavior in other
applications as well (ITK-SNAP, etc.).
Could there be some tag I am missing to write? Since my last post, I tried
writing only to the tag "0020|0032"; the output dictionary array gets
populated properly but the file is still not written as expected. I am using
ITK 4.11, BTW.
Best,
Sarthak
Post by Matt McCormick
Hi Sarthak,
DICOM export requires improved typing to produce a valid set of tags.
https://github.com/KitwareMedical/ITKDICOM
but the implementation is in initial stages. I would be happy to
provide guidance if you would like to move it forward.
Thanks,
Matt
Post by Sarthak P
Hello All,
I am trying to write a DICOM image but I want to preserve the properties
from the input image (origin, direction, spacing, etc.). The ITK examples do
not show how to do this properly and anything I have done with the dicom
tags hasn't worked. Any help would be much appreciated.
//////////
const std::string dataDir = argv[1];
const std::string inputFile = dataDir + "/inputImage.nii.gz";
const std::string outputDir = dataDir + "/test/";
using ImageTypeToRead = itk::Image< float, 3 >;
using ImageTypeToWrite = itk::Image< short, 3 >;
auto inputImage = cbica::ReadImageWithOrientFix< itk::Image< float, 3
(inputFile);
auto imageToWrite = inputImage;
auto dicomIO = itk::GDCMImageIO::New();
auto seriesWriter = itk::ImageSeriesWriter< ImageTypeToWrite,
itk::Image<ImageTypeToWrite::PixelType, 2> >::New();
auto namesGenerator = itk::NumericSeriesFileNames::New();
auto start = imageToWrite->GetLargestPossibleRegion().GetIndex();
auto size = imageToWrite->GetLargestPossibleRegion().GetSize();
namesGenerator->SetSeriesFormat((outputDir +
"/image%03d.dcm").c_str());
namesGenerator->SetStartIndex(start[2]);
namesGenerator->SetEndIndex(start[2] + size[2] - 1);
namesGenerator->SetIncrementIndex(1);
auto castFilter = itk::CastImageFilter<ImageTypeToRead,
ImageTypeToWrite>::New();
castFilter->SetInput(imageToWrite);
castFilter->Update();
seriesWriter->SetInput(castFilter->GetOutput());
seriesWriter->SetImageIO(dicomIO);
seriesWriter->SetFileNames(namesGenerator->GetFileNames());
typename itk::ImageSeriesReader< ImageTypeToRead
::DictionaryArrayType
outputArray;
// this doesn't work at all - was kind of hoping it would do the heavy
lifting for me
//dicomIO->SetOrigin(0, imageToWrite->GetOrigin()[0]);
//dicomIO->SetOrigin(1, imageToWrite->GetOrigin()[1]);
//dicomIO->SetOrigin(2, imageToWrite->GetOrigin()[2]);
//dicomIO->SetSpacing(0, imageToWrite->GetSpacing()[0]);
//dicomIO->SetSpacing(1, imageToWrite->GetSpacing()[1]);
//dicomIO->SetSpacing(2, imageToWrite->GetSpacing()[2]);
//dicomIO->SetDimensions(0,
imageToWrite->GetLargestPossibleRegion().GetSize()[0]);
//dicomIO->SetDimensions(1,
imageToWrite->GetLargestPossibleRegion().GetSize()[1]);
//dicomIO->SetDimensions(2,
imageToWrite->GetLargestPossibleRegion().GetSize()[2]);
// this doesn't work at all
for (size_t i = 0; i <
imageToWrite->GetLargestPossibleRegion().GetSize()[2]; i++)
{
auto dict = new itk::ImageSeriesReader< ImageTypeToRead
::DictionaryType;
typename ImageTypeToWrite::PointType position;
typename ImageTypeToWrite::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = i;
imageToWrite->TransformIndexToPhysicalPoint(index, position);
// tags extracted from dicom lookup
http://dicomlookup.com/lookup.asp
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2])); // patient position
itk::EncapsulateMetaData<std::string>(*dict, "0018|5100",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "2020|0010",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|5101",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) + "\\" +
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
std::to_string(imageToWrite->GetSpacing()[2])); // Slice Thickness
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
std::to_string(imageToWrite->GetSpacing()[2])); // Spacing Between Slices
itk::EncapsulateMetaData<std::string>(*dict, "0008|0008",
"DERIVED\\SECONDARY"); // Image Type
itk::EncapsulateMetaData<std::string>(*dict, "0008|0064", "DV"); //
Conversion Type
outputArray.push_back(dict);
}
seriesWriter->SetMetaDataDictionaryArray(&outputArray); // no dictionary
information present without seriesReader
try
{
seriesWriter->Write();
}
catch (itk::ExceptionObject &e)
{
std::cerr << "Error occurred while trying to write the image '" <<
outputDir << "': " << e.what() << "\n";
exit(EXIT_FAILURE);
}
//////////
Thanks a ton,
Sarthak
_____________________________________
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
_____________________________________
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
Sarthak P
2017-03-09 15:25:09 UTC
Permalink
Hi Matt,

Yes I do know that. I have tried to put the spacing information from the
itk::Image using various combinations with the tags 0018|0088 (slice
thickness) and 0018|0050 (spacing between slices) but to no avail.

Thanks for your help,
Sarthak
Post by Matt McCormick
HI Sarthak,
The slice thickness is different from the spacing between slices. In
DICOM, slice thickness is related to the point spread function of the
imaging system and slice spacing is related to digital sampling.
Hope this helps,
Matt
Post by Sarthak P
Hi Matt,
Thanks for the response.
I don't think I am having issues with writing into the tags since I am
able
Post by Sarthak P
to read the correct information I am writing (for instance, the tag
"0020|0032" is always populated with the physical coordinate of the
specific
Post by Sarthak P
slice in a correct manner both during writing and reading). In an
example,
Post by Sarthak P
the slice thickness should be "2" and the separation between the dicom
slices is "2", which is correct. But when ITK is reading this
collection, it
Post by Sarthak P
keeps the slice thickness at "1". I am seeing the same behavior in other
applications as well (ITK-SNAP, etc.).
Could there be some tag I am missing to write? Since my last post, I
tried
Post by Sarthak P
writing only to the tag "0020|0032"; the output dictionary array gets
populated properly but the file is still not written as expected. I am
using
Post by Sarthak P
ITK 4.11, BTW.
Best,
Sarthak
On Thu, Mar 9, 2017 at 9:20 AM, Matt McCormick <
Post by Matt McCormick
Hi Sarthak,
DICOM export requires improved typing to produce a valid set of tags.
https://github.com/KitwareMedical/ITKDICOM
but the implementation is in initial stages. I would be happy to
provide guidance if you would like to move it forward.
Thanks,
Matt
Post by Sarthak P
Hello All,
I am trying to write a DICOM image but I want to preserve the
properties
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
from the input image (origin, direction, spacing, etc.). The ITK examples do
not show how to do this properly and anything I have done with the
dicom
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
tags hasn't worked. Any help would be much appreciated.
//////////
const std::string dataDir = argv[1];
const std::string inputFile = dataDir + "/inputImage.nii.gz";
const std::string outputDir = dataDir + "/test/";
using ImageTypeToRead = itk::Image< float, 3 >;
using ImageTypeToWrite = itk::Image< short, 3 >;
auto inputImage = cbica::ReadImageWithOrientFix< itk::Image< float,
3
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
(inputFile);
auto imageToWrite = inputImage;
auto dicomIO = itk::GDCMImageIO::New();
auto seriesWriter = itk::ImageSeriesWriter< ImageTypeToWrite,
itk::Image<ImageTypeToWrite::PixelType, 2> >::New();
auto namesGenerator = itk::NumericSeriesFileNames::New();
auto start = imageToWrite->GetLargestPossibleRegion().GetIndex();
auto size = imageToWrite->GetLargestPossibleRegion().GetSize();
namesGenerator->SetSeriesFormat((outputDir +
"/image%03d.dcm").c_str());
namesGenerator->SetStartIndex(start[2]);
namesGenerator->SetEndIndex(start[2] + size[2] - 1);
namesGenerator->SetIncrementIndex(1);
auto castFilter = itk::CastImageFilter<ImageTypeToRead,
ImageTypeToWrite>::New();
castFilter->SetInput(imageToWrite);
castFilter->Update();
seriesWriter->SetInput(castFilter->GetOutput());
seriesWriter->SetImageIO(dicomIO);
seriesWriter->SetFileNames(namesGenerator->GetFileNames());
typename itk::ImageSeriesReader< ImageTypeToRead
::DictionaryArrayType
outputArray;
// this doesn't work at all - was kind of hoping it would do the
heavy
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
lifting for me
//dicomIO->SetOrigin(0, imageToWrite->GetOrigin()[0]);
//dicomIO->SetOrigin(1, imageToWrite->GetOrigin()[1]);
//dicomIO->SetOrigin(2, imageToWrite->GetOrigin()[2]);
//dicomIO->SetSpacing(0, imageToWrite->GetSpacing()[0]);
//dicomIO->SetSpacing(1, imageToWrite->GetSpacing()[1]);
//dicomIO->SetSpacing(2, imageToWrite->GetSpacing()[2]);
//dicomIO->SetDimensions(0,
imageToWrite->GetLargestPossibleRegion().GetSize()[0]);
//dicomIO->SetDimensions(1,
imageToWrite->GetLargestPossibleRegion().GetSize()[1]);
//dicomIO->SetDimensions(2,
imageToWrite->GetLargestPossibleRegion().GetSize()[2]);
// this doesn't work at all
for (size_t i = 0; i <
imageToWrite->GetLargestPossibleRegion().GetSize()[2]; i++)
{
auto dict = new itk::ImageSeriesReader< ImageTypeToRead
::DictionaryType;
typename ImageTypeToWrite::PointType position;
typename ImageTypeToWrite::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = i;
imageToWrite->TransformIndexToPhysicalPoint(index, position);
// tags extracted from dicom lookup
http://dicomlookup.com/lookup.asp
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) +
"\\"
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
+
std::to_string(position[2])); // patient position
itk::EncapsulateMetaData<std::string>(*dict, "0018|5100",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) +
"\\"
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
+
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "2020|0010",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) +
"\\"
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
+
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|5101",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) +
"\\"
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
+
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
std::to_string(imageToWrite->GetSpacing()[2])); // Slice Thickness
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
std::to_string(imageToWrite->GetSpacing()[2])); // Spacing Between Slices
itk::EncapsulateMetaData<std::string>(*dict, "0008|0008",
"DERIVED\\SECONDARY"); // Image Type
itk::EncapsulateMetaData<std::string>(*dict, "0008|0064", "DV");
//
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
Conversion Type
outputArray.push_back(dict);
}
seriesWriter->SetMetaDataDictionaryArray(&outputArray); // no dictionary
information present without seriesReader
try
{
seriesWriter->Write();
}
catch (itk::ExceptionObject &e)
{
std::cerr << "Error occurred while trying to write the image '" <<
outputDir << "': " << e.what() << "\n";
exit(EXIT_FAILURE);
}
//////////
Thanks a ton,
Sarthak
_____________________________________
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
Sarthak P
2017-03-09 15:26:47 UTC
Permalink
So the thing is that even the origin isn't picked up when reading the DICOM
image (it is always 0,0,0) so I am guessing I am doing something wrong when
writing into the tag 0020|0032 itself. Once that is rectified, the spacing
information (should) correct itself.

Best,
Sarthak
Post by Sarthak P
Hi Matt,
Yes I do know that. I have tried to put the spacing information from the
itk::Image using various combinations with the tags 0018|0088 (slice
thickness) and 0018|0050 (spacing between slices) but to no avail.
Thanks for your help,
Sarthak
Post by Matt McCormick
HI Sarthak,
The slice thickness is different from the spacing between slices. In
DICOM, slice thickness is related to the point spread function of the
imaging system and slice spacing is related to digital sampling.
Hope this helps,
Matt
Post by Sarthak P
Hi Matt,
Thanks for the response.
I don't think I am having issues with writing into the tags since I am
able
Post by Sarthak P
to read the correct information I am writing (for instance, the tag
"0020|0032" is always populated with the physical coordinate of the
specific
Post by Sarthak P
slice in a correct manner both during writing and reading). In an
example,
Post by Sarthak P
the slice thickness should be "2" and the separation between the dicom
slices is "2", which is correct. But when ITK is reading this
collection, it
Post by Sarthak P
keeps the slice thickness at "1". I am seeing the same behavior in other
applications as well (ITK-SNAP, etc.).
Could there be some tag I am missing to write? Since my last post, I
tried
Post by Sarthak P
writing only to the tag "0020|0032"; the output dictionary array gets
populated properly but the file is still not written as expected. I am
using
Post by Sarthak P
ITK 4.11, BTW.
Best,
Sarthak
On Thu, Mar 9, 2017 at 9:20 AM, Matt McCormick <
Post by Matt McCormick
Hi Sarthak,
DICOM export requires improved typing to produce a valid set of tags.
https://github.com/KitwareMedical/ITKDICOM
but the implementation is in initial stages. I would be happy to
provide guidance if you would like to move it forward.
Thanks,
Matt
Post by Sarthak P
Hello All,
I am trying to write a DICOM image but I want to preserve the
properties
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
from the input image (origin, direction, spacing, etc.). The ITK examples do
not show how to do this properly and anything I have done with the
dicom
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
tags hasn't worked. Any help would be much appreciated.
//////////
const std::string dataDir = argv[1];
const std::string inputFile = dataDir + "/inputImage.nii.gz";
const std::string outputDir = dataDir + "/test/";
using ImageTypeToRead = itk::Image< float, 3 >;
using ImageTypeToWrite = itk::Image< short, 3 >;
auto inputImage = cbica::ReadImageWithOrientFix< itk::Image<
float, 3
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
(inputFile);
auto imageToWrite = inputImage;
auto dicomIO = itk::GDCMImageIO::New();
auto seriesWriter = itk::ImageSeriesWriter< ImageTypeToWrite,
itk::Image<ImageTypeToWrite::PixelType, 2> >::New();
auto namesGenerator = itk::NumericSeriesFileNames::New();
auto start = imageToWrite->GetLargestPossibleRegion().GetIndex();
auto size = imageToWrite->GetLargestPossibleRegion().GetSize();
namesGenerator->SetSeriesFormat((outputDir +
"/image%03d.dcm").c_str());
namesGenerator->SetStartIndex(start[2]);
namesGenerator->SetEndIndex(start[2] + size[2] - 1);
namesGenerator->SetIncrementIndex(1);
auto castFilter = itk::CastImageFilter<ImageTypeToRead,
ImageTypeToWrite>::New();
castFilter->SetInput(imageToWrite);
castFilter->Update();
seriesWriter->SetInput(castFilter->GetOutput());
seriesWriter->SetImageIO(dicomIO);
seriesWriter->SetFileNames(namesGenerator->GetFileNames());
typename itk::ImageSeriesReader< ImageTypeToRead
::DictionaryArrayType
outputArray;
// this doesn't work at all - was kind of hoping it would do the
heavy
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
lifting for me
//dicomIO->SetOrigin(0, imageToWrite->GetOrigin()[0]);
//dicomIO->SetOrigin(1, imageToWrite->GetOrigin()[1]);
//dicomIO->SetOrigin(2, imageToWrite->GetOrigin()[2]);
//dicomIO->SetSpacing(0, imageToWrite->GetSpacing()[0]);
//dicomIO->SetSpacing(1, imageToWrite->GetSpacing()[1]);
//dicomIO->SetSpacing(2, imageToWrite->GetSpacing()[2]);
//dicomIO->SetDimensions(0,
imageToWrite->GetLargestPossibleRegion().GetSize()[0]);
//dicomIO->SetDimensions(1,
imageToWrite->GetLargestPossibleRegion().GetSize()[1]);
//dicomIO->SetDimensions(2,
imageToWrite->GetLargestPossibleRegion().GetSize()[2]);
// this doesn't work at all
for (size_t i = 0; i <
imageToWrite->GetLargestPossibleRegion().GetSize()[2]; i++)
{
auto dict = new itk::ImageSeriesReader< ImageTypeToRead
::DictionaryType;
typename ImageTypeToWrite::PointType position;
typename ImageTypeToWrite::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = i;
imageToWrite->TransformIndexToPhysicalPoint(index, position);
// tags extracted from dicom lookup
http://dicomlookup.com/lookup.asp
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) +
"\\"
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
+
std::to_string(position[2])); // patient position
itk::EncapsulateMetaData<std::string>(*dict, "0018|5100",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) +
"\\"
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
+
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "2020|0010",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) +
"\\"
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
+
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|5101",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) +
"\\"
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
+
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
std::to_string(imageToWrite->GetSpacing()[2])); // Slice Thickness
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
std::to_string(imageToWrite->GetSpacing()[2])); // Spacing Between Slices
itk::EncapsulateMetaData<std::string>(*dict, "0008|0008",
"DERIVED\\SECONDARY"); // Image Type
itk::EncapsulateMetaData<std::string>(*dict, "0008|0064",
"DV"); //
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
Conversion Type
outputArray.push_back(dict);
}
seriesWriter->SetMetaDataDictionaryArray(&outputArray); // no dictionary
information present without seriesReader
try
{
seriesWriter->Write();
}
catch (itk::ExceptionObject &e)
{
std::cerr << "Error occurred while trying to write the image '"
<<
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
outputDir << "': " << e.what() << "\n";
exit(EXIT_FAILURE);
}
//////////
Thanks a ton,
Sarthak
_____________________________________
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
Sarthak P
2017-03-09 15:54:06 UTC
Permalink
Found recorded bugs related to this:

https://issues.itk.org/jira/browse/ITK-3176 (spacing)
https://issues.itk.org/jira/browse/ITK-3407 (origin)

Guess we wait and watch.

Thanks a ton for your help,
Sarthak
Post by Sarthak P
So the thing is that even the origin isn't picked up when reading the
DICOM image (it is always 0,0,0) so I am guessing I am doing something
wrong when writing into the tag 0020|0032 itself. Once that is rectified,
the spacing information (should) correct itself.
Best,
Sarthak
Post by Sarthak P
Hi Matt,
Yes I do know that. I have tried to put the spacing information from the
itk::Image using various combinations with the tags 0018|0088 (slice
thickness) and 0018|0050 (spacing between slices) but to no avail.
Thanks for your help,
Sarthak
On Thu, Mar 9, 2017 at 9:47 AM, Matt McCormick <
Post by Matt McCormick
HI Sarthak,
The slice thickness is different from the spacing between slices. In
DICOM, slice thickness is related to the point spread function of the
imaging system and slice spacing is related to digital sampling.
Hope this helps,
Matt
Post by Sarthak P
Hi Matt,
Thanks for the response.
I don't think I am having issues with writing into the tags since I am
able
Post by Sarthak P
to read the correct information I am writing (for instance, the tag
"0020|0032" is always populated with the physical coordinate of the
specific
Post by Sarthak P
slice in a correct manner both during writing and reading). In an
example,
Post by Sarthak P
the slice thickness should be "2" and the separation between the dicom
slices is "2", which is correct. But when ITK is reading this
collection, it
Post by Sarthak P
keeps the slice thickness at "1". I am seeing the same behavior in
other
Post by Sarthak P
applications as well (ITK-SNAP, etc.).
Could there be some tag I am missing to write? Since my last post, I
tried
Post by Sarthak P
writing only to the tag "0020|0032"; the output dictionary array gets
populated properly but the file is still not written as expected. I am
using
Post by Sarthak P
ITK 4.11, BTW.
Best,
Sarthak
On Thu, Mar 9, 2017 at 9:20 AM, Matt McCormick <
Post by Matt McCormick
Hi Sarthak,
DICOM export requires improved typing to produce a valid set of tags.
https://github.com/KitwareMedical/ITKDICOM
but the implementation is in initial stages. I would be happy to
provide guidance if you would like to move it forward.
Thanks,
Matt
On Wed, Mar 8, 2017 at 3:11 PM, Sarthak P <
Post by Sarthak P
Hello All,
I am trying to write a DICOM image but I want to preserve the
properties
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
from the input image (origin, direction, spacing, etc.). The ITK examples do
not show how to do this properly and anything I have done with the
dicom
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
tags hasn't worked. Any help would be much appreciated.
//////////
const std::string dataDir = argv[1];
const std::string inputFile = dataDir + "/inputImage.nii.gz";
const std::string outputDir = dataDir + "/test/";
using ImageTypeToRead = itk::Image< float, 3 >;
using ImageTypeToWrite = itk::Image< short, 3 >;
auto inputImage = cbica::ReadImageWithOrientFix< itk::Image<
float, 3
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
(inputFile);
auto imageToWrite = inputImage;
auto dicomIO = itk::GDCMImageIO::New();
auto seriesWriter = itk::ImageSeriesWriter< ImageTypeToWrite,
itk::Image<ImageTypeToWrite::PixelType, 2> >::New();
auto namesGenerator = itk::NumericSeriesFileNames::New();
auto start = imageToWrite->GetLargestPossibleRegion().GetIndex();
auto size = imageToWrite->GetLargestPossibleRegion().GetSize();
namesGenerator->SetSeriesFormat((outputDir +
"/image%03d.dcm").c_str());
namesGenerator->SetStartIndex(start[2]);
namesGenerator->SetEndIndex(start[2] + size[2] - 1);
namesGenerator->SetIncrementIndex(1);
auto castFilter = itk::CastImageFilter<ImageTypeToRead,
ImageTypeToWrite>::New();
castFilter->SetInput(imageToWrite);
castFilter->Update();
seriesWriter->SetInput(castFilter->GetOutput());
seriesWriter->SetImageIO(dicomIO);
seriesWriter->SetFileNames(namesGenerator->GetFileNames());
typename itk::ImageSeriesReader< ImageTypeToRead
::DictionaryArrayType
outputArray;
// this doesn't work at all - was kind of hoping it would do the
heavy
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
lifting for me
//dicomIO->SetOrigin(0, imageToWrite->GetOrigin()[0]);
//dicomIO->SetOrigin(1, imageToWrite->GetOrigin()[1]);
//dicomIO->SetOrigin(2, imageToWrite->GetOrigin()[2]);
//dicomIO->SetSpacing(0, imageToWrite->GetSpacing()[0]);
//dicomIO->SetSpacing(1, imageToWrite->GetSpacing()[1]);
//dicomIO->SetSpacing(2, imageToWrite->GetSpacing()[2]);
//dicomIO->SetDimensions(0,
imageToWrite->GetLargestPossibleRegion().GetSize()[0]);
//dicomIO->SetDimensions(1,
imageToWrite->GetLargestPossibleRegion().GetSize()[1]);
//dicomIO->SetDimensions(2,
imageToWrite->GetLargestPossibleRegion().GetSize()[2]);
// this doesn't work at all
for (size_t i = 0; i <
imageToWrite->GetLargestPossibleRegion().GetSize()[2]; i++)
{
auto dict = new itk::ImageSeriesReader< ImageTypeToRead
::DictionaryType;
typename ImageTypeToWrite::PointType position;
typename ImageTypeToWrite::IndexType index;
index[0] = 0;
index[1] = 0;
index[2] = i;
imageToWrite->TransformIndexToPhysicalPoint(index, position);
// tags extracted from dicom lookup
http://dicomlookup.com/lookup.asp
itk::EncapsulateMetaData<std::string>(*dict, "0020|0032",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) +
"\\"
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
+
std::to_string(position[2])); // patient position
itk::EncapsulateMetaData<std::string>(*dict, "0018|5100",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) +
"\\"
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
+
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "2020|0010",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) +
"\\"
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
+
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|5101",
std::to_string(position[0]) + "\\" + std::to_string(position[1]) +
"\\"
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
+
std::to_string(position[2]));
itk::EncapsulateMetaData<std::string>(*dict, "0018|0050",
std::to_string(imageToWrite->GetSpacing()[2])); // Slice Thickness
itk::EncapsulateMetaData<std::string>(*dict, "0018|0088",
std::to_string(imageToWrite->GetSpacing()[2])); // Spacing Between Slices
itk::EncapsulateMetaData<std::string>(*dict, "0008|0008",
"DERIVED\\SECONDARY"); // Image Type
itk::EncapsulateMetaData<std::string>(*dict, "0008|0064",
"DV"); //
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
Conversion Type
outputArray.push_back(dict);
}
seriesWriter->SetMetaDataDictionaryArray(&outputArray); // no dictionary
information present without seriesReader
try
{
seriesWriter->Write();
}
catch (itk::ExceptionObject &e)
{
std::cerr << "Error occurred while trying to write the image '"
<<
Post by Sarthak P
Post by Matt McCormick
Post by Sarthak P
outputDir << "': " << e.what() << "\n";
exit(EXIT_FAILURE);
}
//////////
Thanks a ton,
Sarthak
_____________________________________
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
Loading...