[med-svn] [gdcm] 01/01: New upstream version 2.8.2
Gert Wollny
gewo at moszumanska.debian.org
Tue Aug 1 17:21:04 UTC 2017
This is an automated email from the git hooks/post-receive script.
gewo pushed a commit to branch upstream
in repository gdcm.
commit 363b32c3336bab7f4e7c662de0fe6f6b6aa1ab93
Author: Gert Wollny <gewo at debian.org>
Date: Tue Aug 1 06:39:18 2017 +0000
New upstream version 2.8.2
---
.travis.yml | 6 +-
Applications/Cxx/gdcmdump.cxx | 35 ++
Applications/Cxx/gdcminfo.cxx | 35 +-
Applications/Cxx/gdcmtar.cxx | 70 ++-
CMakeLists.txt | 2 +-
Examples/Cxx/EmptyMask.cxx | 242 +-------
Examples/Cxx/MrProtocol.cxx | 6 +
Source/Common/gdcmMD5.cxx | 1 +
Source/Common/gdcmSystem.cxx | 2 +-
Source/DataDictionary/gdcmUIDs.cxx | 2 +
.../CMakeLists.txt | 1 +
.../gdcmCSAHeader.cxx | 49 ++
.../gdcmCSAHeader.h | 12 +-
.../gdcmMrProtocol.cxx | 210 +++++++
.../gdcmMrProtocol.h | 83 +++
Source/MediaStorageAndFileFormat/CMakeLists.txt | 1 +
.../gdcmDirectionCosines.cxx | 26 +-
.../gdcmDirectionCosines.h | 6 +
.../gdcmEmptyMaskGenerator.cxx | 465 ++++++++++++++
.../gdcmEmptyMaskGenerator.h | 80 +++
.../MediaStorageAndFileFormat/gdcmPixmapWriter.cxx | 2 +-
Source/MediaStorageAndFileFormat/gdcmPrinter.cxx | 2 +-
.../gdcmSplitMosaicFilter.cxx | 190 +++++-
.../gdcmSplitMosaicFilter.h | 6 +
.../MediaStorageAndFileFormat/Cxx/CMakeLists.txt | 2 +
.../Cxx/TestSplitMosaicFilter.cxx | 15 +-
.../Cxx/TestSplitMosaicFilter2.cxx | 220 +++++++
.../Cxx/TestSplitMosaicFilter3.cxx | 173 ++++++
Utilities/doxygen/man/gdcmdump.xml | 680 +++++++++++++++++++++
Utilities/doxygen/man/gdcminfo.xml | 7 +
Utilities/doxygen/man/gdcmtar.xml | 8 +-
Wrapping/Python/gdcmswig.i | 6 +-
32 files changed, 2391 insertions(+), 254 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 8b3a54e..94c1958 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -29,10 +29,12 @@ matrix:
- CPACK_NAME=Linux
- compiler: gcc
os: linux
+ # No docbook-xsl-ns
addons: {apt: {packages: [default-jdk, mono-devel, swig, libcharls-dev, libvtk5-dev, libexpat-dev, libz-dev, uuid-dev, python-all-dev, libpoppler-dev, xsltproc, docbook-xsl, dcmtk]}}
env:
- CFLAGS="-Wall -Wextra -m64"
- CXXFLAGS="-Wall -Wextra -m64"
+ # Cant use manpage with old docbook
- CMAKE_EXTRA="-DGDCM_USE_SYSTEM_OPENSSL:BOOL=ON -DGDCM_WRAP_PYTHON:BOOL=ON -DGDCM_WRAP_CSHARP:BOOL=ON -DGDCM_WRAP_JAVA:BOOL=ON -DGDCM_WRAP_PHP:BOOL=OFF -DGDCM_USE_SYSTEM_EXPAT:BOOL=ON -DGDCM_USE_SYSTEM_JSON:BOOL=OFF -DGDCM_USE_SYSTEM_LIBXML2:BOOL=ON -DGDCM_USE_SYSTEM_OPENJPEG:BOOL=OFF -DGDCM_USE_SYSTEM_POPPLER:BOOL=ON -DGDCM_USE_SYSTEM_UUID:BOOL=ON -DGDCM_USE_SYSTEM_ZLIB:BOOL=ON -DGDCM_WEAK_SWIG_CHECK:BOOL=ON -DGDCM_LEGACY_SILENT:BOOL=ON -DGDCM_BUILD_DOCBOOK_MANPAGES:BOOL=OFF"
- B_NAME=system
- CPACK_NAME=Linux
@@ -51,7 +53,7 @@ matrix:
- CXXFLAGS="-Wall -Wextra" # -m64 -fsanitize=address,undefined
# http://stackoverflow.com/questions/15678153/homebrew-python-on-mac-os-x-10-8-fatal-python-error-pythreadstate-get-no-cu
#- CMAKE_EXTRA="-DGDCM_WRAP_PYTHON:BOOL=ON -DGDCM_BUILD_DOCBOOK_MANPAGES:BOOL=OFF -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python2.7"
- - CMAKE_EXTRA="-DGDCM_WRAP_PYTHON:BOOL=ON -DGDCM_BUILD_DOCBOOK_MANPAGES:BOOL=OFF"
+ - CMAKE_EXTRA="-DGDCM_WRAP_PYTHON:BOOL=ON -DGDCM_WRAP_CSHARP:BOOL=OFF -DGDCM_WRAP_JAVA:BOOL=ON -DGDCM_USE_SYSTEM_UUID:BOOL=ON -DGDCM_USE_SYSTEM_ZLIB:BOOL=ON -DGDCM_BUILD_DOCBOOK_MANPAGES:BOOL=OFF"
- B_NAME=default
- CPACK_NAME=Darwin
@@ -64,7 +66,7 @@ before_install:
# https://docs.travis-ci.com/user/osx-ci-environment/#Environment-variables
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then mv Testing/Data Testing/Data.old; fi
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update ; fi
- - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install swig python3 ; fi
+ - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install swig docbook-xsl ; fi
# https://github.com/travis-ci/travis-ci/issues/2312
#- if [ "$TRAVIS_OS_NAME" == "osx" ]; then virtualenv env -p python3 ; fi
#- if [ "$TRAVIS_OS_NAME" == "osx" ]; then source env/bin/activate ; fi
diff --git a/Applications/Cxx/gdcmdump.cxx b/Applications/Cxx/gdcmdump.cxx
index 41ba9e4..24a6176 100644
--- a/Applications/Cxx/gdcmdump.cxx
+++ b/Applications/Cxx/gdcmdump.cxx
@@ -964,6 +964,30 @@ static int PrintCSA(const std::string & filename)
return ret;
}
+static int PrintMrProtocol(const std::string & filename)
+{
+ gdcm::Reader reader;
+ reader.SetFileName( filename.c_str() );
+ if( !reader.Read() )
+ {
+ std::cerr << "Failed to read: " << filename << std::endl;
+ return 1;
+ }
+
+ gdcm::CSAHeader csa;
+ const gdcm::DataSet& ds = reader.GetFile().GetDataSet();
+ gdcm::MrProtocol mrprot;
+ if( csa.GetMrProtocol(ds, mrprot))
+ {
+ std::cout << mrprot;
+ }
+ else
+ {
+ std::cout << "Could not find MrProtocol/MrPhoenixProtocol ASCII section" << std::endl;
+ }
+
+ return 0;
+}
static void PrintVersion()
@@ -989,6 +1013,7 @@ static void PrintHelp()
std::cout << " -C --csa print SIEMENS CSA Header (0029,[12]0,SIEMENS CSA HEADER)." << std::endl;
std::cout << " --csa-asl print decoded SIEMENS CSA MR_ASL (base64)." << std::endl;
std::cout << " --csa-diffusion print decoded SIEMENS CSA MRDiffusion (base64)." << std::endl;
+ std::cout << " --mrprotocol print SIEMENS CSA MrProtocol only (within ASCCONV BEGIN/END)." << std::endl;
std::cout << " -P --pdb print GEMS Protocol Data Block (0025,1b,GEMS_SERS_01)." << std::endl;
std::cout << " --elscint print ELSCINT Protocol Information (01f7,26,ELSCINT1)." << std::endl;
std::cout << " --vepro print VEPRO Protocol Information (0055,20,VEPRO VIF 3.0 DATA)." << std::endl;
@@ -1018,6 +1043,7 @@ int main (int argc, char *argv[])
int dump = 0;
int print = 0;
int printcsa = 0;
+ int printmrprotocol = 0;
int printcsabase64 = 0;
int printcsaasl = 0;
int printcsadiffusion = 0;
@@ -1070,6 +1096,7 @@ int main (int argc, char *argv[])
{"ct3", 0, &printct3, 1},
{"csa-asl", 0, &printcsaasl, 1},
{"csa-diffusion", 0, &printcsadiffusion, 1},
+ {"mrprotocol", 0, &printmrprotocol, 1},
{0, 0, 0, 0} // required
};
static const char short_options[] = "i:xrpdcCPAVWDEhvI";
@@ -1299,6 +1326,10 @@ int main (int argc, char *argv[])
{
res += PrintCSA(*it);
}
+ else if( printmrprotocol )
+ {
+ res += PrintMrProtocol(*it);
+ }
else if( printcsabase64 )
{
res += PrintCSABase64(*it, csaname);
@@ -1350,6 +1381,10 @@ int main (int argc, char *argv[])
{
res += PrintCSA(filename);
}
+ else if( printmrprotocol )
+ {
+ res += PrintMrProtocol(filename);
+ }
else if( printcsabase64 )
{
res += PrintCSABase64(filename, csaname);
diff --git a/Applications/Cxx/gdcminfo.cxx b/Applications/Cxx/gdcminfo.cxx
index be862f3..bf8b013 100644
--- a/Applications/Cxx/gdcminfo.cxx
+++ b/Applications/Cxx/gdcminfo.cxx
@@ -31,6 +31,7 @@
#include "gdcmSystem.h"
#include "gdcmDirectory.h"
#include "gdcmImageHelper.h"
+#include "gdcmSplitMosaicFilter.h"
#ifdef GDCM_USE_SYSTEM_POPPLER
#include <poppler/poppler-config.h>
@@ -319,6 +320,7 @@ static void PrintHelp()
// std::cout << " -b --check-big-endian check if file is ." << std::endl;
std::cout << " --force-rescale force rescale." << std::endl;
std::cout << " --force-spacing force spacing." << std::endl;
+ std::cout << " --mosaic dump image information of MOSAIC." << std::endl;
std::cout << "General Options:" << std::endl;
std::cout << " -V --verbose more verbose (warning+error)." << std::endl;
@@ -334,6 +336,7 @@ static void PrintHelp()
int deflated = 0; // check deflated
int checkcompression = 0;
int md5sum = 0;
+ int mosaic = 0;
static int ProcessOneFile( std::string const & filename, gdcm::Defs const & defs )
{
@@ -382,27 +385,42 @@ static int ProcessOneFile( std::string const & filename, gdcm::Defs const & defs
std::cerr << "Could not read image from: " << filename << std::endl;
return 1;
}
- //const gdcm::File &file = reader.GetFile();
- //const gdcm::DataSet &ds = file.GetDataSet();
+ gdcm::SplitMosaicFilter filter;
+ const gdcm::Image *pimage = NULL;
const gdcm::Image &image = reader.GetImage();
- const double *dircos = image.GetDirectionCosines();
+ if( mosaic )
+ {
+ filter.SetImage( image );
+ filter.SetFile( reader.GetFile() );
+ if( !filter.Split() )
+ {
+ std::cerr << "Could not split mosaic : " << filename << std::endl;
+ return 1;
+ }
+ pimage = &filter.GetImage();
+ }
+ else
+ {
+ pimage = ℑ
+ }
+ const double *dircos = pimage->GetDirectionCosines();
gdcm::Orientation::OrientationType type = gdcm::Orientation::GetType(dircos);
const char *label = gdcm::Orientation::GetLabel( type );
- image.Print( std::cout );
+ pimage->Print( std::cout );
std::cout << "Orientation Label: " << label << std::endl;
if( checkcompression )
{
- bool lossy = image.IsLossy();
+ bool lossy = pimage->IsLossy();
std::cout << "Encapsulated Stream was found to be: " << (lossy ? "lossy" : "lossless") << std::endl;
}
if( md5sum )
{
- char *buffer = new char[ image.GetBufferLength() ];
- if( image.GetBuffer( buffer ) )
+ char *buffer = new char[ pimage->GetBufferLength() ];
+ if( pimage->GetBuffer( buffer ) )
{
char digest[33] = {};
- gdcm::MD5::Compute( buffer, image.GetBufferLength(), digest );
+ gdcm::MD5::Compute( buffer, pimage->GetBufferLength(), digest );
std::cout << "md5sum: " << digest << std::endl;
}
else
@@ -563,6 +581,7 @@ int main(int argc, char *argv[])
{"check-compression", 0, &checkcompression, 1},
{"force-rescale", 0, &forcerescale, 1},
{"force-spacing", 0, &forcespacing, 1},
+ {"mosaic", 0, &mosaic, 1},
{"verbose", 0, &verbose, 1},
{"warning", 0, &warning, 1},
diff --git a/Applications/Cxx/gdcmtar.cxx b/Applications/Cxx/gdcmtar.cxx
index 7ac126a..f16f39b 100644
--- a/Applications/Cxx/gdcmtar.cxx
+++ b/Applications/Cxx/gdcmtar.cxx
@@ -37,6 +37,9 @@
#include "gdcmScanner.h"
#include "gdcmIPPSorter.h"
#include "gdcmAttribute.h"
+#include "gdcmAnonymizer.h"
+#include "gdcmTagKeywords.h"
+#include "gdcmMrProtocol.h"
#include <string>
#include <iostream>
@@ -65,6 +68,7 @@ static void PrintHelp()
std::cout << " --enhance enhance (default)" << std::endl;
std::cout << " -U --unenhance unenhance" << std::endl;
std::cout << " -M --mosaic Split SIEMENS Mosaic image into multiple frames." << std::endl;
+ std::cout << " --mosaic-private When splitting SIEMENS Mosaic image into multiple frames, ppreserve private attributes (advanced user only)." << std::endl;
std::cout << " -p --pattern Specify trailing file pattern." << std::endl;
std::cout << " --root-uid Root UID." << std::endl;
//std::cout << " --resources-path Resources path." << std::endl;
@@ -957,6 +961,7 @@ int main (int argc, char *argv[])
std::string root;
int resourcespath = 0;
int mosaic = 0;
+ int mosaic_private = 0;
int enhance = 1;
int unenhance = 0;
std::string xmlpath;
@@ -981,6 +986,7 @@ int main (int argc, char *argv[])
{"unenhance", 0, &unenhance, 1}, // unenhance
{"root-uid", 1, &rootuid, 1}, // specific Root (not GDCM)
//{"resources-path", 0, &resourcespath, 1},
+ {"mosaic-private", 0, &mosaic_private, 1}, // keep private attributes
// General options !
{"verbose", 0, &verbose, 1},
@@ -1246,8 +1252,7 @@ int main (int argc, char *argv[])
const unsigned int *dims = image.GetDimensions();
const gdcm::DataElement &pixeldata = image.GetDataElement();
const gdcm::ByteValue *bv = pixeldata.GetByteValue();
- unsigned long slice_len = image.GetBufferLength() / dims[2];
- //assert( image.GetBufferLength() == bv->GetLength() );
+ size_t slice_len = image.GetBufferLength() / dims[2];
gdcm::FilenameGenerator fg;
fg.SetNumberOfFilenames( dims[2] );
@@ -1265,17 +1270,78 @@ int main (int argc, char *argv[])
const double *origin = image.GetOrigin();
double zspacing = image.GetSpacing(2);
+ gdcm::CSAHeader csa;
+ gdcm::DataSet & ds = reader.GetFile().GetDataSet();
+
+ gdcm::MrProtocol mrprot;
+ if( !csa.GetMrProtocol(ds, mrprot) ) return 1;
+
+ gdcm::MrProtocol::SliceArray sa;
+ b = mrprot.GetSliceArray(sa);
+ if( !b ) return 1;
+
+ size_t size = sa.Slices.size();
+ if( !size ) return 1;
+
+ if( !mosaic_private )
+ {
+ gdcm::Anonymizer ano;
+ ano.SetFile( reader.GetFile() );
+ // Remove CSA header
+ ano.RemovePrivateTags();
+ }
+
+ double slicePos[3];
+ double sliceNor[3];
+ namespace kwd = gdcm::Keywords;
+ gdcm::UIDGenerator ug;
+
+ kwd::InstanceNumber instart;
+ instart.Set(ds);
+ int istart = instart.GetValue();
+
for(unsigned int i = 0; i < dims[2]; ++i)
{
+ gdcm::MrProtocol::Slice & protSlice = sa.Slices[i];
+ gdcm::MrProtocol::Vector3 & protV = protSlice.Position;
+ gdcm::MrProtocol::Vector3 & protN = protSlice.Normal;
+ slicePos[0] = protV.dSag;
+ slicePos[1] = protV.dCor;
+ slicePos[2] = protV.dTra;
+ sliceNor[0] = protN.dSag;
+ sliceNor[1] = protN.dCor;
+ sliceNor[2] = protN.dTra;
+
double new_origin[3];
for (int j = 0; j < 3; j++)
{
// the n'th slice is n * z-spacing aloung the IOP-derived
// z-axis
new_origin[j] = origin[j] + normal[j] * i * zspacing;
+ if( std::fabs(slicePos[j] - new_origin[j]) > 1e-3 )
+ {
+ gdcmErrorMacro("Invalid position found");
+ return 1;
+ }
+ const double snv_dot = gdcm::DirectionCosines::Dot( normal, sliceNor );
+ if( std::fabs(1. - snv_dot) > 1e-6 )
+ {
+ gdcmErrorMacro("Invalid direction found");
+ return false;
+ }
}
+ kwd::SOPInstanceUID sid;
+ sid.SetValue( ug.Generate() );
+ ds.Replace( sid.GetAsDataElement() );
+
const char *outfilenamei = fg.GetFilename(i);
+ kwd::SliceLocation sl;
+ sl.SetValue( new_origin[2] );
+ ds.Replace( sl.GetAsDataElement() );
+ kwd::InstanceNumber in;
+ in.SetValue( istart + i ); // Start at mosaic instance number
+ ds.Replace( in.GetAsDataElement() );
gdcm::ImageWriter writer;
writer.SetFileName( outfilenamei );
//writer.SetFile( filter.GetFile() );
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d8be715..1342e89 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,7 +35,7 @@ set(GDCM_PACKAGE_CONTACT "GDCM Developers <gdcm-developers at lists.sourceforge.net
#----------------------------------------------------------------------------
set(GDCM_MAJOR_VERSION 2)
set(GDCM_MINOR_VERSION 8)
-set(GDCM_BUILD_VERSION 0)
+set(GDCM_BUILD_VERSION 2)
set(GDCM_VERSION
"${GDCM_MAJOR_VERSION}.${GDCM_MINOR_VERSION}.${GDCM_BUILD_VERSION}")
# let advanced user the option to define GDCM_API_VERSION:
diff --git a/Examples/Cxx/EmptyMask.cxx b/Examples/Cxx/EmptyMask.cxx
index f829a22..7ee8009 100644
--- a/Examples/Cxx/EmptyMask.cxx
+++ b/Examples/Cxx/EmptyMask.cxx
@@ -11,224 +11,44 @@
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
-#include "gdcmImage.h"
-#include "gdcmImageWriter.h"
-#include "gdcmFileDerivation.h"
-#include "gdcmUIDGenerator.h"
-#include "gdcmImageRegionReader.h"
-#include "gdcmDirectory.h"
-#include "gdcmScanner.h"
-#include "gdcmFilename.h"
-#include "gdcmFileStreamer.h"
-#include "gdcmAnonymizer.h"
-#include "gdcmAttribute.h"
+#include "gdcmEmptyMaskGenerator.h"
-static gdcm::Tag t1(0x8,0x16);
-static gdcm::Tag t2(0x8,0x18);
-static gdcm::Tag t3(0x20,0xe);
-static gdcm::Tag t4(0x20,0x52);
-
-static bool EmptyMaskDICOMFile( gdcm::UIDGenerator & uid, const gdcm::Scanner & s,
- const std::map< std::string, std::string > & seriesuidhash,
- const std::map< std::string, std::string > & framerefuidhash,
- const char * outfile, const char * filename )
-{
- if( s.IsKey( filename ) )
- {
- gdcm::ImageRegionReader irr;
- irr.SetFileName( filename );
- const bool b3 = irr.ReadInformation();
- (void)b3;
- size_t buflen = irr.ComputeBufferLength();
-
- // Step 2: DERIVED object
- gdcm::FileDerivation fd;
- const char * ReferencedSOPClassUID = s.GetValue (filename, t1);
- const char * ReferencedSOPInstanceUID = s.GetValue (filename, t2);
- if( !fd.AddReference( ReferencedSOPClassUID, ReferencedSOPInstanceUID ) )
- {
- //std::cerr << "AddRef: " << (ReferencedSOPClassUID ? ReferencedSOPClassUID : "") << "," << (ReferencedSOPInstanceUID ? ReferencedSOPInstanceUID : "") << std::endl;
- std::cerr << "AddRef: " << filename << std::endl;
- // This is not considered an error to not reference, eg. UID padded with 0
- }
-
- // CID 7202 Source Image Purposes of Reference
- // DCM 121321 Mask image for image processing operation
- fd.SetPurposeOfReferenceCodeSequenceCodeValue( 121321 );
- // CID 7203 Image Derivation
- // DCM 113047 Pixel by pixel mask
- fd.SetDerivationCodeSequenceCodeValue( 113047 );
- fd.SetDerivationDescription( "Empty Mask Derivation" );
- fd.SetAppendDerivationHistory( true );
- fd.SetFile( irr.GetFile() );
- if( !fd.Derive() )
- {
- std::cerr << "Sorry could not derive using input info" << std::endl;
- return false;
- }
-
- gdcm::Anonymizer ano;
- ano.SetFile( fd.GetFile() );
- ano.RemoveGroupLength();
- ano.Replace (t2, uid.Generate());
- const char * oldseriesuid = s.GetValue (filename, t3);
- const char * oldframerefuid = s.GetValue (filename, t4);
- if( oldseriesuid )
- {
- std::map< std::string, std::string >::const_iterator it1 = seriesuidhash.find( oldseriesuid );
- ano.Replace (t3, it1->second.c_str() );
- }
- if( oldframerefuid )
- {
- std::map< std::string, std::string >::const_iterator it2 = framerefuidhash.find( oldframerefuid );
- ano.Replace (t4, it2->second.c_str() );
- }
-
- {
- gdcm::DataSet& ds = ano.GetFile().GetDataSet();
- gdcm::Attribute<0x0008,0x0008> at3;
- gdcm::Attribute<0x0008,0x0008> at4;
- at3.SetFromDataSet( ds );
- unsigned int nvalues = at3.GetNumberOfValues();
- unsigned int newvalues = std::max( nvalues, 4u );
- at4.SetNumberOfValues( newvalues );
- // copy original ones:
- for( unsigned int i = 0u; i < nvalues; ++i )
- {
- at4.SetValue(i, at3.GetValue(i) );
- }
- // Make up non empty values:
- static const gdcm::CSComp values[] = {"DERIVED","SECONDARY","OTHER"};
- for( unsigned int i = nvalues; i < 3u; ++i )
- {
- at4.SetValue(i, values[i] );
- }
- // why not:
- at4.SetValue( 3u, "MASK" );
- ds.Replace( at4.GetAsDataElement() );
- }
-
- gdcm::File & file = ano.GetFile();
- gdcm::FileMetaInformation & fmi = file.GetHeader();
- const gdcm::TransferSyntax & orits = fmi.GetDataSetTransferSyntax();
- gdcm::TransferSyntax::TSType newts = gdcm::TransferSyntax::ImplicitVRLittleEndian;
- if( orits.IsExplicit() )
- {
- newts = gdcm::TransferSyntax::ExplicitVRLittleEndian;
- }
- fmi.Clear();
- fmi.SetDataSetTransferSyntax( newts );
-
- gdcm::Writer w;
- w.SetFile( ano.GetFile() );
-
- // Set the filename:
- w.SetFileName( outfile );
- if( !w.Write() )
- {
- return false;
- }
- gdcm::FileStreamer fs;
- fs.SetTemplateFileName(outfile);
- fs.SetOutputFileName(outfile);
- gdcm::Tag pixeldata (0x7fe0, 0x0010);
- fs.CheckDataElement( pixeldata );
- if( !fs.StartDataElement( pixeldata ) )
- {
- std::cerr << "StartDataElement" << std::endl;
- return false;
- }
- {
- const size_t chunk = 4096;
- char bytes[chunk] = {};
- const size_t nchunks = buflen / chunk;
- const size_t remain = buflen % chunk;
- for( size_t i = 0; i < nchunks; ++i )
- {
- // Read the source file into a byte array.
- fs.AppendToDataElement( pixeldata, bytes, chunk );
- }
- fs.AppendToDataElement( pixeldata, bytes, remain );
- }
- if( !fs.StopDataElement( pixeldata ) )
- {
- // Most likely an issue with Pixel Data Length computation:
- std::cerr << "StopDataElement" << std::endl;
- return false;
- }
- }
- else
- {
- std::cerr << "Not DICOM file: " << filename << std::endl;
- return false;
- }
- return true;
-}
+#include <string>
+#include <cstring>
-int main(int, char *argv[])
+int main( int argc, char *argv[] )
{
- gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( "EmptyMask" );
- const char * dirname = argv[1];
- const char * outdir = argv[2];
- gdcm::System::FileIsDirectory( dirname );
- gdcm::System::MakeDirectory( outdir );
- gdcm::Directory d;
- const unsigned int nfiles = d.Load( dirname, true );
- (void)nfiles;
- gdcm::Directory::FilenamesType const & filenames = d.GetFilenames();
-
- gdcm::Trace::WarningOff();
- gdcm::Trace::ErrorOff();
-
- gdcm::Scanner s;
- s.AddTag( t1 );
- s.AddTag( t2 );
- s.AddTag( t3 );
- s.AddTag( t4 );
- const bool b2 = s.Scan( filenames );
- (void)b2;
- gdcm::UIDGenerator uid;
- int ret = 0;
- std::map< std::string, std::string > seriesuidhash;
+ std::string inputdir;
+ std::string outputdir;
+ bool input_sopclassuid = true;
+ bool grayscale_secondary_sopclassuid = false;
+ if( argc < 3 ) return 1;
+ inputdir = argv[1];
+ outputdir = argv[2];
+ // input_sopclassuid -> Use original SOP Class UID from input DICOM (Default).
+ // grayscale_secondary_sopclassuid -> Use Grayscale Secondary Image Storage SOP Class UID.
+ if( argc >= 3 )
{
- gdcm::Scanner::ValuesType vt = s.GetValues(t3);
- for(
- gdcm::Scanner::ValuesType::const_iterator it = vt.begin();
- it != vt.end(); ++it )
- {
- const char * newseriesuid = uid.Generate();
- seriesuidhash.insert(
- std::make_pair( *it, newseriesuid ) );
+ input_sopclassuid = false;
+ if( strcmp("input_sopclassuid", argv[3]) == 0 )
+ input_sopclassuid = true;
+ else if (strcmp("grayscale_secondary_sopclassuid", argv[3]) == 0 ) {
+ grayscale_secondary_sopclassuid = true;
}
}
- std::map< std::string, std::string > framerefuidhash;
- {
- gdcm::Scanner::ValuesType vt = s.GetValues(t4);
- // Frame of Reference are relative to Series UID
- // http://dicom.nema.org/medical/Dicom/2015a/output/chtml/part03/sect_C.7.4.html
- for(
- gdcm::Scanner::ValuesType::const_iterator it = vt.begin();
- it != vt.end(); ++it )
- {
- const char * newframerefuid = uid.Generate();
- framerefuidhash.insert(
- std::make_pair( *it, newframerefuid ) );
- }
- }
- for( gdcm::Directory::FilenamesType::const_iterator it = filenames.begin(); it != filenames.end(); ++it )
+
+ //
+ gdcm::EmptyMaskGenerator emg;
+ if( input_sopclassuid )
+ emg.SetSOPClassUIDMode( gdcm::EmptyMaskGenerator::UseOriginalSOPClassUID );
+ else if( grayscale_secondary_sopclassuid )
+ emg.SetSOPClassUIDMode( gdcm::EmptyMaskGenerator::UseGrayscaleSecondaryImageStorage );
+ emg.SetInputDirectory( inputdir.c_str() );
+ emg.SetOutputDirectory( outputdir.c_str() );
+ if( !emg.Execute() )
{
- const char * filename = it->c_str();
- gdcm::Filename fn( filename );
- std::string outfile = outdir;
- outfile += '/';
- outfile += fn.GetName();
- if( !EmptyMaskDICOMFile( uid, s, seriesuidhash, framerefuidhash, outfile.c_str(), filename ) )
- {
- std::cerr << "Failure to EmptyMask" << std::endl;
- gdcm::System::RemoveFile(outfile.c_str());
- ret = 1;
- }
+ return 1;
}
- return ret;
+ return 0;
}
diff --git a/Examples/Cxx/MrProtocol.cxx b/Examples/Cxx/MrProtocol.cxx
index 5f0a313..67bc0c3 100644
--- a/Examples/Cxx/MrProtocol.cxx
+++ b/Examples/Cxx/MrProtocol.cxx
@@ -540,5 +540,11 @@ One can find it also in the protocol:
return 1;
}
+ gdcm::MrProtocol mrprot;
+ if( csa.GetMrProtocol(ds, mrprot) )
+ {
+ std::cout << mrprot << std::endl;
+ }
+
return 0;
}
diff --git a/Source/Common/gdcmMD5.cxx b/Source/Common/gdcmMD5.cxx
index a60d4d0..7b3bf03 100644
--- a/Source/Common/gdcmMD5.cxx
+++ b/Source/Common/gdcmMD5.cxx
@@ -53,6 +53,7 @@ bool MD5::Compute(const char *buffer, size_t buf_len, char digest_str[33])
digest_str[2*16] = '\0';
return true;
#else
+ (void)digest_str;
return false;
#endif
}
diff --git a/Source/Common/gdcmSystem.cxx b/Source/Common/gdcmSystem.cxx
index a33e533..0721bdf 100644
--- a/Source/Common/gdcmSystem.cxx
+++ b/Source/Common/gdcmSystem.cxx
@@ -977,7 +977,7 @@ static const char *CharsetAliasToName(const char *alias)
}
}
// We need to tell the user...
- gdcmWarningMacro( "Could not find Charset from alias: " + alias );
+ gdcmWarningMacro( std::string("Could not find Charset from alias: ") + alias );
return NULL;
}
#endif //_WIN32
diff --git a/Source/DataDictionary/gdcmUIDs.cxx b/Source/DataDictionary/gdcmUIDs.cxx
index 62c7a66..f7764f0 100644
--- a/Source/DataDictionary/gdcmUIDs.cxx
+++ b/Source/DataDictionary/gdcmUIDs.cxx
@@ -363,6 +363,8 @@ DICOM_Conformance_Statement_MR_R2.6.pdf
{"1.2.840.10008.1.2.4.102","MPEG-4 AVC/H.264 High Profile / Level 4.1"},
{"1.2.840.10008.1.2.4.103","MPEG-4 AVC/H.264 BD-compatible High Profile / Level 4.1"},
{"1.2.840.10008.5.1.4.1.1.130", "Enhanced PET Image Storage" },
+{"1.2.840.10008.5.1.4.1.1.14.1","Intravascular Optical Coherence Tomography Image Storage - For Presentation"},
+{"1.2.840.10008.5.1.4.1.1.14.2","Intravascular Optical Coherence Tomography Image Storage - For Processing"},
{ 0, 0 }
};
diff --git a/Source/DataStructureAndEncodingDefinition/CMakeLists.txt b/Source/DataStructureAndEncodingDefinition/CMakeLists.txt
index 9fb6965..b9b428e 100644
--- a/Source/DataStructureAndEncodingDefinition/CMakeLists.txt
+++ b/Source/DataStructureAndEncodingDefinition/CMakeLists.txt
@@ -52,6 +52,7 @@ set(DSED_SRCS
gdcmWriter.cxx
#gdcmParser.cxx
gdcmCSAHeader.cxx
+ gdcmMrProtocol.cxx
gdcmPDBHeader.cxx
gdcmTransferSyntax.cxx
gdcmVM.cxx
diff --git a/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.cxx b/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.cxx
index fc3c0b2..15baa69 100644
--- a/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.cxx
+++ b/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.cxx
@@ -1261,4 +1261,53 @@ const PrivateTag & CSAHeader::GetCSADataInfo()
return t3;
}
+bool CSAHeader::GetMrProtocol( const DataSet & ds, MrProtocol & mrProtocol )
+{
+ if(!ds.FindDataElement( t2 ) )
+ return false;
+ if( !LoadFromDataElement( ds.GetDataElement( t2 ) ) )
+ return false;
+
+ // 28 - 'MrProtocolVersion' VM 1, VR IS, SyngoDT 6, NoOfItems 6, Data '21710006'
+ int mrprotocolversion = 0;
+ static const char version[] = "MrProtocolVersion";
+ // This is not an error if we do not find the version:
+ if( FindCSAElementByName( version ) )
+ {
+ const CSAElement &csavers = GetCSAElementByName( version );
+ if( !csavers.IsEmpty() )
+ {
+ const ByteValue* bv = csavers.GetByteValue();
+ std::string str( bv->GetPointer(), bv->GetLength() );
+ std::istringstream is(str);
+ is >> mrprotocolversion;
+ }
+ }
+
+ static const char * candidates[] = {
+ "MrProtocol",
+ "MrPhoenixProtocol"
+ };
+ static const int n = sizeof candidates / sizeof * candidates;
+ bool found = false;
+ for( int i = 0; i < n; ++i )
+ {
+ const char * candidate = candidates[i];
+ if( FindCSAElementByName( candidate ) )
+ {
+ // assume the correct one is the one that is not empty,
+ // ideally we should rely on the version...
+ const gdcm::CSAElement &csael = GetCSAElementByName( candidate );
+ if( !csael.IsEmpty() )
+ {
+ if( mrProtocol.Load(csael.GetByteValue(), candidate, mrprotocolversion) )
+ {
+ found = true;
+ }
+ }
+ }
+ }
+ return found;
+}
+
} // end namespace gdcm
diff --git a/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.h b/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.h
index a886efa..2782a68 100644
--- a/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.h
+++ b/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.h
@@ -17,6 +17,7 @@
#include "gdcmTypes.h"
#include "gdcmDataSet.h"
#include "gdcmCSAElement.h"
+#include "gdcmMrProtocol.h"
namespace gdcm
{
@@ -76,11 +77,11 @@ public :
ZEROED_OUT
} CSAHeaderType;
- template <typename TSwap>
- std::istream &Read(std::istream &is);
+ GDCM_LEGACY(template <typename TSwap>
+ std::istream &Read(std::istream &is));
- template <typename TSwap>
- const std::ostream &Write(std::ostream &os) const;
+ GDCM_LEGACY(template <typename TSwap>
+ const std::ostream &Write(std::ostream &os) const);
/// Decode the CSAHeader from element 'de'
bool LoadFromDataElement(DataElement const &de);
@@ -118,6 +119,9 @@ public :
/// \warning Case Sensitive
bool FindCSAElementByName(const char *name);
+ /// Retrieve the ASCII portion stored within the MrProtocol/MrPhoenixProtocol:
+ bool GetMrProtocol( const DataSet & ds, MrProtocol & mrProtocol );
+
protected:
const CSAElement& GetCSAEEnd() const;
diff --git a/Source/DataStructureAndEncodingDefinition/gdcmMrProtocol.cxx b/Source/DataStructureAndEncodingDefinition/gdcmMrProtocol.cxx
new file mode 100644
index 0000000..b22b92f
--- /dev/null
+++ b/Source/DataStructureAndEncodingDefinition/gdcmMrProtocol.cxx
@@ -0,0 +1,210 @@
+/*=========================================================================
+
+ Program: GDCM (Grassroots DICOM). A DICOM library
+
+ Copyright (c) 2006-2011 Mathieu Malaterre
+ All rights reserved.
+ See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notice for more information.
+
+=========================================================================*/
+#include "gdcmMrProtocol.h"
+
+#include <map>
+#include <string>
+
+namespace gdcm
+{
+
+struct MrProtocol::Element {
+};
+
+typedef std::map< std::string, std::string > MyMapType;
+struct MrProtocol::Internals {
+ MyMapType mymap;
+ std::string csastr;
+ int version;
+};
+
+static inline bool starts_with(const std::string& s1, const std::string& s2)
+{
+ return s2.size() <= s1.size() && s1.compare(0, s2.size(), s2) == 0;
+}
+
+MrProtocol::MrProtocol()
+{
+ Pimpl = new MrProtocol::Internals;
+}
+
+bool MrProtocol::Load( const ByteValue * bv, const char * csastr, int version )
+{
+ if( bv )
+ {
+ std::string str(bv->GetPointer(), bv->GetLength());
+ std::istringstream is(str);
+ std::string s;
+ Pimpl->version = version;
+ if( csastr ) Pimpl->csastr = csastr;
+ else Pimpl->csastr = "";
+ MyMapType &mymap = Pimpl->mymap;
+ mymap.clear();
+ // Need to handle both:
+ // ### ASCCONV BEGIN ###
+ // as well as:
+ // ### ASCCONV BEGIN object=MrProtDataImpl at MrProtocolData version=41310008 converter=%MEASCONST%/ConverterList/Prot_Converter.txt ###
+ static const char begin[] = "### ASCCONV BEGIN ";
+ static const char end[] = "### ASCCONV END ###";
+ bool hasstarted = false;
+ while( std::getline(is, s ) )
+ {
+ if( !hasstarted )
+ {
+ hasstarted = starts_with(s, begin);
+ }
+ if( !hasstarted ) continue;
+ if( starts_with(s, end) ) break;
+ std::string::size_type pos = s.find( '=' );
+ if( pos != std::string::npos )
+ {
+ std::string sub1 = s.substr(0, pos);
+ sub1.erase( sub1.find_last_not_of(" \t") + 1);
+ std::string sub2 = s.substr(pos+1); // skip the '=' char
+ sub2.erase( 0, sub2.find_first_not_of(" \t"));
+ mymap.insert( MyMapType::value_type(sub1, sub2) );
+ }
+ else
+ {
+ // ### ASCCONV BEGIN ###
+ // ### ASCCONV END ###
+ }
+ }
+ }
+ else
+ {
+ Pimpl->version = 0;
+ Pimpl->csastr = "";
+ Pimpl->mymap.clear();
+ return false;
+ }
+ return true;
+}
+
+MrProtocol::~MrProtocol()
+{
+ delete Pimpl;
+}
+
+int MrProtocol::GetVersion() const
+{
+ return Pimpl->version;
+}
+
+static inline std::string trim(std::string str)
+{
+ str.erase(0, str.find_first_not_of('"'));
+ str.erase(str.find_last_not_of('"')+1);
+ return str;
+}
+
+void MrProtocol::Print(std::ostream &os) const
+{
+ {
+ os << Pimpl->csastr << " / Version: " << Pimpl->version << std::endl;
+ os << std::endl;
+ MyMapType &mymap = Pimpl->mymap;
+ for( MyMapType::const_iterator it = mymap.begin();
+ it != mymap.end(); ++it)
+ {
+ os << it->first << " : " << trim(std::string(it->second)) << std::endl;
+ }
+ }
+}
+
+const char * MrProtocol::GetMrProtocolByName(const char *name) const
+{
+ if( name )
+ {
+ MyMapType &mymap = Pimpl->mymap;
+ MyMapType::const_iterator it = mymap.find ( name );
+ if( it == mymap.end() ) return NULL;
+ return it->second.c_str();
+ }
+ return NULL;
+}
+
+bool MrProtocol::FindMrProtocolByName(const char *name) const
+{
+ if( name )
+ {
+ MyMapType &mymap = Pimpl->mymap;
+ MyMapType::const_iterator it = mymap.find ( name );
+ if( it != mymap.end() ) return true;
+ }
+ return false;
+}
+
+bool MrProtocol::GetSliceArray( MrProtocol::SliceArray & sa ) const
+{
+ // Technically this is all boilerplate code, since we could infer the type
+ // from the first few leters, eg:
+ // us -> unsigned char
+ // d -> double
+ // ...
+ sa.Slices.clear();
+ static const char saSize[] = "sSliceArray.lSize";
+ const char * sizestr = GetMrProtocolByName(saSize);
+ if( sizestr == NULL ) return false;
+ const int size = atoi( sizestr );
+ sa.Slices.resize( size );
+
+ // sSliceArray.asSlice[*].sPosition.dSag
+ // sSliceArray.asSlice[*].sPosition.dCor
+ // sSliceArray.asSlice[*].sPosition.dTra
+ char buf[512];
+ static const char templ1[] = "sSliceArray.asSlice[%d].sPosition.%s";
+ static const char templ2[] = "sSliceArray.asSlice[%d].sNormal.%s";
+ static const char *dir[3] = { "dSag", "dCor", "dTra"};
+ for( int i = 0; i < size; ++i )
+ {
+ Slice & slice = sa.Slices[i];
+ {
+ double v[3];
+ for( int j = 0; j < 3; ++j )
+ {
+ sprintf( buf, templ1, i, dir[j] );
+ const char * valstr = GetMrProtocolByName(buf);
+ // when not present this means 0.0
+ double val = 0.0;
+ if( valstr ) val = atof( valstr );
+ v[j] = val;
+ }
+ Vector3 & pos = slice.Position;
+ pos.dSag = v[0];
+ pos.dCor = v[1];
+ pos.dTra = v[2];
+ }
+ {
+ double v[3];
+ for( int j = 0; j < 3; ++j )
+ {
+ sprintf( buf, templ2, i, dir[j] );
+ const char * valstr = GetMrProtocolByName(buf);
+ // when not present this means 0.0
+ double val = 0.0;
+ if( valstr ) val = atof( valstr );
+ v[j] = val;
+ }
+ Vector3 & pos = slice.Normal;
+ pos.dSag = v[0];
+ pos.dCor = v[1];
+ pos.dTra = v[2];
+ }
+ }
+
+ return true;
+}
+
+} // end namespace gdcm
diff --git a/Source/DataStructureAndEncodingDefinition/gdcmMrProtocol.h b/Source/DataStructureAndEncodingDefinition/gdcmMrProtocol.h
new file mode 100644
index 0000000..4954da5
--- /dev/null
+++ b/Source/DataStructureAndEncodingDefinition/gdcmMrProtocol.h
@@ -0,0 +1,83 @@
+/*=========================================================================
+
+ Program: GDCM (Grassroots DICOM). A DICOM library
+
+ Copyright (c) 2006-2011 Mathieu Malaterre
+ All rights reserved.
+ See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notice for more information.
+
+=========================================================================*/
+#ifndef GDCMMRPROTOCOL_H
+#define GDCMMRPROTOCOL_H
+
+#include "gdcmTypes.h"
+#include "gdcmDataSet.h"
+
+namespace gdcm
+{
+class ByteValue;
+/*
+ * Everything done in this code is for the sole purpose of writing interoperable
+ * software under Sect. 1201 (f) Reverse Engineering exception of the DMCA.
+ * If you believe anything in this code violates any law or any of your rights,
+ * please contact us (gdcm-developers at lists.sourceforge.net) so that we can
+ * find a solution.
+ */
+//-----------------------------------------------------------------------------
+
+class DataElement;
+/**
+ * \brief Class for MrProtocol
+ */
+class GDCM_EXPORT MrProtocol
+{
+ friend std::ostream& operator<<(std::ostream &_os, const MrProtocol &d);
+public :
+ MrProtocol();
+ ~MrProtocol();
+
+ bool Load( const ByteValue * bv, const char * str, int version );
+ void Print(std::ostream &os) const;
+
+ int GetVersion() const;
+
+ const char * GetMrProtocolByName(const char *name) const;
+
+ bool FindMrProtocolByName(const char *name) const;
+
+ struct Vector3
+ {
+ double dSag;
+ double dCor;
+ double dTra;
+ };
+ struct Slice
+ {
+ Vector3 Normal;
+ Vector3 Position;
+ };
+ struct SliceArray
+ {
+ std::vector< Slice > Slices;
+ };
+ bool GetSliceArray( MrProtocol::SliceArray & sa ) const;
+
+private:
+ struct Element;
+ struct Internals;
+ Internals *Pimpl;
+};
+//-----------------------------------------------------------------------------
+inline std::ostream& operator<<(std::ostream &os, const MrProtocol &d)
+{
+ d.Print( os );
+ return os;
+}
+
+} // end namespace gdcm
+//-----------------------------------------------------------------------------
+#endif //GDCMMRPROTOCOL_H
diff --git a/Source/MediaStorageAndFileFormat/CMakeLists.txt b/Source/MediaStorageAndFileFormat/CMakeLists.txt
index c408a17..b8bdb8a 100644
--- a/Source/MediaStorageAndFileFormat/CMakeLists.txt
+++ b/Source/MediaStorageAndFileFormat/CMakeLists.txt
@@ -1,6 +1,7 @@
# Define the srcs for Media Storage And FileFormat
# MSFF
set(MSFF_SRCS
+ gdcmEmptyMaskGenerator.cxx
gdcmFileStreamer.cxx
gdcmJSON.cxx
gdcmFileChangeTransferSyntax.cxx
diff --git a/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.cxx b/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.cxx
index dada2d8..7f5e3f1 100644
--- a/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.cxx
+++ b/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.cxx
@@ -84,19 +84,39 @@ void DirectionCosines::Cross(double z[3]) const
z[0] = Zx; z[1] = Zy; z[2] = Zz;
}
-double DirectionCosines::Dot() const
+static inline double DotImpl(const double x[3], const double y[3])
{
- const double *x = Values;
- const double *y = x+3;
return x[0]*y[0] + x[1]*y[1] + x[2]*y[2];
}
+double DirectionCosines::Dot(const double x[3], const double y[3])
+{
+ return DotImpl(x, y);
+}
+
+double DirectionCosines::Dot() const
+{
+ return DotImpl(Values, Values+3);
+}
+
// static function is within gdcm:: namespace, so should not pollute too much on UNIX
static inline double Norm(const double x[3])
{
return sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
}
+void DirectionCosines::Normalize(double v[3])
+{
+ double den;
+ if ( (den = Norm(v)) != 0.0 )
+ {
+ for (int i=0; i < 3; i++)
+ {
+ v[i] /= den;
+ }
+ }
+}
+
void DirectionCosines::Normalize()
{
double *x = Values;
diff --git a/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.h b/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.h
index ce0842b..d03eafb 100644
--- a/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.h
+++ b/Source/MediaStorageAndFileFormat/gdcmDirectionCosines.h
@@ -40,9 +40,15 @@ public:
/// Compute Dot
double Dot() const;
+ /// Compute Dot
+ static double Dot(const double x[3], const double y[3]);
+
/// Normalize in-place
void Normalize();
+ /// Normalize in-place
+ static void Normalize(double v[3]);
+
/// Make the class behave like a const double *
operator const double* () const { return Values; }
diff --git a/Source/MediaStorageAndFileFormat/gdcmEmptyMaskGenerator.cxx b/Source/MediaStorageAndFileFormat/gdcmEmptyMaskGenerator.cxx
new file mode 100644
index 0000000..acbf8b1
--- /dev/null
+++ b/Source/MediaStorageAndFileFormat/gdcmEmptyMaskGenerator.cxx
@@ -0,0 +1,465 @@
+/*=========================================================================
+
+ Program: GDCM (Grassroots DICOM). A DICOM library
+
+ Copyright (c) 2006-2011 Mathieu Malaterre
+ All rights reserved.
+ See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notice for more information.
+
+=========================================================================*/
+#include "gdcmEmptyMaskGenerator.h"
+
+#include "gdcmImage.h"
+#include "gdcmImageWriter.h"
+#include "gdcmFileDerivation.h"
+#include "gdcmUIDGenerator.h"
+#include "gdcmImageRegionReader.h"
+#include "gdcmDirectory.h"
+#include "gdcmScanner.h"
+#include "gdcmFilename.h"
+#include "gdcmFileStreamer.h"
+#include "gdcmAnonymizer.h"
+#include "gdcmAttribute.h"
+#include "gdcmTagKeywords.h"
+
+namespace gdcm {
+
+struct EmptyMaskGenerator::impl
+{
+ static const Tag TSOPClassUID;
+ static const Tag TSOPInstanceUID;
+ static const Tag TSeriesInstanceUID;
+ static const Tag TFrameOfReferenceUID;
+
+ SOPClassUIDMode mode;
+ std::string inputdir;
+ std::string outputdir;
+ UIDGenerator uid;
+ std::map< std::string, std::string > seriesuidhash;
+ std::map< std::string, std::string > framerefuidhash;
+ Scanner s;
+ bool collectuids(Tag const & tag, std::map< std::string, std::string > & hash);
+ bool setup(const char * dirname, const char * outdir);
+ bool setmask( File & file );
+ bool derive( const char * filename, File & file );
+ bool anonymizeattributes( const char * filename, File & file );
+ bool populateattributes( const char * filename, File const & orifile, File & file );
+ bool setts( File & file );
+ bool run(const char * filename, const char * outfile);
+};
+
+const Tag EmptyMaskGenerator::impl::TSOPClassUID = Tag(0x0008,0x0016);
+const Tag EmptyMaskGenerator::impl::TSOPInstanceUID = Tag(0x0008,0x0018);
+const Tag EmptyMaskGenerator::impl::TSeriesInstanceUID = Tag(0x0020,0x000e);
+const Tag EmptyMaskGenerator::impl::TFrameOfReferenceUID = Tag(0x0020,0x0052);
+
+bool EmptyMaskGenerator::impl::collectuids( Tag const & tag, std::map< std::string, std::string > & hash)
+{
+ Scanner::ValuesType vt = s.GetValues(tag);
+ for( Scanner::ValuesType::const_iterator it = vt.begin();
+ it != vt.end(); ++it )
+ {
+ const char * newuid = uid.Generate();
+ hash.insert( std::make_pair( *it, newuid ) );
+ }
+ return true;
+}
+
+bool EmptyMaskGenerator::impl::setmask( File & file )
+{
+ DataSet& ds = file.GetDataSet();
+ namespace kwd = Keywords;
+ kwd::ImageType imtype;
+ kwd::ImageType copy;
+ imtype.SetFromDataSet( ds );
+ unsigned int nvalues = imtype.GetNumberOfValues();
+ unsigned int newvalues = std::max( nvalues, 4u );
+ copy.SetNumberOfValues( newvalues );
+ // copy original ones:
+ for( unsigned int i = 0u; i < nvalues; ++i )
+ {
+ copy.SetValue(i, imtype.GetValue(i) );
+ }
+ // Make up non empty values:
+ static const CSComp values[] = {"DERIVED","SECONDARY","OTHER"};
+ for( unsigned int i = nvalues; i < 3u; ++i )
+ {
+ copy.SetValue(i, values[i] );
+ }
+ // The fourth value is required to be set to 'MASK' for SD
+ copy.SetValue( 3u, "MASK" );
+ ds.Replace( copy.GetAsDataElement() );
+ return true;
+}
+
+bool EmptyMaskGenerator::impl::setup(const char * dirname, const char * outdir)
+{
+ if( !System::FileIsDirectory( dirname ) )
+ return false;
+ if( !System::MakeDirectory( outdir ) )
+ return false;
+ Directory d;
+ // recursive search by default
+ const unsigned int nfiles = d.Load( dirname, true );
+ if( nfiles == 0 )
+ {
+ gdcmDebugMacro( "No files found in: " << dirname );
+ return false;
+ }
+ Directory::FilenamesType const & filenames = d.GetFilenames();
+
+ s.AddTag( TSOPClassUID );
+ s.AddTag( TSOPInstanceUID );
+ s.AddTag( TSeriesInstanceUID );
+ s.AddTag( TFrameOfReferenceUID );
+ // reduce verbosity when looping over a set of files:
+ Trace::WarningOff();
+ if( !s.Scan( filenames ) )
+ {
+ gdcmDebugMacro( "Scanner failure for directory: " << dirname );
+ return false;
+ }
+ if( !collectuids( TSeriesInstanceUID, seriesuidhash ) ) return false;
+ // Frame of Reference are relative to Series UID
+ // http://dicom.nema.org/medical/Dicom/2015a/output/chtml/part03/sect_C.7.4.html
+ if( !collectuids( TFrameOfReferenceUID, framerefuidhash ) ) return false;
+
+ return true;
+}
+
+bool EmptyMaskGenerator::impl::derive( const char * filename, File & file )
+{
+ FileDerivation fd;
+ const char * referencedsopclassuid = s.GetValue (filename, TSOPClassUID);
+ const char * referencedsopinstanceuid = s.GetValue (filename, TSOPInstanceUID);
+ if( !fd.AddReference( referencedsopclassuid, referencedsopinstanceuid ) )
+ {
+ gdcmDebugMacro( "Impossible to AddRef: " << filename );
+ // This is not considered an error to not reference, eg. UID padded with 0
+ }
+
+ // CID 7202 Source Image Purposes of Reference
+ // DCM 121321 Mask image for image processing operation
+ fd.SetPurposeOfReferenceCodeSequenceCodeValue( 121321 );
+ // CID 7203 Image Derivation
+ // DCM 113047 Pixel by pixel mask
+ fd.SetDerivationCodeSequenceCodeValue( 113047 );
+ fd.SetDerivationDescription( "Empty Mask Derivation" );
+ // always append derivation history to any existing one:
+ fd.SetAppendDerivationHistory( true );
+ fd.SetFile( file );
+ if( !fd.Derive() )
+ {
+ gdcmDebugMacro( "Sorry could not derive using input info" );
+ return false;
+ }
+ return true;
+}
+
+bool EmptyMaskGenerator::impl::anonymizeattributes( const char * filename, File & file )
+{
+ Anonymizer ano;
+ ano.SetFile( file );
+ ano.RemoveGroupLength();
+ ano.RemovePrivateTags();
+ namespace kwd = Keywords;
+ ano.Remove( kwd::WindowCenter::GetTag() );
+ ano.Remove( kwd::WindowWidth::GetTag() );
+ if( !ano.Replace (TSOPInstanceUID, uid.Generate()) ) return false;
+ const char * oldseriesuid = s.GetValue (filename, TSeriesInstanceUID);
+ const char * oldframerefuid = s.GetValue (filename, TFrameOfReferenceUID);
+ if( oldseriesuid )
+ {
+ std::map< std::string, std::string >::const_iterator it1 = seriesuidhash.find( oldseriesuid );
+ if( !ano.Replace (TSeriesInstanceUID, it1->second.c_str() ) ) return false;
+ }
+ if( oldframerefuid )
+ {
+ std::map< std::string, std::string >::const_iterator it2 = framerefuidhash.find( oldframerefuid );
+ if( !ano.Replace (TFrameOfReferenceUID, it2->second.c_str() ) ) return false;
+ }
+ return true;
+}
+
+bool EmptyMaskGenerator::impl::populateattributes( const char * filename, File const & orifile, File & file )
+{
+ namespace kwd = Keywords;
+ DataSet & ds = file.GetDataSet();
+
+ // ContentDate
+ char date[22];
+ const size_t datelen = 8;
+ System::GetCurrentDateTime(date);
+ kwd::ContentDate contentdate;
+ // Do not copy the whole cstring:
+ contentdate.SetValue( DAComp( date, datelen ) );
+ ds.Insert( contentdate.GetAsDataElement() );
+ // ContentTime
+ const size_t timelen = 6 + 1 + 6; // time + milliseconds
+ kwd::ContentTime contenttime;
+ // Do not copy the whole cstring:
+ contenttime.SetValue( TMComp(date+datelen, timelen) );
+ ds.Insert( contenttime.GetAsDataElement() );
+
+ const DataSet & orids = orifile.GetDataSet();
+ kwd::SeriesInstanceUID seriesinstanceuid;
+ seriesinstanceuid.SetValue( uid.Generate() ); // In case original instance is missing Series Instance UID
+ kwd::SeriesNumber seriesnumber = { 1 };
+ const char * oldseriesuid = s.GetValue (filename, TSeriesInstanceUID);
+ if( oldseriesuid )
+ {
+ std::map< std::string, std::string >::iterator it =
+ seriesuidhash.find( oldseriesuid );
+ seriesinstanceuid.SetValue( it->second.c_str() );
+ std::map< std::string, std::string >::difference_type diff =
+ std::distance(seriesuidhash.begin(),it);
+ seriesnumber.SetValue( 1 + (int)diff ); // Start at one
+ }
+ ds.Insert( seriesinstanceuid.GetAsDataElement() );
+ ds.Insert( seriesnumber.GetAsDataElement() );
+ kwd::FrameOfReferenceUID frameref;
+ frameref.SetValue( uid.Generate() );
+ const char * oldframerefuid = s.GetValue (filename, TFrameOfReferenceUID);
+ if( oldframerefuid )
+ {
+ std::map< std::string, std::string >::const_iterator it = framerefuidhash.find( oldframerefuid );
+ frameref.SetValue( it->second.c_str() );
+ }
+ ds.Insert( frameref.GetAsDataElement() );
+ kwd::InstanceNumber instancenum = { 1 };
+ if( orids.FindDataElement( instancenum.GetTag() ) )
+ {
+ instancenum.SetFromDataSet( orids );
+ }
+ else
+ {
+ static unsigned int counter = 0; // unsigned will wrap properly
+ instancenum.SetValue( counter++ );
+ }
+ ds.Insert( instancenum.GetAsDataElement() );
+ kwd::StudyInstanceUID studyinstanceuid;
+ studyinstanceuid.SetFromDataSet( orids );
+ ds.Insert( studyinstanceuid.GetAsDataElement() );
+ kwd::StudyID studyid = { "ST1" };
+ studyid.SetFromDataSet( orids );
+ ds.Insert( studyid.GetAsDataElement() );
+ kwd::PatientID patientid;
+ patientid.SetFromDataSet( orids );
+ ds.Insert( patientid.GetAsDataElement() );
+ kwd::PositionReferenceIndicator pri;
+ ds.Insert( pri.GetAsDataElement() );
+ kwd::BodyPartExamined bodypartex;
+ bodypartex.SetFromDataSet( orids );
+ ds.Insert( bodypartex.GetAsDataElement() );
+ // Sync with Body Part Examined:
+ kwd::Laterality lat;
+ if( orids.FindDataElement( lat.GetTag() ) )
+ {
+ lat.SetFromDataSet( orids );
+ ds.Insert( lat.GetAsDataElement() );
+ }
+ kwd::PatientOrientation pator;
+ pator.SetFromDataSet( orids );
+ ds.Insert( pator.GetAsDataElement() );
+ kwd::BurnedInAnnotation bia = { "NO" };
+ ds.Insert( bia.GetAsDataElement() );
+ kwd::ConversionType convtype = { "SYN" };
+ ds.Insert( convtype.GetAsDataElement() );
+ kwd::PresentationLUTShape plutshape = { "IDENTITY" }; // MONOCHROME2
+ ds.Insert( plutshape.GetAsDataElement() );
+ kwd::SOPClassUID sopclassuid;
+ // gdcm will pick the Word in case Byte class is not compatible:
+ MediaStorage ms = MediaStorage::MultiframeGrayscaleByteSecondaryCaptureImageStorage;
+ sopclassuid.SetValue( ms.GetString() );
+ ds.Insert( sopclassuid.GetAsDataElement() );
+ return true;
+}
+
+bool EmptyMaskGenerator::impl::setts( File & file )
+{
+ FileMetaInformation & fmi = file.GetHeader();
+ const TransferSyntax & orits = fmi.GetDataSetTransferSyntax();
+ TransferSyntax::TSType newts = TransferSyntax::ImplicitVRLittleEndian;
+ if( orits.IsExplicit() )
+ {
+ newts = TransferSyntax::ExplicitVRLittleEndian;
+ }
+ fmi.Clear();
+ fmi.SetDataSetTransferSyntax( newts );
+ return true;
+}
+
+bool EmptyMaskGenerator::impl::run(const char * filename, const char * outfile)
+{
+ if( !s.IsKey( filename ) )
+ {
+ gdcmErrorMacro( "Not DICOM file: " << filename );
+ return false;
+ }
+
+ ImageRegionReader irr;
+ irr.SetFileName( filename );
+ if( !irr.ReadInformation() )
+ {
+ gdcmErrorMacro( "Impossible to ReadInformation (not an image?): " << filename );
+ return false;
+ }
+ size_t buflen = irr.ComputeBufferLength();
+ Image & img = irr.GetImage();
+ if( img.GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME1
+ && img.GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME2 )
+ {
+ gdcmErrorMacro( "Cannot process PhotometricInterpretation from: " << filename );
+ return false;
+ }
+
+ if( mode == UseOriginalSOPClassUID )
+ {
+ File & file = irr.GetFile();
+ // derive operation needs to operate on original attributes (before anonymization):
+ if( !derive( filename, file ) ) return false;
+ // copy original attributes:
+ if( !anonymizeattributes( filename, file ) ) return false;
+ if( !setmask( file ) ) return false;
+ if( !setts( file ) ) return false;
+
+ Writer w;
+ w.SetFile( file );
+ w.SetFileName( outfile );
+ if( !w.Write() )
+ {
+ return false;
+ }
+ }
+ else if ( mode == UseGrayscaleSecondaryImageStorage )
+ {
+ ImageWriter w;
+ File & file = w.GetFile();
+ if( !derive( filename, file ) ) return false;
+ // create attributes:
+ if( !populateattributes( filename, irr.GetFile(), file ) ) return false;
+ if( !setmask( file ) ) return false;
+ if( !setts( file ) ) return false;
+
+ PixelFormat & pf = img.GetPixelFormat();
+ pf.SetPixelRepresentation(0); // always overwrite to unsigned
+ img.SetSlope(1);
+ img.SetIntercept(0);
+ w.SetImage( img );
+ w.SetFileName( outfile );
+ // sentinel, SC is never acceptable:
+ if( w.ComputeTargetMediaStorage() == MediaStorage::SecondaryCaptureImageStorage )
+ {
+ gdcmErrorMacro( "Failure to compute MediaStorage: " << filename );
+ return false;
+ }
+ if( !w.Write() )
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // possibly dead code, but make sure to report an error for invalid state:
+ return false;
+ }
+
+ // now create the empty pixel data element, a chunk at a time:
+ FileStreamer fs;
+ fs.SetTemplateFileName(outfile);
+ fs.SetOutputFileName(outfile);
+ Tag pixeldata (0x7fe0, 0x0010);
+ fs.CheckDataElement( pixeldata ); // double check generated output
+ if( !fs.StartDataElement( pixeldata ) )
+ {
+ gdcmErrorMacro( "StartDataElement" );
+ return false;
+ }
+ {
+ const unsigned int chunk = 4096u;
+ char bytes[chunk] = {};
+ const unsigned int nchunks = (unsigned int)( buflen / chunk);
+ const unsigned int remain = buflen % chunk;
+ for( unsigned int i = 0; i < nchunks; ++i )
+ {
+ // Read the source file into a byte array.
+ fs.AppendToDataElement( pixeldata, bytes, chunk );
+ }
+ fs.AppendToDataElement( pixeldata, bytes, remain );
+ }
+ if( !fs.StopDataElement( pixeldata ) )
+ {
+ // Most likely an issue with Pixel Data Length computation:
+ gdcmErrorMacro( "StopDataElement" );
+ return false;
+ }
+
+ return true;
+}
+
+EmptyMaskGenerator::EmptyMaskGenerator():pimpl(new impl)
+{
+}
+
+EmptyMaskGenerator::~EmptyMaskGenerator()
+{
+ delete pimpl;
+}
+
+void EmptyMaskGenerator::SetSOPClassUIDMode( SOPClassUIDMode mode )
+{
+ pimpl->mode = mode;
+}
+
+void EmptyMaskGenerator::SetInputDirectory(const char * dirname)
+{
+ if( dirname )
+ pimpl->inputdir = dirname;
+}
+
+void EmptyMaskGenerator::SetOutputDirectory(const char * dirname)
+{
+ if( dirname )
+ pimpl->outputdir = dirname;
+}
+
+
+bool EmptyMaskGenerator::Execute()
+{
+ const char * dirname = pimpl->inputdir.c_str();
+ const char * outdir = pimpl->outputdir.c_str();
+ if( !pimpl->setup(dirname, outdir) )
+ {
+ return false;
+ }
+ bool success = true;
+ Directory::FilenamesType const & filenames = pimpl->s.GetFilenames();
+ for( Directory::FilenamesType::const_iterator it = filenames.begin(); it != filenames.end(); ++it )
+ {
+ const char * filename = it->c_str();
+ Filename fn( filename );
+ std::string outfile = outdir;
+ outfile += '/';
+ outfile += fn.GetName();
+ if( !pimpl->run( filename, outfile.c_str() ) )
+ {
+ gdcmErrorMacro( "Failure to EmptyMask" );
+ // Since we may have failed in the middle of writing of the file, remove it:
+ if( System::FileExists(outfile.c_str()) && !System::RemoveFile(outfile.c_str()) )
+ {
+ gdcmErrorMacro( "Failure to RemoveFile: " << outfile );
+ // may want to call exit() here, since we failed to remove a file we created in this process:
+ return false;
+ }
+ // declare failure to process a file, but continue main loop:
+ success = false;
+ }
+ }
+ return success;
+}
+
+} // end namespace gdcm
diff --git a/Source/MediaStorageAndFileFormat/gdcmEmptyMaskGenerator.h b/Source/MediaStorageAndFileFormat/gdcmEmptyMaskGenerator.h
new file mode 100644
index 0000000..a9f9459
--- /dev/null
+++ b/Source/MediaStorageAndFileFormat/gdcmEmptyMaskGenerator.h
@@ -0,0 +1,80 @@
+/*=========================================================================
+
+ Program: GDCM (Grassroots DICOM). A DICOM library
+
+ Copyright (c) 2006-2011 Mathieu Malaterre
+ All rights reserved.
+ See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notice for more information.
+
+=========================================================================*/
+#ifndef GDCMEMPTYMASKGENERATOR_H
+#define GDCMEMPTYMASKGENERATOR_H
+
+#include "gdcmSubject.h"
+
+namespace gdcm {
+/**
+ * \brief EmptyMaskGenerator
+ * Main class to generate a Empty Mask Series from an input Series. This class
+ * takes an input folder and generates a series of DICOM files in the specified
+ * output directory.
+ * This class handles multiples DICOM Series within the same input directory.
+ *
+ * The class allow two mode of operations:
+ * - UseOriginalSOPClassUID
+ * - UseGrayscaleSecondaryImageStorage
+ *
+ * UseOriginalSOPClassUID is the mode where original attributes are copied from
+ * the original DICOM instance.
+ *
+ * UseGrayscaleSecondaryImageStorage is the mode where attributes are generated
+ * so as to create a MultiframeGrayscaleByteSecondaryCaptureImageStorage
+ * (MultiframeGrayscaleWordSecondaryCaptureImageStorage) instance.
+ *
+ * In both mode:
+ * - the Study references (StudyInstanceUID and StudyID) are preserved.
+ * - the PatientID reference is preserved.
+ * - the Image Type attribute will be setup so that the fourth
+ * element is set to 'MASK'.
+ * - a new Series Instance UID is generated. It is thus required to run the process
+ * over all files using the same input Series Instance UID so that a proper mapping
+ * from the old Series UID is done to the new one.
+ * Since a new Series Instance UID is generated, there is no sense to
+ * preserve the original Frame of Reference UID, altough it would have made
+ * sense here.
+ */
+class GDCM_EXPORT EmptyMaskGenerator
+{
+public:
+ EmptyMaskGenerator();
+ ~EmptyMaskGenerator();
+
+ enum SOPClassUIDMode {
+ UseOriginalSOPClassUID = 0, // default
+ UseGrayscaleSecondaryImageStorage
+ };
+
+ /// Select generation of SOP Class UID method:
+ /// Default is UseOriginalSOPClassUID
+ void SetSOPClassUIDMode( SOPClassUIDMode mode );
+
+ /// Specify input directory
+ void SetInputDirectory( const char * dirname );
+
+ /// Specify output directory
+ void SetOutputDirectory( const char * dirname );
+
+ /// Main loop
+ bool Execute();
+
+private:
+ struct impl;
+ // PIMPL idiom
+ impl* pimpl;
+};
+} // end namespace gdcm
+#endif //GDCMEMPTYMASKGENERATOR_H
diff --git a/Source/MediaStorageAndFileFormat/gdcmPixmapWriter.cxx b/Source/MediaStorageAndFileFormat/gdcmPixmapWriter.cxx
index 3773f33..57f6026 100644
--- a/Source/MediaStorageAndFileFormat/gdcmPixmapWriter.cxx
+++ b/Source/MediaStorageAndFileFormat/gdcmPixmapWriter.cxx
@@ -493,7 +493,7 @@ bool PixmapWriter::PrepareWrite( MediaStorage const & ref_ms )
// Pixel Data
DataElement depixdata( Tag(0x7fe0,0x0010) );
- gdcm::DataElement & pde = PixelData->GetDataElement();
+ DataElement & pde = PixelData->GetDataElement();
const ByteValue *bvpixdata = NULL;
// Sometime advanced user may use a gdcm::ImageRegionReader to feed an empty gdcm::Image
if( !pde.IsEmpty() )
diff --git a/Source/MediaStorageAndFileFormat/gdcmPrinter.cxx b/Source/MediaStorageAndFileFormat/gdcmPrinter.cxx
index 6cd4108..0970115 100644
--- a/Source/MediaStorageAndFileFormat/gdcmPrinter.cxx
+++ b/Source/MediaStorageAndFileFormat/gdcmPrinter.cxx
@@ -756,7 +756,7 @@ VR Printer::PrintDataElement(std::ostringstream &os, const Dicts &dicts, const D
assert( refvr & VR::VRASCII );
if( bv )
{
- unsigned int count = VM::GetNumberOfElementsFromArray(bv->GetPointer(), bv->GetLength());
+ size_t count = VM::GetNumberOfElementsFromArray(bv->GetPointer(), bv->GetLength());
guessvm = VM::GetVMTypeFromLength(count, 1); // hackish...
}
}
diff --git a/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.cxx b/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.cxx
index 1267ac2..f1c07da 100644
--- a/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.cxx
+++ b/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.cxx
@@ -15,6 +15,8 @@
#include "gdcmCSAHeader.h"
#include "gdcmAttribute.h"
#include "gdcmImageHelper.h"
+#include "gdcmDirectionCosines.h"
+#include "gdcmAnonymizer.h"
#include <math.h>
@@ -45,6 +47,28 @@ static bool reorganize_mosaic(const unsigned short *input, const unsigned int *i
}
return true;
}
+
+#ifdef SNVINVERT
+static bool reorganize_mosaic_invert(const unsigned short *input, const unsigned int *inputdims,
+ unsigned int square, const unsigned int *outputdims, unsigned short *output )
+{
+ for(unsigned int x = 0; x < outputdims[0]; ++x)
+ {
+ for(unsigned int y = 0; y < outputdims[1]; ++y)
+ {
+ for(unsigned int z = 0; z < outputdims[2]; ++z)
+ {
+ const size_t outputidx = x + y*outputdims[0] + (outputdims[2]-1-z)*outputdims[0]*outputdims[1];
+ const size_t inputidx = (x + (z%square)*outputdims[0]) +
+ (y + (z/square)*outputdims[1])*inputdims[0];
+ output[ outputidx ] = input[ inputidx ];
+ }
+ }
+ }
+ return true;
+}
+#endif
+
}
void SplitMosaicFilter::SetImage(const Image& image)
@@ -61,7 +85,6 @@ bool SplitMosaicFilter::ComputeMOSAICDimensions( unsigned int dims[3] )
int numberOfImagesInMosaic = 0;
if( csa.LoadFromDataElement( ds.GetDataElement( t1 ) ) )
{
- // SliceThickness ??
if( csa.FindCSAElementByName( "NumberOfImagesInMosaic" ) )
{
const CSAElement &csael4 = csa.GetCSAElementByName( "NumberOfImagesInMosaic" );
@@ -79,15 +102,18 @@ bool SplitMosaicFilter::ComputeMOSAICDimensions( unsigned int dims[3] )
// oh well, let try harder:
// (0019,100a) US 72 # 2,1 NumberOfImagesInMosaic
PrivateTag t2 (0x0019,0x0a, "SIEMENS MR HEADER");
- const DataElement &de = ds.GetDataElement( t2 );
- const ByteValue * bv = de.GetByteValue();
- if( bv )
+ if( ds.FindDataElement( t2 ) )
{
- Element<VR::US, VM::VM1> el1 = {{0}};
- std::istringstream is;
- is.str( std::string( bv->GetPointer(), bv->GetLength() ) );
- el1.Read( is );
- numberOfImagesInMosaic = el1.GetValue();
+ const DataElement &de = ds.GetDataElement( t2 );
+ const ByteValue * bv = de.GetByteValue();
+ if( bv )
+ {
+ Element<VR::US, VM::VM1> el1 = {{0}};
+ std::istringstream is;
+ is.str( std::string( bv->GetPointer(), bv->GetLength() ) );
+ el1.Read( is );
+ numberOfImagesInMosaic = el1.GetValue();
+ }
}
}
if( !numberOfImagesInMosaic )
@@ -108,6 +134,110 @@ bool SplitMosaicFilter::ComputeMOSAICDimensions( unsigned int dims[3] )
return true;
}
+bool SplitMosaicFilter::ComputeMOSAICSliceNormal( double slicenormalvector[3], bool & inverted )
+{
+ CSAHeader csa;
+ DataSet& ds = GetFile().GetDataSet();
+
+ double normal[3];
+ bool snvfound = false;
+ const PrivateTag &t1 = csa.GetCSAImageHeaderInfoTag();
+ static const char snvstr[] = "SliceNormalVector";
+ if( csa.LoadFromDataElement( ds.GetDataElement( t1 ) ) )
+ {
+ if( csa.FindCSAElementByName( snvstr ) )
+ {
+ const CSAElement &snv_csa = csa.GetCSAElementByName( snvstr );
+ if( !snv_csa.IsEmpty() )
+ {
+ const ByteValue * bv = snv_csa.GetByteValue();
+ const std::string str(bv->GetPointer(), bv->GetLength());
+ std::istringstream is;
+ is.str( str );
+ char sep;
+ double *snv = normal;
+ if( is >> snv[0] >> sep >> snv[1] >> sep >> snv[2] )
+ {
+ snvfound = true;
+ }
+ }
+ }
+ }
+ if( snvfound )
+ {
+ Attribute<0x20,0x37> iop;
+ iop.SetFromDataSet( ds );
+ DirectionCosines dc( iop.GetValues() );
+ double z[3];
+ dc.Cross (z);
+ const double snv_dot = dc.Dot( normal, z );
+ if( (1. - snv_dot) < 1e-6 )
+ {
+ gdcmDebugMacro("Same direction");
+ inverted = false;
+ }
+ else if( (-1. - snv_dot) < 1e-6 )
+ {
+ gdcmWarningMacro("SliceNormalVector is opposite direction");
+ inverted = true;
+ }
+ else
+ {
+ gdcmErrorMacro( "Unexpected normal for SliceNormalVector, dot is: " << snv_dot );
+ return false;
+ }
+ }
+
+ for( int i = 0; i < 3; ++i)
+ slicenormalvector[i] = normal[i];
+
+ return snvfound;
+}
+
+bool SplitMosaicFilter::ComputeMOSAICSlicePosition( double pos[3], bool )
+{
+ CSAHeader csa;
+ DataSet& ds = GetFile().GetDataSet();
+
+ MrProtocol mrprot;
+ if( !csa.GetMrProtocol(ds, mrprot) ) return false;
+
+ MrProtocol::SliceArray sa;
+ bool b = mrprot.GetSliceArray(sa);
+ if( !b ) return false;
+
+ size_t size = sa.Slices.size();
+ if( !size ) return false;
+#if 0
+ {
+ double z[3];
+ for( int i = 0; i < size; ++i )
+ {
+ MrProtocol::Slice & slice = sa.Slices[i];
+ MrProtocol::Vector3 & p = slice.Position;
+ z[0] = p.dSag;
+ z[1] = p.dCor;
+ z[2] = p.dTra;
+ const double snv_dot = DirectionCosines::Dot( slicenormalvector, z );
+ if( (1. - snv_dot) < 1e-6 )
+ {
+ gdcmErrorMacro("Invalid direction found");
+ return false;
+ }
+ }
+ }
+#endif
+
+ size_t index = 0;
+ MrProtocol::Slice & slice = sa.Slices[index];
+ MrProtocol::Vector3 & p = slice.Position;
+ pos[0] = p.dSag;
+ pos[1] = p.dCor;
+ pos[2] = p.dTra;
+
+ return true;
+}
+
bool SplitMosaicFilter::Split()
{
bool success = true;
@@ -118,12 +248,23 @@ bool SplitMosaicFilter::Split()
{
return false;
}
- unsigned int div = (unsigned int )ceil(sqrt( (double)dims[2]) );
+ const unsigned int div = (unsigned int )ceil(sqrt( (double)dims[2]) );
+ bool inverted;
+ double normal[3];
+ if( !ComputeMOSAICSliceNormal( normal, inverted ) )
+ {
+ return false;
+ }
+ double origin[3];
+ if( !ComputeMOSAICSlicePosition( origin, inverted ) )
+ {
+ return false;
+ }
const Image &inputimage = GetImage();
if( inputimage.GetPixelFormat() != PixelFormat::UINT16 )
{
- gdcmDebugMacro( "Expecting UINT16 PixelFormat" );
+ gdcmErrorMacro( "Expecting UINT16 PixelFormat" );
return false;
}
unsigned long l = inputimage.GetBufferLength();
@@ -135,29 +276,44 @@ bool SplitMosaicFilter::Split()
std::vector<char> outbuf;
outbuf.resize(l);
- bool b = details::reorganize_mosaic(
- (unsigned short*)&buf[0], inputimage.GetDimensions(), div, dims,
- (unsigned short*)&outbuf[0] );
+ bool b;
+#ifdef SNVINVERT
+ if( inverted )
+ {
+ b = details::reorganize_mosaic_invert(
+ (unsigned short*)&buf[0], inputimage.GetDimensions(), div, dims,
+ (unsigned short*)&outbuf[0] );
+ }
+ else
+#endif
+ {
+ b = details::reorganize_mosaic(
+ (unsigned short*)&buf[0], inputimage.GetDimensions(), div, dims,
+ (unsigned short*)&outbuf[0] );
+ }
if( !b ) return false;
VL::Type outbufSize = (VL::Type)outbuf.size();
pixeldata.SetByteValue( &outbuf[0], outbufSize );
Image &image = GetImage();
- const gdcm::TransferSyntax &ts = image.GetTransferSyntax();
+ const TransferSyntax &ts = image.GetTransferSyntax();
if( ts.IsExplicit() )
{
- image.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian );
+ image.SetTransferSyntax( TransferSyntax::ExplicitVRLittleEndian );
}
else
{
- image.SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian );
+ image.SetTransferSyntax( TransferSyntax::ImplicitVRLittleEndian );
}
image.SetNumberOfDimensions( 3 );
image.SetDimension(0, dims[0] );
image.SetDimension(1, dims[1] );
image.SetDimension(2, dims[2] );
+ // Fix origin (direction is ok since we reorganize the tiles):
+ image.SetOrigin( origin );
+
PhotometricInterpretation pi;
pi = PhotometricInterpretation::MONOCHROME2;
diff --git a/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.h b/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.h
index 717a4e8..588d924 100644
--- a/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.h
+++ b/Source/MediaStorageAndFileFormat/gdcmSplitMosaicFilter.h
@@ -47,6 +47,12 @@ public:
/// stored in the MOSAIC header.
bool ComputeMOSAICDimensions(unsigned int dims[3]);
+ /// Extract the value for SliceNormalVector (CSA header)
+ bool ComputeMOSAICSliceNormal( double dims[3], bool & inverted );
+
+ /// Extract the value for ImagePositionPatient (requires inverted flag)
+ bool ComputeMOSAICSlicePosition( double pos[3], bool inverted );
+
void SetImage(const Image& image);
const Image &GetImage() const { return *I; }
Image &GetImage() { return *I; }
diff --git a/Testing/Source/MediaStorageAndFileFormat/Cxx/CMakeLists.txt b/Testing/Source/MediaStorageAndFileFormat/Cxx/CMakeLists.txt
index d22a082..ff59d92 100644
--- a/Testing/Source/MediaStorageAndFileFormat/Cxx/CMakeLists.txt
+++ b/Testing/Source/MediaStorageAndFileFormat/Cxx/CMakeLists.txt
@@ -103,6 +103,7 @@ set(MSFF_TEST_SRCS
if(GDCM_DATA_ROOT)
set(MSFF_TEST_SRCS
${MSFF_TEST_SRCS}
+ TestSplitMosaicFilter3
TestStrictScanner1
TestStrictScanner2
TestScanner1
@@ -139,6 +140,7 @@ if(GDCM_DATA_EXTRA_ROOT)
set(MSFF_TEST_SRCS
${MSFF_TEST_SRCS}
TestSplitMosaicFilter
+ TestSplitMosaicFilter2
TestOverlay2
TestImageRegionReader4
)
diff --git a/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter.cxx b/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter.cxx
index bb63114..ddf3855 100644
--- a/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter.cxx
+++ b/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter.cxx
@@ -28,7 +28,7 @@ static bool reorganize_mosaic_invert(unsigned short *input,
{
size_t outputidx = x + y*outputdims[0] + z*outputdims[0]*outputdims[1];
size_t inputidx = (x + (z%square)*outputdims[0]) +
- (y + (z/square)*outputdims[0])*inputdims[0];
+ (y + (z/square)*outputdims[1])*inputdims[0];
input[ inputidx ] = output[ outputidx ];
}
}
@@ -89,6 +89,19 @@ int TestSplitMosaicFilter(int argc, char *argv[])
std::cerr << "Could not split << " << filename << std::endl;
return 1;
}
+ unsigned int modims[3];
+ b = filter.ComputeMOSAICDimensions( modims );
+ if( !b )
+ {
+ std::cerr << "Could not ComputeMOSAICDimensions << " << filename << std::endl;
+ return 1;
+ }
+ const unsigned int ref[3] = { 64u, 64u, 31u };
+ if( modims[0] != ref[0] || modims[1] != ref[1] || modims[2] != ref[2] )
+ {
+ std::cerr << "Invalid ComputeMOSAICDimensions << " << filename << std::endl;
+ return 1;
+ }
// const gdcm::Image &image = filter.GetImage();
diff --git a/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter2.cxx b/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter2.cxx
new file mode 100644
index 0000000..0a0136c
--- /dev/null
+++ b/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter2.cxx
@@ -0,0 +1,220 @@
+/*=========================================================================
+
+ Program: GDCM (Grassroots DICOM). A DICOM library
+
+ Copyright (c) 2006-2011 Mathieu Malaterre
+ All rights reserved.
+ See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notice for more information.
+
+=========================================================================*/
+#include "gdcmSplitMosaicFilter.h"
+#include "gdcmTesting.h"
+#include "gdcmSystem.h"
+#include "gdcmReader.h"
+#include "gdcmAnonymizer.h"
+#include "gdcmPrivateTag.h"
+#include "gdcmCSAHeader.h"
+#include "gdcmElement.h"
+#include "gdcmDirectionCosines.h"
+
+int TestSplitMosaicFilter2(int argc, char *argv[])
+{
+ std::string filename;
+ if( argc == 2 )
+ {
+ filename = argv[1];
+ }
+ else
+ {
+ const char *extradataroot = gdcm::Testing::GetDataExtraRoot();
+ if( !extradataroot )
+ {
+ return 1;
+ }
+ if( !gdcm::System::FileIsDirectory(extradataroot) )
+ {
+ std::cerr << "No such directory: " << extradataroot << std::endl;
+ return 1;
+ }
+
+ filename = extradataroot;
+ filename += "/gdcmSampleData/images_of_interest/MR-sonata-3D-as-Tile.dcm";
+ }
+ gdcm::SplitMosaicFilter s;
+ if( !gdcm::System::FileExists(filename.c_str()) )
+ {
+ return 1;
+ }
+
+ gdcm::Reader reader;
+ reader.SetFileName( filename.c_str() );
+ if( !reader.Read() )
+ {
+ std::cerr << "could not read: " << filename << std::endl;
+ return 1;
+ }
+
+ gdcm::SplitMosaicFilter filter;
+ filter.SetFile( reader.GetFile() );
+ bool inverted;
+ double slicenormal[3];
+ bool b = filter.ComputeMOSAICSliceNormal( slicenormal, inverted );
+ if( !b )
+ {
+ std::cerr << "Could not ComputeMOSAICSliceNormal: " << filename << std::endl;
+ return 1;
+ }
+
+ // SliceNormalVector is slightly less precise that sNormal:
+ //const double refnormal[3] = {-0.08193696,0.08808136,0.99273763};
+ // Value as read from sNormal (sSlice)
+ const double refnor[3] = { -0.08193693363, 0.08808135446, 0.992737636 };
+ const double eps = 1e-6;
+ gdcm::DirectionCosines dc;
+ const double dot = dc.Dot( slicenormal, refnor );
+ if( std::fabs( 1.0 - dot ) > eps )
+ {
+ std::cerr << "Invalid ComputeMOSAICSliceNormal: " << filename << std::endl;
+ return 1;
+ }
+
+ double slicepos[3];
+ b = filter.ComputeMOSAICSlicePosition( slicepos, inverted );
+ if( !b )
+ {
+ std::cerr << "Could not ComputeMOSAICSlicePosition: " << filename << std::endl;
+ return 1;
+ }
+
+ const double refpos[3] = { 2.24891108,-52.65585315,-26.94105767 };
+ for( int i = 0; i < 3; ++i )
+ {
+ if( std::fabs( refpos[i] - slicepos[i] ) > eps )
+ {
+ std::cerr << "Invalid ComputeMOSAICSlicePosition: " << filename << std::endl;
+ return 1;
+ }
+ }
+
+ gdcm::CSAHeader csa;
+ gdcm::DataSet & ds = reader.GetFile().GetDataSet();
+ gdcm::MrProtocol mrprot;
+ if( !csa.GetMrProtocol(ds, mrprot))
+ {
+ std::cerr << "No MrProtocol" << filename << std::endl;
+ return 1;
+ }
+
+ gdcm::MrProtocol::SliceArray sa;
+ b = mrprot.GetSliceArray(sa);
+ if( !b || sa.Slices.size() != 31 )
+ {
+ return 1;
+ }
+
+ gdcm::MrProtocol::Slice & slice0 = sa.Slices[0];
+ gdcm::MrProtocol::Vector3 & p0 = slice0.Position;
+ double pos0[3];
+ pos0[0] = p0.dSag;
+ pos0[1] = p0.dCor;
+ pos0[2] = p0.dTra;
+ for( int i = 0; i < 3; ++i )
+ {
+ if( std::fabs( refpos[i] - pos0[i] ) > eps )
+ {
+ std::cerr << "Invalid slice0: " << filename << std::endl;
+ return 1;
+ }
+ }
+
+ gdcm::MrProtocol::Slice & slice1 = sa.Slices[1];
+ gdcm::MrProtocol::Vector3 & p1 = slice1.Position;
+ double pos1[3];
+ pos1[0] = p1.dSag;
+ pos1[1] = p1.dCor;
+ pos1[2] = p1.dTra;
+ double altnor[3];
+ for( int i = 0; i < 3; ++i )
+ {
+ altnor[i] = pos1[i] - pos0[i];
+ }
+ dc.Normalize( altnor );
+ const double dot2 = dc.Dot( altnor, refnor );
+ if( std::fabs( 1.0 - dot2 ) > eps )
+ {
+ std::cerr << "Incompatible alt " << filename << std::endl;
+ return 1;
+ }
+
+ for( int k = 0; k < 31; ++k )
+ {
+ gdcm::MrProtocol::Slice & slice = sa.Slices[k];
+ gdcm::MrProtocol::Vector3 & nor = slice.Normal;
+ double normal[3];
+ normal[0] = nor.dSag;
+ normal[1] = nor.dCor;
+ normal[2] = nor.dTra;
+ for( int i = 0; i < 3; ++i )
+ {
+ if( std::fabs( refnor[i] - normal[i] ) > eps )
+ {
+ std::cerr << "Invalid normal: " << filename << std::endl;
+ return 1;
+ }
+ }
+ }
+
+
+ gdcm::Anonymizer ano;
+ ano.SetFile( reader.GetFile() );
+ const gdcm::PrivateTag &t1 = csa.GetCSAImageHeaderInfoTag();
+ ano.Remove( t1 );
+
+ unsigned int modims[3];
+ b = filter.ComputeMOSAICDimensions( modims );
+ if( b ) return 1;
+
+ // alternate code path:
+ gdcm::PrivateTag t2 (0x0019,0x0a, "SIEMENS MR HEADER");
+ if( ds.FindDataElement( t2 ) )
+ {
+ return 1;
+ }
+ else
+ {
+ // Create a fake one:
+ std::string creator = ds.GetPrivateCreator( t2 );
+ if( !creator.empty() ) return 1;
+ gdcm::Tag t3 (0x0019,0x10);
+ ano.Replace( t3, t2.GetOwner() );
+ gdcm::Element<gdcm::VR::US, gdcm::VM::VM1> elem;
+ elem.SetValue( 31 );
+ gdcm::DataElement de = elem.GetAsDataElement();
+ de.SetTag( t2 );
+ const uint16_t el = de.GetTag().GetElement();
+ de.GetTag().SetElement( 0x1000 + el );
+ if( de.GetVR() != gdcm::VR::US ) return 1;
+ ds.Insert( de );
+ creator = ds.GetPrivateCreator( de.GetTag() );
+ if( creator.empty() ) return 1;
+ }
+
+ b = filter.ComputeMOSAICDimensions( modims );
+ if( !b )
+ {
+ std::cerr << "Could not ComputeMOSAICDimensions " << filename << std::endl;
+ return 1;
+ }
+ const unsigned int ref[3] = { 64u, 64u, 31u };
+ if( modims[0] != ref[0] || modims[1] != ref[1] || modims[2] != ref[2] )
+ {
+ std::cerr << "Invalid ComputeMOSAICDimensions " << filename << std::endl;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter3.cxx b/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter3.cxx
new file mode 100644
index 0000000..58260ae
--- /dev/null
+++ b/Testing/Source/MediaStorageAndFileFormat/Cxx/TestSplitMosaicFilter3.cxx
@@ -0,0 +1,173 @@
+/*=========================================================================
+
+ Program: GDCM (Grassroots DICOM). A DICOM library
+
+ Copyright (c) 2006-2011 Mathieu Malaterre
+ All rights reserved.
+ See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notice for more information.
+
+=========================================================================*/
+#include "gdcmSplitMosaicFilter.h"
+#include "gdcmTesting.h"
+#include "gdcmSystem.h"
+#include "gdcmReader.h"
+#include "gdcmAnonymizer.h"
+#include "gdcmPrivateTag.h"
+#include "gdcmCSAHeader.h"
+#include "gdcmElement.h"
+#include "gdcmDirectionCosines.h"
+
+int TestSplitMosaicFilter3(int , char *[])
+{
+ const char *directory = gdcm::Testing::GetDataRoot();
+ std::string filename = std::string(directory) + "/SIEMENS_MOSAIC_12BitsStored-16BitsJPEG.dcm";
+ gdcm::SplitMosaicFilter s;
+ if( !gdcm::System::FileExists(filename.c_str()) )
+ {
+ return 1;
+ }
+
+ gdcm::Reader reader;
+ reader.SetFileName( filename.c_str() );
+ if( !reader.Read() )
+ {
+ std::cerr << "could not read: " << filename << std::endl;
+ return 1;
+ }
+
+ gdcm::SplitMosaicFilter filter;
+ filter.SetFile( reader.GetFile() );
+ bool inverted;
+ double slicenormal[3];
+ bool b = filter.ComputeMOSAICSliceNormal( slicenormal, inverted );
+ if( !b )
+ {
+ std::cerr << "Could not ComputeMOSAICSliceNormal: " << filename << std::endl;
+ return 1;
+ }
+
+ const double refnor[3] = { -0.03737130908,-0.314588168,0.9484923141 };
+ const double eps = 1e-6;
+ gdcm::DirectionCosines dc;
+ const double dot = dc.Dot( slicenormal, refnor );
+ if( std::fabs( 1.0 - dot ) > eps )
+ {
+ std::cerr << "Invalid ComputeMOSAICSliceNormal: " << filename << std::endl;
+ return 1;
+ }
+
+ double slicepos[3];
+ b = filter.ComputeMOSAICSlicePosition( slicepos, inverted );
+ if( !b )
+ {
+ std::cerr << "Could not ComputeMOSAICSlicePosition: " << filename << std::endl;
+ return 1;
+ }
+
+ const double refpos[3] = { -10.48860023,-7.82515782,-28.87523447 };
+
+ for( int i = 0; i < 3; ++i )
+ {
+ if( std::fabs( refpos[i] - slicepos[i] ) > eps )
+ {
+ std::cerr << "Invalid ComputeMOSAICSlicePosition: " << filename << std::endl;
+ return 1;
+ }
+ }
+
+ gdcm::CSAHeader csa;
+ gdcm::DataSet & ds = reader.GetFile().GetDataSet();
+ gdcm::MrProtocol mrprot;
+ if( !csa.GetMrProtocol(ds, mrprot))
+ {
+ std::cerr << "No MrProtocol" << filename << std::endl;
+ return 1;
+ }
+
+ gdcm::MrProtocol::SliceArray sa;
+ b = mrprot.GetSliceArray(sa);
+ if( !b || sa.Slices.size() != 18 )
+ {
+ std::cerr << "Size" << filename << std::endl;
+ return 1;
+ }
+
+ gdcm::MrProtocol::Slice & slice0 = sa.Slices[0];
+ gdcm::MrProtocol::Vector3 & p0 = slice0.Position;
+ double pos0[3];
+ pos0[0] = p0.dSag;
+ pos0[1] = p0.dCor;
+ pos0[2] = p0.dTra;
+ for( int i = 0; i < 3; ++i )
+ {
+ if( std::fabs( refpos[i] - pos0[i] ) > eps )
+ {
+ std::cerr << "Invalid slice0: " << filename << std::endl;
+ return 1;
+ }
+ }
+
+ gdcm::MrProtocol::Slice & slice1 = sa.Slices[1];
+ gdcm::MrProtocol::Vector3 & p1 = slice1.Position;
+ double pos1[3];
+ pos1[0] = p1.dSag;
+ pos1[1] = p1.dCor;
+ pos1[2] = p1.dTra;
+ double altnor[3];
+ for( int i = 0; i < 3; ++i )
+ {
+ altnor[i] = pos1[i] - pos0[i];
+ }
+ dc.Normalize( altnor );
+ const double dot2 = dc.Dot( altnor, refnor );
+ if( std::fabs( 1.0 - dot2 ) > eps )
+ {
+ std::cerr << "Incompatible alt " << filename << std::endl;
+ return 1;
+ }
+
+ for( int k = 0; k < 18; ++k )
+ {
+ gdcm::MrProtocol::Slice & slice = sa.Slices[k];
+ gdcm::MrProtocol::Vector3 & nor = slice.Normal;
+ double normal[3];
+ normal[0] = nor.dSag;
+ normal[1] = nor.dCor;
+ normal[2] = nor.dTra;
+ for( int i = 0; i < 3; ++i )
+ {
+ if( std::fabs( refnor[i] - normal[i] ) > eps )
+ {
+ std::cerr << "Invalid normal: " << filename << std::endl;
+ return 1;
+ }
+ }
+ }
+
+
+ gdcm::Anonymizer ano;
+ ano.SetFile( reader.GetFile() );
+ const gdcm::PrivateTag &t1 = csa.GetCSAImageHeaderInfoTag();
+ ano.Remove( t1 );
+
+ unsigned int modims[3];
+ b = filter.ComputeMOSAICDimensions( modims );
+ if(! b )
+ {
+ std::cerr << "ComputeMOSAICDimensions: " << filename << std::endl;
+ return 1;
+ }
+
+ const unsigned int ref[3] = { 64u, 64u, 18u };
+ if( modims[0] != ref[0] || modims[1] != ref[1] || modims[2] != ref[2] )
+ {
+ std::cerr << "Invalid ComputeMOSAICDimensions " << filename << std::endl;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/Utilities/doxygen/man/gdcmdump.xml b/Utilities/doxygen/man/gdcmdump.xml
index a3ff2de..8dae04c 100644
--- a/Utilities/doxygen/man/gdcmdump.xml
+++ b/Utilities/doxygen/man/gdcmdump.xml
@@ -53,6 +53,7 @@ dcm_directory DICOM input directory
-C --csa print SIEMENS CSA Header (0029,[12]0,SIEMENS CSA HEADER).
--csa-asl print decoded SIEMENS CSA MR_ASL (base64).
--csa-diffusion print decoded SIEMENS CSA MRDiffusion (base64).
+ --mrprotocol print SIEMENS CSA MrProtocol only (within ASCCONV BEGIN/END).
-P --pdb print GEMS Protocol Data Block (0025,1b,GEMS_SERS_01).
--elscint print ELSCINT Protocol Information (01f7,26,ELSCINT1).
--vepro print VEPRO Protocol Information (0055,20,VEPRO VIF 3.0 DATA).
@@ -264,6 +265,685 @@ $ dcmdump -f asl.dcm
(fffe,e0dd)
</literallayout></para>
</refsection>
+<refsection xml:id="gdcmdump_1siemens_mrprotocol">
+<title>SIEMENS CSA Header: MrProtocol</title>
+
+<para>Using this option it is possible to dump a sorted version of MrProtocol (extra '"' are trimmed).</para>
+
+<para>Eg.:</para>
+
+<para><literallayout>$ gdcmdump --mrprotocol input.dcm
+</literallayout></para>
+
+<para><literallayout>
+MrProtocolVersion: 12510002
+acFlowComp[0] : 1
+adFlipAngleDegree[0] : 90
+alTE[0] : 60000
+alTR[0] : 3000000
+dRefSNR : 181090.7706
+dRefSNR_VOI : 181090.7706
+lAverages : 1
+lCombinedEchoes : 1
+lContrasts : 1
+lParadigmPeriodicity : 1
+lRepetitions : 79
+lScanTimeSec : 3
+lTotalScanTimeSec : 246
+sAdjFreSpec.ulMode : 0x1
+sAdjShimSpec.ulMode : 0x2
+sAdjWatSupSpec.ulMode : 0x1
+sAngio.ucPCFlowMode : 0x2
+sAngio.ucTOFInflow : 0x4
+sAutoAlign.dAAMatrix[0] : 1
+sAutoAlign.dAAMatrix[10] : 1
+sAutoAlign.dAAMatrix[15] : 1
+sAutoAlign.dAAMatrix[5] : 1
+sCOIL_SELECT_MEAS.asList[0].lElementSelected : 1
+sCOIL_SELECT_MEAS.asList[0].lRxChannelConnected : 1
+sCOIL_SELECT_MEAS.asList[0].sCoilElementID.lCoilCopy : 1
+sCOIL_SELECT_MEAS.asList[0].sCoilElementID.tCoilID : 8_Channel_Head
+sCOIL_SELECT_MEAS.asList[0].sCoilElementID.tElement : PH7
+sCOIL_SELECT_MEAS.asList[1].lElementSelected : 1
+sCOIL_SELECT_MEAS.asList[1].lRxChannelConnected : 2
+sCOIL_SELECT_MEAS.asList[1].sCoilElementID.lCoilCopy : 1
+sCOIL_SELECT_MEAS.asList[1].sCoilElementID.tCoilID : 8_Channel_Head
+sCOIL_SELECT_MEAS.asList[1].sCoilElementID.tElement : PH5
+sCOIL_SELECT_MEAS.asList[2].lElementSelected : 1
+sCOIL_SELECT_MEAS.asList[2].lRxChannelConnected : 3
+sCOIL_SELECT_MEAS.asList[2].sCoilElementID.lCoilCopy : 1
+sCOIL_SELECT_MEAS.asList[2].sCoilElementID.tCoilID : 8_Channel_Head
+sCOIL_SELECT_MEAS.asList[2].sCoilElementID.tElement : PH3
+sCOIL_SELECT_MEAS.asList[3].lElementSelected : 1
+sCOIL_SELECT_MEAS.asList[3].lRxChannelConnected : 4
+sCOIL_SELECT_MEAS.asList[3].sCoilElementID.lCoilCopy : 1
+sCOIL_SELECT_MEAS.asList[3].sCoilElementID.tCoilID : 8_Channel_Head
+sCOIL_SELECT_MEAS.asList[3].sCoilElementID.tElement : PH1
+sCOIL_SELECT_MEAS.asList[4].lElementSelected : 1
+sCOIL_SELECT_MEAS.asList[4].lRxChannelConnected : 5
+sCOIL_SELECT_MEAS.asList[4].sCoilElementID.lCoilCopy : 1
+sCOIL_SELECT_MEAS.asList[4].sCoilElementID.tCoilID : 8_Channel_Head
+sCOIL_SELECT_MEAS.asList[4].sCoilElementID.tElement : PH8
+sCOIL_SELECT_MEAS.asList[5].lElementSelected : 1
+sCOIL_SELECT_MEAS.asList[5].lRxChannelConnected : 6
+sCOIL_SELECT_MEAS.asList[5].sCoilElementID.lCoilCopy : 1
+sCOIL_SELECT_MEAS.asList[5].sCoilElementID.tCoilID : 8_Channel_Head
+sCOIL_SELECT_MEAS.asList[5].sCoilElementID.tElement : PH6
+sCOIL_SELECT_MEAS.asList[6].lElementSelected : 1
+sCOIL_SELECT_MEAS.asList[6].lRxChannelConnected : 7
+sCOIL_SELECT_MEAS.asList[6].sCoilElementID.lCoilCopy : 1
+sCOIL_SELECT_MEAS.asList[6].sCoilElementID.tCoilID : 8_Channel_Head
+sCOIL_SELECT_MEAS.asList[6].sCoilElementID.tElement : PH4
+sCOIL_SELECT_MEAS.asList[7].lElementSelected : 1
+sCOIL_SELECT_MEAS.asList[7].lRxChannelConnected : 8
+sCOIL_SELECT_MEAS.asList[7].sCoilElementID.lCoilCopy : 1
+sCOIL_SELECT_MEAS.asList[7].sCoilElementID.tCoilID : 8_Channel_Head
+sCOIL_SELECT_MEAS.asList[7].sCoilElementID.tElement : PH2
+sCOIL_SELECT_MEAS.sCOILPLUGS.auiNmbrOfNibbles[0] : 0x2
+sCOIL_SELECT_MEAS.sCOILPLUGS.auiNmbrOfNibbles[1] : 0x2
+sCOIL_SELECT_MEAS.sCOILPLUGS.auiNmbrOfNibbles[2] : 0x2
+sCOIL_SELECT_MEAS.sCOILPLUGS.auiNmbrOfNibbles[3] : 0x2
+sCOIL_SELECT_MEAS.sCOILPLUGS.auiNmbrOfNibbles[4] : 0x2
+sCOIL_SELECT_MEAS.sCOILPLUGS.aulPlugId[0] : 0xff
+sCOIL_SELECT_MEAS.sCOILPLUGS.aulPlugId[1] : 0xaa
+sCOIL_SELECT_MEAS.sCOILPLUGS.aulPlugId[2] : 0xee
+sCOIL_SELECT_MEAS.sCOILPLUGS.aulPlugId[3] : 0xee
+sCOIL_SELECT_MEAS.sCOILPLUGS.aulPlugId[4] : 0xa4
+sDiffusion.ulMode : 0x1
+sEFISPEC.bEFIDataValid : 1
+sEllipticalFilter.ucMode : 0x1
+sFastImaging.lEPIFactor : 128
+sFastImaging.lSegments : 1
+sFastImaging.lTurboFactor : 1
+sGRADSPEC.alShimCurrent[0] : -166
+sGRADSPEC.alShimCurrent[1] : 596
+sGRADSPEC.alShimCurrent[2] : -516
+sGRADSPEC.alShimCurrent[3] : 84
+sGRADSPEC.alShimCurrent[4] : -295
+sGRADSPEC.bB0CompensationValid : 1
+sGRADSPEC.bCrossTermCompensationValid : 1
+sGRADSPEC.bDelayValid : 1
+sGRADSPEC.bEddyCompensationValid : 1
+sGRADSPEC.bOffsetValid : 1
+sGRADSPEC.bSensitivityValid : 1
+sGRADSPEC.bShimCurrentValid : 1
+sGRADSPEC.flGSWDMinRiseTime : 5
+sGRADSPEC.flSensitivityX : 0.000353238
+sGRADSPEC.flSensitivityY : 0.000364826
+sGRADSPEC.flSensitivityZ : 0.000356804
+sGRADSPEC.lDelayX : 14
+sGRADSPEC.lDelayY : 15
+sGRADSPEC.lDelayZ : 13
+sGRADSPEC.lOffsetX : -10
+sGRADSPEC.lOffsetY : 22
+sGRADSPEC.lOffsetZ : 34
+sGRADSPEC.sB0CompensationX.aflAmplitude[0] : -0.0110937
+sGRADSPEC.sB0CompensationX.aflAmplitude[1] : -0.0276212
+sGRADSPEC.sB0CompensationX.aflAmplitude[2] : 0.00261628
+sGRADSPEC.sB0CompensationX.aflTimeConstant[0] : 1.86006
+sGRADSPEC.sB0CompensationX.aflTimeConstant[1] : 0.0451358
+sGRADSPEC.sB0CompensationX.aflTimeConstant[2] : 0.00199924
+sGRADSPEC.sB0CompensationY.aflAmplitude[0] : 0.0647921
+sGRADSPEC.sB0CompensationY.aflAmplitude[1] : 0.0207167
+sGRADSPEC.sB0CompensationY.aflAmplitude[2] : -0.0131878
+sGRADSPEC.sB0CompensationY.aflTimeConstant[0] : 0.852499
+sGRADSPEC.sB0CompensationY.aflTimeConstant[1] : 0.0633158
+sGRADSPEC.sB0CompensationY.aflTimeConstant[2] : 0.00199999
+sGRADSPEC.sB0CompensationZ.aflAmplitude[0] : 0.119857
+sGRADSPEC.sB0CompensationZ.aflAmplitude[1] : 0.0106907
+sGRADSPEC.sB0CompensationZ.aflAmplitude[2] : -0.0159243
+sGRADSPEC.sB0CompensationZ.aflTimeConstant[0] : 1.03958
+sGRADSPEC.sB0CompensationZ.aflTimeConstant[1] : 0.019543
+sGRADSPEC.sB0CompensationZ.aflTimeConstant[2] : 0.00141055
+sGRADSPEC.sCrossTermCompensationXY.aflAmplitude[0] : 0.000779649
+sGRADSPEC.sCrossTermCompensationXY.aflTimeConstant[0] : 0.609972
+sGRADSPEC.sCrossTermCompensationXZ.aflAmplitude[0] : -0.000357764
+sGRADSPEC.sCrossTermCompensationXZ.aflTimeConstant[0] : 0.757463
+sGRADSPEC.sCrossTermCompensationYX.aflAmplitude[0] : 0.00028701
+sGRADSPEC.sCrossTermCompensationYX.aflTimeConstant[0] : 0.692162
+sGRADSPEC.sCrossTermCompensationYZ.aflAmplitude[0] : 0.000341002
+sGRADSPEC.sCrossTermCompensationYZ.aflTimeConstant[0] : 0.643997
+sGRADSPEC.sEddyCompensationX.aflAmplitude[0] : 0.00321033
+sGRADSPEC.sEddyCompensationX.aflAmplitude[1] : 0.0764387
+sGRADSPEC.sEddyCompensationX.aflAmplitude[2] : -0.0119296
+sGRADSPEC.sEddyCompensationX.aflAmplitude[3] : 0.002806
+sGRADSPEC.sEddyCompensationX.aflAmplitude[4] : 0.00131044
+sGRADSPEC.sEddyCompensationX.aflTimeConstant[0] : 1.92825
+sGRADSPEC.sEddyCompensationX.aflTimeConstant[1] : 0.530542
+sGRADSPEC.sEddyCompensationX.aflTimeConstant[2] : 0.348189
+sGRADSPEC.sEddyCompensationX.aflTimeConstant[3] : 0.0172583
+sGRADSPEC.sEddyCompensationX.aflTimeConstant[4] : 0.00199055
+sGRADSPEC.sEddyCompensationY.aflAmplitude[0] : 0.00129643
+sGRADSPEC.sEddyCompensationY.aflAmplitude[1] : 0.0657945
+sGRADSPEC.sEddyCompensationY.aflAmplitude[2] : -0.00875319
+sGRADSPEC.sEddyCompensationY.aflAmplitude[3] : 0.00247817
+sGRADSPEC.sEddyCompensationY.aflAmplitude[4] : 0.00136282
+sGRADSPEC.sEddyCompensationY.aflTimeConstant[0] : 2.18733
+sGRADSPEC.sEddyCompensationY.aflTimeConstant[1] : 0.554603
+sGRADSPEC.sEddyCompensationY.aflTimeConstant[2] : 0.363992
+sGRADSPEC.sEddyCompensationY.aflTimeConstant[3] : 0.0174167
+sGRADSPEC.sEddyCompensationY.aflTimeConstant[4] : 0.0019934
+sGRADSPEC.sEddyCompensationZ.aflAmplitude[0] : 0.0106364
+sGRADSPEC.sEddyCompensationZ.aflAmplitude[1] : 0.0644895
+sGRADSPEC.sEddyCompensationZ.aflAmplitude[2] : -0.0116849
+sGRADSPEC.sEddyCompensationZ.aflAmplitude[3] : 0.00245425
+sGRADSPEC.sEddyCompensationZ.aflAmplitude[4] : -0.000382604
+sGRADSPEC.sEddyCompensationZ.aflTimeConstant[0] : 2.45763
+sGRADSPEC.sEddyCompensationZ.aflTimeConstant[1] : 0.728919
+sGRADSPEC.sEddyCompensationZ.aflTimeConstant[2] : 0.490303
+sGRADSPEC.sEddyCompensationZ.aflTimeConstant[3] : 0.0146871
+sGRADSPEC.sEddyCompensationZ.aflTimeConstant[4] : 0.00198729
+sGRADSPEC.ucMode : 0x11
+sGroupArray.anMember[10] : 10
+sGroupArray.anMember[11] : 11
+sGroupArray.anMember[12] : 12
+sGroupArray.anMember[13] : 13
+sGroupArray.anMember[14] : 14
+sGroupArray.anMember[15] : 15
+sGroupArray.anMember[16] : 16
+sGroupArray.anMember[17] : 17
+sGroupArray.anMember[18] : 18
+sGroupArray.anMember[19] : 19
+sGroupArray.anMember[1] : 1
+sGroupArray.anMember[20] : 20
+sGroupArray.anMember[21] : 21
+sGroupArray.anMember[22] : 22
+sGroupArray.anMember[23] : 23
+sGroupArray.anMember[24] : 24
+sGroupArray.anMember[25] : 25
+sGroupArray.anMember[26] : 26
+sGroupArray.anMember[27] : 27
+sGroupArray.anMember[28] : 28
+sGroupArray.anMember[29] : 29
+sGroupArray.anMember[2] : 2
+sGroupArray.anMember[30] : 30
+sGroupArray.anMember[31] : -1
+sGroupArray.anMember[3] : 3
+sGroupArray.anMember[4] : 4
+sGroupArray.anMember[5] : 5
+sGroupArray.anMember[6] : 6
+sGroupArray.anMember[7] : 7
+sGroupArray.anMember[8] : 8
+sGroupArray.anMember[9] : 9
+sGroupArray.asGroup[0].dDistFact : 0.1
+sGroupArray.asGroup[0].nSize : 31
+sGroupArray.lSize : 1
+sGroupArray.sPSat.dGap : 10
+sGroupArray.sPSat.dThickness : 50
+sKSpace.dPhaseResolution : 1
+sKSpace.dSliceResolution : 1
+sKSpace.lBaseResolution : 64
+sKSpace.lImagesPerSlab : 64
+sKSpace.lPartitions : 64
+sKSpace.lPhaseEncodingLines : 64
+sKSpace.ucAveragingMode : 0x2
+sKSpace.ucDimension : 0x2
+sKSpace.ucMultiSliceMode : 0x2
+sKSpace.ucPhasePartialFourier : 0x10
+sKSpace.ucSlicePartialFourier : 0x10
+sKSpace.unReordering : 0x1
+sNavigatorPara.ucRespComp : 0x4
+sPat.lAccelFact3D : 1
+sPat.lAccelFactPE : 1
+sPat.ucPATMode : 0x1
+sPat.ucRefScanMode : 0x1
+sPhysioImaging.lMethod1 : 1
+sPhysioImaging.lMethod2 : 1
+sPhysioImaging.lPhases : 1
+sPhysioImaging.lRetroGatedImages : 16
+sPhysioImaging.lSignal1 : 1
+sPhysioImaging.lSignal2 : 1
+sPhysioImaging.sPhysioECG.lArrhythmiaDetection : 1
+sPhysioImaging.sPhysioECG.lCardiacGateOffThreshold : 700000
+sPhysioImaging.sPhysioECG.lCardiacGateOnThreshold : 100000
+sPhysioImaging.sPhysioECG.lTriggerPulses : 1
+sPhysioImaging.sPhysioECG.lTriggerWindow : 5
+sPhysioImaging.sPhysioExt.lCardiacGateOffThreshold : 700000
+sPhysioImaging.sPhysioExt.lCardiacGateOnThreshold : 100000
+sPhysioImaging.sPhysioExt.lTriggerPulses : 1
+sPhysioImaging.sPhysioExt.lTriggerWindow : 5
+sPhysioImaging.sPhysioPulse.lCardiacGateOffThreshold : 700000
+sPhysioImaging.sPhysioPulse.lCardiacGateOnThreshold : 100000
+sPhysioImaging.sPhysioPulse.lTriggerPulses : 1
+sPhysioImaging.sPhysioPulse.lTriggerWindow : 5
+sPhysioImaging.sPhysioResp.dGatingRatio : 0.3
+sPhysioImaging.sPhysioResp.lRespGatePhase : 2
+sPhysioImaging.sPhysioResp.lRespGateThreshold : 20
+sPrepPulses.ucFatSat : 0x1
+sPrepPulses.ucFatSatMode : 0x2
+sPrepPulses.ucInversion : 0x4
+sPrepPulses.ucSatRecovery : 0x1
+sPrepPulses.ucWaterSat : 0x4
+sProtConsistencyInfo.flGMax : 26
+sProtConsistencyInfo.flNominalB0 : 1.494
+sProtConsistencyInfo.flRiseTime : 5
+sRXSPEC.aFFT_SCALE[0].bValid : 1
+sRXSPEC.aFFT_SCALE[0].flFactor : 0.720612
+sRXSPEC.aFFT_SCALE[0].lRxChannel : 1
+sRXSPEC.aFFT_SCALE[1].bValid : 1
+sRXSPEC.aFFT_SCALE[1].flFactor : 0.719059
+sRXSPEC.aFFT_SCALE[1].lRxChannel : 2
+sRXSPEC.aFFT_SCALE[2].bValid : 1
+sRXSPEC.aFFT_SCALE[2].flFactor : 0.705708
+sRXSPEC.aFFT_SCALE[2].lRxChannel : 3
+sRXSPEC.aFFT_SCALE[3].bValid : 1
+sRXSPEC.aFFT_SCALE[3].flFactor : 0.731533
+sRXSPEC.aFFT_SCALE[3].lRxChannel : 4
+sRXSPEC.aFFT_SCALE[4].bValid : 1
+sRXSPEC.aFFT_SCALE[4].flFactor : 0.722418
+sRXSPEC.aFFT_SCALE[4].lRxChannel : 5
+sRXSPEC.aFFT_SCALE[5].bValid : 1
+sRXSPEC.aFFT_SCALE[5].flFactor : 0.738751
+sRXSPEC.aFFT_SCALE[5].lRxChannel : 6
+sRXSPEC.aFFT_SCALE[6].bValid : 1
+sRXSPEC.aFFT_SCALE[6].flFactor : 0.719098
+sRXSPEC.aFFT_SCALE[6].lRxChannel : 7
+sRXSPEC.aFFT_SCALE[7].bValid : 1
+sRXSPEC.aFFT_SCALE[7].flFactor : 0.733029
+sRXSPEC.aFFT_SCALE[7].lRxChannel : 8
+sRXSPEC.alDwellTime[0] : 3000
+sRXSPEC.bGainValid : 1
+sRXSPEC.bVariCapVoltagesValid : 1
+sRXSPEC.lGain : 1
+sSliceArray.anAsc[10] : 10
+sSliceArray.anAsc[11] : 11
+sSliceArray.anAsc[12] : 12
+sSliceArray.anAsc[13] : 13
+sSliceArray.anAsc[14] : 14
+sSliceArray.anAsc[15] : 15
+sSliceArray.anAsc[16] : 16
+sSliceArray.anAsc[17] : 17
+sSliceArray.anAsc[18] : 18
+sSliceArray.anAsc[19] : 19
+sSliceArray.anAsc[1] : 1
+sSliceArray.anAsc[20] : 20
+sSliceArray.anAsc[21] : 21
+sSliceArray.anAsc[22] : 22
+sSliceArray.anAsc[23] : 23
+sSliceArray.anAsc[24] : 24
+sSliceArray.anAsc[25] : 25
+sSliceArray.anAsc[26] : 26
+sSliceArray.anAsc[27] : 27
+sSliceArray.anAsc[28] : 28
+sSliceArray.anAsc[29] : 29
+sSliceArray.anAsc[2] : 2
+sSliceArray.anAsc[30] : 30
+sSliceArray.anAsc[3] : 3
+sSliceArray.anAsc[4] : 4
+sSliceArray.anAsc[5] : 5
+sSliceArray.anAsc[6] : 6
+sSliceArray.anAsc[7] : 7
+sSliceArray.anAsc[8] : 8
+sSliceArray.anAsc[9] : 9
+sSliceArray.anPos[10] : 10
+sSliceArray.anPos[11] : 11
+sSliceArray.anPos[12] : 12
+sSliceArray.anPos[13] : 13
+sSliceArray.anPos[14] : 14
+sSliceArray.anPos[15] : 15
+sSliceArray.anPos[16] : 16
+sSliceArray.anPos[17] : 17
+sSliceArray.anPos[18] : 18
+sSliceArray.anPos[19] : 19
+sSliceArray.anPos[1] : 1
+sSliceArray.anPos[20] : 20
+sSliceArray.anPos[21] : 21
+sSliceArray.anPos[22] : 22
+sSliceArray.anPos[23] : 23
+sSliceArray.anPos[24] : 24
+sSliceArray.anPos[25] : 25
+sSliceArray.anPos[26] : 26
+sSliceArray.anPos[27] : 27
+sSliceArray.anPos[28] : 28
+sSliceArray.anPos[29] : 29
+sSliceArray.anPos[2] : 2
+sSliceArray.anPos[30] : 30
+sSliceArray.anPos[3] : 3
+sSliceArray.anPos[4] : 4
+sSliceArray.anPos[5] : 5
+sSliceArray.anPos[6] : 6
+sSliceArray.anPos[7] : 7
+sSliceArray.anPos[8] : 8
+sSliceArray.anPos[9] : 9
+sSliceArray.asSlice[0].dPhaseFOV : 230
+sSliceArray.asSlice[0].dReadoutFOV : 230
+sSliceArray.asSlice[0].dThickness : 4
+sSliceArray.asSlice[0].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[0].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[0].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[0].sPosition.dCor : -52.65585315
+sSliceArray.asSlice[0].sPosition.dSag : 2.24891108
+sSliceArray.asSlice[0].sPosition.dTra : -26.94105767
+sSliceArray.asSlice[10].dPhaseFOV : 230
+sSliceArray.asSlice[10].dReadoutFOV : 230
+sSliceArray.asSlice[10].dThickness : 4
+sSliceArray.asSlice[10].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[10].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[10].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[10].sPosition.dCor : -48.78027355
+sSliceArray.asSlice[10].sPosition.dSag : -1.356313999
+sSliceArray.asSlice[10].sPosition.dTra : 16.73939831
+sSliceArray.asSlice[11].dPhaseFOV : 230
+sSliceArray.asSlice[11].dReadoutFOV : 230
+sSliceArray.asSlice[11].dThickness : 4
+sSliceArray.asSlice[11].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[11].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[11].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[11].sPosition.dCor : -48.39271559
+sSliceArray.asSlice[11].sPosition.dSag : -1.716836507
+sSliceArray.asSlice[11].sPosition.dTra : 21.10744391
+sSliceArray.asSlice[12].dPhaseFOV : 230
+sSliceArray.asSlice[12].dReadoutFOV : 230
+sSliceArray.asSlice[12].dThickness : 4
+sSliceArray.asSlice[12].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[12].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[12].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[12].sPosition.dCor : -48.00515763
+sSliceArray.asSlice[12].sPosition.dSag : -2.077359015
+sSliceArray.asSlice[12].sPosition.dTra : 25.47548951
+sSliceArray.asSlice[13].dPhaseFOV : 230
+sSliceArray.asSlice[13].dReadoutFOV : 230
+sSliceArray.asSlice[13].dThickness : 4
+sSliceArray.asSlice[13].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[13].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[13].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[13].sPosition.dCor : -47.61759967
+sSliceArray.asSlice[13].sPosition.dSag : -2.437881523
+sSliceArray.asSlice[13].sPosition.dTra : 29.84353511
+sSliceArray.asSlice[14].dPhaseFOV : 230
+sSliceArray.asSlice[14].dReadoutFOV : 230
+sSliceArray.asSlice[14].dThickness : 4
+sSliceArray.asSlice[14].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[14].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[14].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[14].sPosition.dCor : -47.23004171
+sSliceArray.asSlice[14].sPosition.dSag : -2.798404031
+sSliceArray.asSlice[14].sPosition.dTra : 34.21158071
+sSliceArray.asSlice[15].dPhaseFOV : 230
+sSliceArray.asSlice[15].dReadoutFOV : 230
+sSliceArray.asSlice[15].dThickness : 4
+sSliceArray.asSlice[15].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[15].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[15].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[15].sPosition.dCor : -46.84248375
+sSliceArray.asSlice[15].sPosition.dSag : -3.158926539
+sSliceArray.asSlice[15].sPosition.dTra : 38.57962631
+sSliceArray.asSlice[16].dPhaseFOV : 230
+sSliceArray.asSlice[16].dReadoutFOV : 230
+sSliceArray.asSlice[16].dThickness : 4
+sSliceArray.asSlice[16].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[16].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[16].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[16].sPosition.dCor : -46.45492579
+sSliceArray.asSlice[16].sPosition.dSag : -3.519449047
+sSliceArray.asSlice[16].sPosition.dTra : 42.9476719
+sSliceArray.asSlice[17].dPhaseFOV : 230
+sSliceArray.asSlice[17].dReadoutFOV : 230
+sSliceArray.asSlice[17].dThickness : 4
+sSliceArray.asSlice[17].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[17].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[17].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[17].sPosition.dCor : -46.06736783
+sSliceArray.asSlice[17].sPosition.dSag : -3.879971555
+sSliceArray.asSlice[17].sPosition.dTra : 47.3157175
+sSliceArray.asSlice[18].dPhaseFOV : 230
+sSliceArray.asSlice[18].dReadoutFOV : 230
+sSliceArray.asSlice[18].dThickness : 4
+sSliceArray.asSlice[18].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[18].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[18].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[18].sPosition.dCor : -45.67980987
+sSliceArray.asSlice[18].sPosition.dSag : -4.240494063
+sSliceArray.asSlice[18].sPosition.dTra : 51.6837631
+sSliceArray.asSlice[19].dPhaseFOV : 230
+sSliceArray.asSlice[19].dReadoutFOV : 230
+sSliceArray.asSlice[19].dThickness : 4
+sSliceArray.asSlice[19].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[19].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[19].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[19].sPosition.dCor : -45.29225191
+sSliceArray.asSlice[19].sPosition.dSag : -4.601016571
+sSliceArray.asSlice[19].sPosition.dTra : 56.0518087
+sSliceArray.asSlice[1].dPhaseFOV : 230
+sSliceArray.asSlice[1].dReadoutFOV : 230
+sSliceArray.asSlice[1].dThickness : 4
+sSliceArray.asSlice[1].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[1].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[1].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[1].sPosition.dCor : -52.26829519
+sSliceArray.asSlice[1].sPosition.dSag : 1.888388572
+sSliceArray.asSlice[1].sPosition.dTra : -22.57301207
+sSliceArray.asSlice[20].dPhaseFOV : 230
+sSliceArray.asSlice[20].dReadoutFOV : 230
+sSliceArray.asSlice[20].dThickness : 4
+sSliceArray.asSlice[20].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[20].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[20].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[20].sPosition.dCor : -44.90469395
+sSliceArray.asSlice[20].sPosition.dSag : -4.961539079
+sSliceArray.asSlice[20].sPosition.dTra : 60.4198543
+sSliceArray.asSlice[21].dPhaseFOV : 230
+sSliceArray.asSlice[21].dReadoutFOV : 230
+sSliceArray.asSlice[21].dThickness : 4
+sSliceArray.asSlice[21].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[21].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[21].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[21].sPosition.dCor : -44.51713599
+sSliceArray.asSlice[21].sPosition.dSag : -5.322061587
+sSliceArray.asSlice[21].sPosition.dTra : 64.7878999
+sSliceArray.asSlice[22].dPhaseFOV : 230
+sSliceArray.asSlice[22].dReadoutFOV : 230
+sSliceArray.asSlice[22].dThickness : 4
+sSliceArray.asSlice[22].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[22].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[22].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[22].sPosition.dCor : -44.12957804
+sSliceArray.asSlice[22].sPosition.dSag : -5.682584095
+sSliceArray.asSlice[22].sPosition.dTra : 69.15594549
+sSliceArray.asSlice[23].dPhaseFOV : 230
+sSliceArray.asSlice[23].dReadoutFOV : 230
+sSliceArray.asSlice[23].dThickness : 4
+sSliceArray.asSlice[23].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[23].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[23].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[23].sPosition.dCor : -43.74202008
+sSliceArray.asSlice[23].sPosition.dSag : -6.043106603
+sSliceArray.asSlice[23].sPosition.dTra : 73.52399109
+sSliceArray.asSlice[24].dPhaseFOV : 230
+sSliceArray.asSlice[24].dReadoutFOV : 230
+sSliceArray.asSlice[24].dThickness : 4
+sSliceArray.asSlice[24].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[24].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[24].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[24].sPosition.dCor : -43.35446212
+sSliceArray.asSlice[24].sPosition.dSag : -6.403629111
+sSliceArray.asSlice[24].sPosition.dTra : 77.89203669
+sSliceArray.asSlice[25].dPhaseFOV : 230
+sSliceArray.asSlice[25].dReadoutFOV : 230
+sSliceArray.asSlice[25].dThickness : 4
+sSliceArray.asSlice[25].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[25].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[25].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[25].sPosition.dCor : -42.96690416
+sSliceArray.asSlice[25].sPosition.dSag : -6.764151619
+sSliceArray.asSlice[25].sPosition.dTra : 82.26008229
+sSliceArray.asSlice[26].dPhaseFOV : 230
+sSliceArray.asSlice[26].dReadoutFOV : 230
+sSliceArray.asSlice[26].dThickness : 4
+sSliceArray.asSlice[26].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[26].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[26].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[26].sPosition.dCor : -42.5793462
+sSliceArray.asSlice[26].sPosition.dSag : -7.124674127
+sSliceArray.asSlice[26].sPosition.dTra : 86.62812789
+sSliceArray.asSlice[27].dPhaseFOV : 230
+sSliceArray.asSlice[27].dReadoutFOV : 230
+sSliceArray.asSlice[27].dThickness : 4
+sSliceArray.asSlice[27].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[27].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[27].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[27].sPosition.dCor : -42.19178824
+sSliceArray.asSlice[27].sPosition.dSag : -7.485196635
+sSliceArray.asSlice[27].sPosition.dTra : 90.99617349
+sSliceArray.asSlice[28].dPhaseFOV : 230
+sSliceArray.asSlice[28].dReadoutFOV : 230
+sSliceArray.asSlice[28].dThickness : 4
+sSliceArray.asSlice[28].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[28].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[28].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[28].sPosition.dCor : -41.80423028
+sSliceArray.asSlice[28].sPosition.dSag : -7.845719143
+sSliceArray.asSlice[28].sPosition.dTra : 95.36421908
+sSliceArray.asSlice[29].dPhaseFOV : 230
+sSliceArray.asSlice[29].dReadoutFOV : 230
+sSliceArray.asSlice[29].dThickness : 4
+sSliceArray.asSlice[29].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[29].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[29].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[29].sPosition.dCor : -41.41667232
+sSliceArray.asSlice[29].sPosition.dSag : -8.206241651
+sSliceArray.asSlice[29].sPosition.dTra : 99.73226468
+sSliceArray.asSlice[2].dPhaseFOV : 230
+sSliceArray.asSlice[2].dReadoutFOV : 230
+sSliceArray.asSlice[2].dThickness : 4
+sSliceArray.asSlice[2].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[2].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[2].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[2].sPosition.dCor : -51.88073723
+sSliceArray.asSlice[2].sPosition.dSag : 1.527866064
+sSliceArray.asSlice[2].sPosition.dTra : -18.20496647
+sSliceArray.asSlice[30].dPhaseFOV : 230
+sSliceArray.asSlice[30].dReadoutFOV : 230
+sSliceArray.asSlice[30].dThickness : 4
+sSliceArray.asSlice[30].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[30].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[30].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[30].sPosition.dCor : -41.02911436
+sSliceArray.asSlice[30].sPosition.dSag : -8.566764159
+sSliceArray.asSlice[30].sPosition.dTra : 104.1003103
+sSliceArray.asSlice[3].dPhaseFOV : 230
+sSliceArray.asSlice[3].dReadoutFOV : 230
+sSliceArray.asSlice[3].dThickness : 4
+sSliceArray.asSlice[3].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[3].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[3].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[3].sPosition.dCor : -51.49317927
+sSliceArray.asSlice[3].sPosition.dSag : 1.167343556
+sSliceArray.asSlice[3].sPosition.dTra : -13.83692088
+sSliceArray.asSlice[4].dPhaseFOV : 230
+sSliceArray.asSlice[4].dReadoutFOV : 230
+sSliceArray.asSlice[4].dThickness : 4
+sSliceArray.asSlice[4].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[4].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[4].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[4].sPosition.dCor : -51.10562131
+sSliceArray.asSlice[4].sPosition.dSag : 0.8068210485
+sSliceArray.asSlice[4].sPosition.dTra : -9.468875277
+sSliceArray.asSlice[5].dPhaseFOV : 230
+sSliceArray.asSlice[5].dReadoutFOV : 230
+sSliceArray.asSlice[5].dThickness : 4
+sSliceArray.asSlice[5].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[5].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[5].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[5].sPosition.dCor : -50.71806335
+sSliceArray.asSlice[5].sPosition.dSag : 0.4462985405
+sSliceArray.asSlice[5].sPosition.dTra : -5.100829679
+sSliceArray.asSlice[6].dPhaseFOV : 230
+sSliceArray.asSlice[6].dReadoutFOV : 230
+sSliceArray.asSlice[6].dThickness : 4
+sSliceArray.asSlice[6].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[6].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[6].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[6].sPosition.dCor : -50.33050539
+sSliceArray.asSlice[6].sPosition.dSag : 0.08577603254
+sSliceArray.asSlice[6].sPosition.dTra : -0.7327840804
+sSliceArray.asSlice[7].dPhaseFOV : 230
+sSliceArray.asSlice[7].dReadoutFOV : 230
+sSliceArray.asSlice[7].dThickness : 4
+sSliceArray.asSlice[7].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[7].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[7].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[7].sPosition.dCor : -49.94294743
+sSliceArray.asSlice[7].sPosition.dSag : -0.2747464754
+sSliceArray.asSlice[7].sPosition.dTra : 3.635261518
+sSliceArray.asSlice[8].dPhaseFOV : 230
+sSliceArray.asSlice[8].dReadoutFOV : 230
+sSliceArray.asSlice[8].dThickness : 4
+sSliceArray.asSlice[8].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[8].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[8].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[8].sPosition.dCor : -49.55538947
+sSliceArray.asSlice[8].sPosition.dSag : -0.6352689834
+sSliceArray.asSlice[8].sPosition.dTra : 8.003307116
+sSliceArray.asSlice[9].dPhaseFOV : 230
+sSliceArray.asSlice[9].dReadoutFOV : 230
+sSliceArray.asSlice[9].dThickness : 4
+sSliceArray.asSlice[9].sNormal.dCor : 0.08808135446
+sSliceArray.asSlice[9].sNormal.dSag : -0.08193693363
+sSliceArray.asSlice[9].sNormal.dTra : 0.992737636
+sSliceArray.asSlice[9].sPosition.dCor : -49.16783151
+sSliceArray.asSlice[9].sPosition.dSag : -0.9957914914
+sSliceArray.asSlice[9].sPosition.dTra : 12.37135271
+sSliceArray.lConc : 1
+sSliceArray.lSize : 31
+sSliceArray.sTSat.dThickness : 50
+sSliceArray.ucMode : 0x4
+sSpecPara.lDecouplingType : 1
+sSpecPara.lExcitationType : 1
+sSpecPara.lNOEType : 1
+sSpecPara.lPhaseCyclingType : 1
+sSpecPara.lPhaseEncodingType : 1
+sSpecPara.lRFExcitationBandwidth : 1
+sSpecPara.lSpectralSuppression : 1
+sSpecPara.ucRemoveOversampling : 0x1
+sTXSPEC.aRFPULSE[0].bAmplitudeValid : 0x1
+sTXSPEC.aRFPULSE[0].flAmplitude : 263.068
+sTXSPEC.aRFPULSE[0].tName : SincRFPulse
+sTXSPEC.aRFPULSE[1].bAmplitudeValid : 0x1
+sTXSPEC.aRFPULSE[1].flAmplitude : 31.9334
+sTXSPEC.aRFPULSE[1].tName : SLoopFCSatNS
+sTXSPEC.asNucleusInfo[0].bAmplitudeCorrectionValid : 1
+sTXSPEC.asNucleusInfo[0].bFrequencyValid : 1
+sTXSPEC.asNucleusInfo[0].bReferenceAmplitudeValid : 1
+sTXSPEC.asNucleusInfo[0].flAmplitudeCorrection : 1
+sTXSPEC.asNucleusInfo[0].flReferenceAmplitude : 259.084
+sTXSPEC.asNucleusInfo[0].lFrequency : 63644057
+sTXSPEC.asNucleusInfo[0].tNucleus : 1H
+sTXSPEC.asNucleusInfo[1].bAmplitudeCorrectionValid : 1
+sTXSPEC.asNucleusInfo[1].bFrequencyValid : 1
+sTXSPEC.asNucleusInfo[1].bReferenceAmplitudeValid : 1
+sTXSPEC.bBTBValid : 1
+sTXSPEC.bKDynValid : 1
+sTXSPEC.flKDynMagnitudeClipHigh : 1.04
+sTXSPEC.flKDynMagnitudeClipLow : 0.96
+sTXSPEC.flKDynMagnitudeMax : 1.5
+sTXSPEC.flKDynMagnitudeMin : 0.5
+sTXSPEC.flKDynPhaseClip : 0.174533
+sTXSPEC.flKDynPhaseMax : 0.698132
+sTXSPEC.lBTB1ParallelCapacity : 9
+sTXSPEC.lBTB1SerialCapacity : 16
+sTXSPEC.lBTB2ParallelCapacity : 8
+sTXSPEC.lBTB2SerialCapacity : 16
+sTXSPEC.lNoOfTraPulses : 2
+sTXSPEC.ucExcitMode : 0x1
+sTXSPEC.ucRFPulseType : 0x2
+sTXSPEC.ucSimultaneousExcitation : 0x1
+tProtocolName : ep2d+AF8-BOLD+AF8-evntX4
+tReferenceImage0 : 1.3.12.2.1107.5.2.12.21296.30000006070308044128100000804
+tReferenceImage1 : 1.3.12.2.1107.5.2.12.21296.30000006070308044128100000798
+tReferenceImage2 : 1.3.12.2.1107.5.2.12.21296.30000006070308044128100000797
+tSequenceFileName : %SiemensSeq%\ep2d_pace
+tcurrentEVAProt : %CURRENTEVAPROT%\EVA6A.tmp
+tdefaultEVAProt : %SiemensEvaDefProt%\BOLD\t-test_10B10A_moco.evp
+ucDisableChangeStoreImages : 0x1
+ucDixon : 0x1
+ucOneSeriesForAllMeas : 0x1
+ucPHAPSMode : 0x1
+ucReconstructionMode : 0x1
+ucScanRegionPosValid : 0x1
+ulVersion : 0xbee332
+</literallayout></para>
+</refsection>
<refsection xml:id="gdcmdump_1gems_pdb">
<title>GEMS Protocol Data Block</title>
diff --git a/Utilities/doxygen/man/gdcminfo.xml b/Utilities/doxygen/man/gdcminfo.xml
index e2e495b..795a9d2 100644
--- a/Utilities/doxygen/man/gdcminfo.xml
+++ b/Utilities/doxygen/man/gdcminfo.xml
@@ -163,6 +163,13 @@ Orientation Label: SAGITTAL
<para>Pay attention that this tool also checks the Image Lossy Compression attribute (0028,2110). This means <option>--check-compression</option> will also returns a value of lossy if a predecessor was found to be lossy compressed.</para>
</refsection>
</refsection>
+<refsection xml:id="gdcminfo_1mosaic">
+<title>Checking image as if MOSAIC</title>
+<para>Dump the image as if MOSAIC. If the input is really MOSAIC image, then print the information of the true underlying MOSAIC volume.</para>
+<para><literallayout>$ gdcminfo --mosaic siemens_mosaic.dcm
+</literallayout></para>
+
+</refsection>
<refsection xml:id="gdcminfo_1see_also">
<title>SEE ALSO</title>
diff --git a/Utilities/doxygen/man/gdcmtar.xml b/Utilities/doxygen/man/gdcmtar.xml
index 0d042d6..5d43f5b 100644
--- a/Utilities/doxygen/man/gdcmtar.xml
+++ b/Utilities/doxygen/man/gdcmtar.xml
@@ -43,6 +43,7 @@ file-out DICOM output filename
<para><literallayout> --enhance enhance (default)
-U --unenhance unenhance
-M --mosaic Split SIEMENS Mosaic image into multiple frames.
+ --mosaic-private When splitting SIEMENS Mosaic image into multiple frames, ppreserve private attributes (advanced user only).
-p --pattern Specify trailing file pattern.
--root-uid Root UID.
</literallayout></para>
@@ -80,7 +81,7 @@ file-out DICOM output filename
<title>Typical usage</title>
<refsection xml:id="gdcmtar_1mosaic">
<title>SIEMENS Mosaic</title>
-
+<para>This option will turn a 2D frame containing sub-frame of a SIEMENS MOSAIC into a set of MR Image Storage (legacy).</para>
<para><literallayout>$ gdcminfo MR-sonata-3D-as-Tile.dcm
</literallayout></para>
@@ -138,6 +139,11 @@ NumberOfDimensions: 2
Dimensions: (64,64,1)
...
</literallayout></para>
+<para>By default all private attributes are removed since they may not match the newly generated SOP Instance. One way to preserver the private attributes is to use the --mosaic-private command line option</para>
+<para><literallayout>$ gdcmtar --mosaic --mosaic-private -i MR-sonata-3D-as-Tile.dcm -o mosaic --pattern %03d.dcm
+</literallayout></para>
+
+
</refsection>
</refsection>
<refsection xml:id="gdcmtar_1see_also">
diff --git a/Wrapping/Python/gdcmswig.i b/Wrapping/Python/gdcmswig.i
index d4f71ee..26722ee 100644
--- a/Wrapping/Python/gdcmswig.i
+++ b/Wrapping/Python/gdcmswig.i
@@ -26,7 +26,6 @@
// "There is no option to suppress all SWIG warning messages."
#pragma SWIG nowarn=302,303,312,362,383,389,401,503,504,509,510,514,516
%{
-#define SWIG_PYTHON_STRICT_BYTE_CHAR
#include <cstddef> // ptrdiff_t
#include "gdcmTypes.h"
#include "gdcmASN1.h"
@@ -71,6 +70,7 @@
#include "gdcmBasicOffsetTable.h"
//#include "gdcmLO.h"
#include "gdcmCSAElement.h"
+#include "gdcmMrProtocol.h"
#include "gdcmPDBElement.h"
#include "gdcmFileSet.h"
@@ -195,6 +195,7 @@
#include "gdcmImageRegionReader.h"
#include "gdcmJSON.h"
#include "gdcmFileDecompressLookupTable.h"
+#include "gdcmEmptyMaskGenerator.h"
using namespace gdcm;
%}
@@ -444,6 +445,8 @@ EXTEND_CLASS_PRINT(gdcm::Fragment)
EXTEND_CLASS_PRINT(gdcm::PDBElement)
%include "gdcmPDBHeader.h"
EXTEND_CLASS_PRINT(gdcm::PDBHeader)
+%include "gdcmMrProtocol.h"
+EXTEND_CLASS_PRINT(gdcm::MrProtocol)
%include "gdcmCSAElement.h"
EXTEND_CLASS_PRINT(gdcm::CSAElement)
%include "gdcmCSAHeader.h"
@@ -797,3 +800,4 @@ EXTEND_CLASS_PRINT(gdcm::BoxRegion)
%clear char* inreadbuffer;
%include "gdcmJSON.h"
%include "gdcmFileDecompressLookupTable.h"
+%include "gdcmEmptyMaskGenerator.h"
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/gdcm.git
More information about the debian-med-commit
mailing list