diff --git a/Core/Code/Testing/CMakeLists.txt b/Core/Code/Testing/CMakeLists.txt index 2e3e2808a3..cbff306220 100644 --- a/Core/Code/Testing/CMakeLists.txt +++ b/Core/Code/Testing/CMakeLists.txt @@ -1,26 +1,29 @@ MITK_CREATE_MODULE_TESTS(LABELS MITK-Core) # MITK_INSTALL_TARGETS(EXECUTABLES MitkTestDriver) mitkAddCustomModuleTest(mitkPicFileReaderTest_emptyFile mitkPicFileReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/Data/emptyFile.pic) mitkAddCustomModuleTest(mitkPicFileReaderTest_emptyGzipFile mitkPicFileReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/Data/emptyFile.pic.gz) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_CT mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-ct.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_MR mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-mr.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_SC mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-sc.dcm) mitkAddCustomModuleTest(mitkEventMapperTest_Test1And2 mitkEventMapperTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) mitkAddCustomModuleTest(mitkNodeDependentPointSetInteractorTest mitkNodeDependentPointSetInteractorTest ${MITK_DATA_DIR}/Pic3D.pic.gz ${MITK_DATA_DIR}/BallBinary30x30x30.pic.gz) mitkAddCustomModuleTest(mitkDataStorageTest_US4DCyl mitkDataStorageTest ${MITK_DATA_DIR}/US4DCyl.pic.gz) mitkAddCustomModuleTest(mitkStateMachineFactoryTest_TestStateMachine1_2 mitkStateMachineFactoryTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) ADD_TEST(mitkPointSetLocaleTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPointSetLocaleTest ${MITK_DATA_DIR}/pointSet.mps) SET_PROPERTY(TEST mitkPointSetLocaleTest PROPERTY LABELS MITK-Core) ADD_TEST(mitkPicFileReaderTest_emptyGzipFile ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPicFileReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/Data/emptyFile.pic.gz) SET_PROPERTY(TEST mitkPicFileReaderTest_emptyGzipFile PROPERTY LABELS MITK-Core) ADD_TEST(mitkImageTest_brainImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageTest ${MITK_DATA_DIR}/brain.mhd) SET_PROPERTY(TEST mitkImageTest_brainImage PROPERTY LABELS MITK-Core) + +add_subdirectory(DICOMTesting) + diff --git a/Core/Code/Testing/DICOMTesting/CMakeLists.txt b/Core/Code/Testing/DICOMTesting/CMakeLists.txt new file mode 100644 index 0000000000..2ba6f34a77 --- /dev/null +++ b/Core/Code/Testing/DICOMTesting/CMakeLists.txt @@ -0,0 +1,35 @@ +if (BUILD_TESTING) +if (MITK_USE_GDCMIO) +if (GDCM_DIR) + +# clear variables from prior files.cmake +set(MODULE_TESTS) +set(MODULE_IMAGE_TESTS) +set(MODULE_TESTIMAGES) +set(MODULE_CUSTOM_TESTS) +set(H_FILES) +set(CPP_FILES) + +# now create a new module only for testing purposes +MITK_CREATE_MODULE( mitkDICOMTesting + DEPENDS Mitk # mitkCore.so +) + + +# add helpful applications +MITK_USE_MODULE( mitkDICOMTesting ) +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${ALL_INCLUDE_DIRECTORIES}) + +# dumps out image information +add_executable(DumpDICOMMitkImage DumpDICOMMitkImage.cpp) +target_link_libraries(DumpDICOMMitkImage ${ALL_LIBRARIES}) + +# compares dumped out image information against reference dump +add_executable(VerifyDICOMMitkImageDump VerifyDICOMMitkImageDump.cpp) +target_link_libraries(VerifyDICOMMitkImageDump ${ALL_LIBRARIES}) + +add_subdirectory(Testing) + +endif() +endif() +endif() diff --git a/Core/Code/Testing/DICOMTesting/DICOMTesting.dox b/Core/Code/Testing/DICOMTesting/DICOMTesting.dox new file mode 100644 index 0000000000..4fb69d36b1 --- /dev/null +++ b/Core/Code/Testing/DICOMTesting/DICOMTesting.dox @@ -0,0 +1,78 @@ +/** + +\page DICOMTesting MITK DICOM testing + +\section DICOMTesting_introduction Introduction + +Since loading a set of DICOM images is not a trivial task, MITK implements some tests +which verify its DICOM loading ability. + +\section DICOMTesting_problem Problem description + +The task of loading DICOM files into mitk::Images is a challenge because of major differences +in the way that DICOM and MITK represent images: + + - DICOM images + - are mostly stored as one slice per file + - do not describe how they can be arraged into image stacks with orthogonal axis + - sometimes they cannot be arranged in image stacks as described above (e.g. tilted gantry) + - mitk::Image (at least its mature areas) + - represents image stacks with orthogonal axis (nothing like a tilted gantry) + - have a concept of a fourth dimension (time steps) + +Because image processing applications based on MITK still need a way to load DICOM images into +mitk::Image objects, MITK needs to put a lot of effort into building image stacks as best as it can. And this needs to be well tested. + +For more background information, see David Clunie's most valuable posts on comp.protocols.dicom, e.g.: + + - http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/6db91972e161f0d4/6e0304ac264a6eb5 + - http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/e9bd1497bea3e66b/187a7dc8810613d2 + - http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/5d80bb0b7fafcb81/cf96119e3b024ed8 + - http://groups.google.com/group/comp.protocols.dicom/browse_thread/thread/4568635e083a3fba/e2a8ceec23032601 + +\section DICOMTesting_testidea Test principle + +The test idea is simple: load known sets of DICOM files, +analyze relevant aspects of the generated mitk::Image +objects and compare against stored expected results: + - number of 3D images generated + - origin, orientation + - pixel type, spacing, extent + +\section DICOMTesting_implementation Implementation + +\section DICOMTesting_implementation_utils Test helpers (applications and classes) + +Application DumpDICOMMitkImage + +Takes a list of DICOM images, loads them using TestDICOMLoading, then dumps information +about the resulting mitk::Images to standard output. + +This application is helpful when defining reference data for tests. + +Application VerifyDICOMMitkImageDump + +Takes a list of DICOM images and loads them using TestDICOMLoading. +Takes a dump file as generated by DumpDICOMMitkImage, parses it and +compares it to actually generated mitk::Images. + +This application is used to implement the majority of test cases. They all +load images, then verify the expected result structure. + +Class TestDICOMLoading + +\section DICOMTesting_testlist Specific tests + +This list is meant to provide an up-to-date list of all implemented DICOM loading tests. +If you ever find this outdated, please update it or make the persons who invalidated the list update it. + +mitkDICOMTestingSanityTest_* +These tests implement basic testing of the implemented helper classes. The tests use DicomSeriesReader to load +a number of DICOM image. They verify: + - DicomSeriesReader recognizes all input files as DICOM images + - DicomSeriesReader generates a number of mitk::Images from the DICOM images + - the number of mitk::Images matches a number given on the command line or CTest's add_test() + - helper methods in class TestDICOMLoading make minimal sense (comparison of an image dump to itself must be valid) + +*/ + diff --git a/Core/Code/Testing/DICOMTesting/DumpDICOMMitkImage.cpp b/Core/Code/Testing/DICOMTesting/DumpDICOMMitkImage.cpp new file mode 100644 index 0000000000..f7e0522545 --- /dev/null +++ b/Core/Code/Testing/DICOMTesting/DumpDICOMMitkImage.cpp @@ -0,0 +1,26 @@ +#include "mitkTestDICOMLoading.h" + +int main(int argc, char** argv) +{ + mitk::TestDICOMLoading loader; + mitk::TestDICOMLoading::StringContainer files; + + for (int arg = 1; arg < argc; ++arg) files.push_back( argv[arg] ); + + mitk::TestDICOMLoading::ImageList images = loader.LoadFiles(files); + + // combine individual dumps in a way that VerifyDICOMMitkImageDump is able to separate again. + // I.e.: when changing this piece of code, always change VerifyDICOMMitkImageDump, too. + unsigned int imageCounter(0); + for ( mitk::TestDICOMLoading::ImageList::const_iterator imageIter = images.begin(); + imageIter != images.end(); + ++imageIter ) + { + std::cout << "--------------------------------------------------------------------------------\n"; + std::cout << "-- Image " << ++imageCounter; + std::cout << "--------------------------------------------------------------------------------\n"; + std::cout << loader.DumpImageInformation( *imageIter ) << "\n"; + std::cout << "--------------------------------------------------------------------------------\n"; + } +} + diff --git a/Core/Code/Testing/DICOMTesting/Testing/CMakeLists.txt b/Core/Code/Testing/DICOMTesting/Testing/CMakeLists.txt new file mode 100644 index 0000000000..8ab610c5d9 --- /dev/null +++ b/Core/Code/Testing/DICOMTesting/Testing/CMakeLists.txt @@ -0,0 +1,11 @@ + +MITK_CREATE_MODULE_TESTS(LABELS MITK-Core) + +# verify minimum expectations: +# files are recognized as DICOM +# loading files results in a given number of images +mitkAddCustomModuleTest(mitkDICOMTestingSanityTest_NoFiles mitkDICOMTestingSanityTest 0) +mitkAddCustomModuleTest(mitkDICOMTestingSanityTest_CTImage mitkDICOMTestingSanityTest 1 ${MITK_DATA_DIR}/spacing-ok-ct.dcm) +mitkAddCustomModuleTest(mitkDICOMTestingSanityTest_MRImage mitkDICOMTestingSanityTest 1 ${MITK_DATA_DIR}/spacing-ok-mr.dcm) +mitkAddCustomModuleTest(mitkDICOMTestingSanityTest_SCImage mitkDICOMTestingSanityTest 1 ${MITK_DATA_DIR}/spacing-ok-sc.dcm) + diff --git a/Core/Code/Testing/DICOMTesting/Testing/files.cmake b/Core/Code/Testing/DICOMTesting/Testing/files.cmake new file mode 100644 index 0000000000..92af05e67b --- /dev/null +++ b/Core/Code/Testing/DICOMTesting/Testing/files.cmake @@ -0,0 +1,6 @@ + +# tests with no extra command line parameter +SET(MODULE_CUSTOM_TESTS + mitkDICOMTestingSanityTest.cpp +) + diff --git a/Core/Code/Testing/DICOMTesting/Testing/mitkDICOMTestingSanityTest.cpp b/Core/Code/Testing/DICOMTesting/Testing/mitkDICOMTestingSanityTest.cpp new file mode 100644 index 0000000000..eb4da0b568 --- /dev/null +++ b/Core/Code/Testing/DICOMTesting/Testing/mitkDICOMTestingSanityTest.cpp @@ -0,0 +1,54 @@ + + +#include "mitkTestDICOMLoading.h" +#include "mitkTestingMacros.h" + +int mitkDICOMTestingSanityTest(int argc, char** argv) +{ + MITK_TEST_BEGIN("DICOMTestingSanity") + + mitk::TestDICOMLoading loader; + mitk::TestDICOMLoading::StringContainer files; + + // adapt expectations depending on configuration + std::string configuration = mitk::DicomSeriesReader::GetConfigurationString(); + MITK_TEST_OUTPUT(<< "Configuration: " << configuration) + /* + MITK_TEST_CONDITION_REQUIRED( configuration.find( "GDCM_VERSION: 2." ) != std::string::npos, + "Expect at least GDCM version 2" ) + */ + + // load files from commandline + int numberOfExpectedImages = 0; + if (argc > 1) numberOfExpectedImages = atoi(argv[1]); + for (int arg = 2; arg < argc; ++arg) files.push_back( argv[arg] ); + + // verify all files are DICOM + for (mitk::TestDICOMLoading::StringContainer::const_iterator fileIter = files.begin(); + fileIter != files.end(); + ++fileIter) + { + MITK_TEST_CONDITION_REQUIRED( mitk::DicomSeriesReader::IsDicom(*fileIter) , *fileIter << " is recognized as loadable DICOM object" ) + + } + + // compare with expected number of images from commandline + mitk::TestDICOMLoading::ImageList images = loader.LoadFiles(files); + MITK_TEST_CONDITION_REQUIRED( images.size() == numberOfExpectedImages, "Loading " << files.size() + << " files from commandline results in " << numberOfExpectedImages + << " images (see test invocation)" ) + + // check dump equality (dumping image information must always equal itself) + for ( mitk::TestDICOMLoading::ImageList::const_iterator imageIter = images.begin(); + imageIter != images.end(); + ++imageIter ) + { + const mitk::Image* image = *imageIter; + MITK_TEST_CONDITION( loader.CompareImageInformationDumps( loader.DumpImageInformation(image), + loader.DumpImageInformation(image) ) == true, + "Image information dumping is able to reproduce its result." ) + } + + MITK_TEST_END() +} + diff --git a/Core/Code/Testing/DICOMTesting/VerifyDICOMMitkImageDump.cpp b/Core/Code/Testing/DICOMTesting/VerifyDICOMMitkImageDump.cpp new file mode 100644 index 0000000000..cd4ba9a06a --- /dev/null +++ b/Core/Code/Testing/DICOMTesting/VerifyDICOMMitkImageDump.cpp @@ -0,0 +1,31 @@ + +#include "mitkTestDICOMLoading.h" + +int main(int argc, char** argv) +{ + /** + Loads a list of DICOM images, compares generated mitk::Images against stored references. + + first argument: file with reference dumps + following arguments: file names to load + */ + mitk::TestDICOMLoading loader; + mitk::TestDICOMLoading::StringContainer files; + + // TODO load reference dumps + + for (int arg = 2; arg < argc; ++arg) files.push_back( argv[arg] ); + + mitk::TestDICOMLoading::ImageList images = loader.LoadFiles(files); + + unsigned int imageCounter(0); + for ( mitk::TestDICOMLoading::ImageList::const_iterator imageIter = images.begin(); + imageIter != images.end(); + ++imageIter ) + { + std::string imageDump = loader.DumpImageInformation( *imageIter ); + + // TODO compare against reference + } +} + diff --git a/Core/Code/Testing/DICOMTesting/files.cmake b/Core/Code/Testing/DICOMTesting/files.cmake new file mode 100644 index 0000000000..f6fd6ff9d6 --- /dev/null +++ b/Core/Code/Testing/DICOMTesting/files.cmake @@ -0,0 +1,4 @@ + +SET(CPP_FILES + mitkTestDICOMLoading.cpp +) diff --git a/Core/Code/Testing/DICOMTesting/mitkTestDICOMLoading.cpp b/Core/Code/Testing/DICOMTesting/mitkTestDICOMLoading.cpp new file mode 100644 index 0000000000..7bf5d72949 --- /dev/null +++ b/Core/Code/Testing/DICOMTesting/mitkTestDICOMLoading.cpp @@ -0,0 +1,299 @@ +#define MBILOG_ENABLE_DEBUG + +#include "mitkTestDICOMLoading.h" + +#include + +mitk::TestDICOMLoading::TestDICOMLoading() +{ + MITK_INFO << "TestDICOMLoading()"; +} + +void mitk::TestDICOMLoading::SetDefaultLocale() +{ + // remember old locale only once + if (m_PreviousCLocale == NULL) + { + m_PreviousCLocale = setlocale(LC_NUMERIC, NULL); + + // set to "C" + setlocale(LC_NUMERIC, "C"); + + m_PreviousCppLocale = std::cin.getloc(); + + std::locale l( "C" ); + std::cin.imbue(l); + std::cout.imbue(l); + } +} + +void mitk::TestDICOMLoading::ResetUserLocale() +{ + if (m_PreviousCLocale) + { + setlocale(LC_NUMERIC, m_PreviousCLocale); + + std::cin.imbue(m_PreviousCppLocale); + std::cout.imbue(m_PreviousCppLocale); + + m_PreviousCLocale = NULL; + } +} + + + +mitk::TestDICOMLoading::ImageList mitk::TestDICOMLoading::LoadFiles( const StringContainer& files ) +{ + for (StringContainer::const_iterator iter = files.begin(); + iter != files.end(); + ++iter) + { + MITK_DEBUG << "File " << *iter; + } + + StringContainer sortedFiles = DicomSeriesReader::SortSeriesSlices( files ); + + DataNode::Pointer node = DicomSeriesReader::LoadDicomSeries( sortedFiles ); + + ImageList result; + + if (node.IsNotNull()) + { + Image::Pointer image = dynamic_cast( node->GetData() ); + + result.push_back( image ); + } + else + { + } + + return result; +} + +// add a line to stringstream result (see DumpImageInformation +#define DumpLine(field, data) DumpILine(0, field, data) + +// add an indented(!) line to stringstream result (see DumpImageInformation +#define DumpILine(indent, field, data) \ +{ \ + std::string DumpLine_INDENT; DumpLine_INDENT.resize(indent, ' ' ); \ + result << DumpLine_INDENT << field << ": " << data << "\n"; \ +} + +std::string +mitk::TestDICOMLoading::DumpImageInformation( const Image* image ) +{ + std::stringstream result; + + if (image == NULL) return result.str(); + + SetDefaultLocale(); + + // basic image data + DumpLine( "Pixeltype", image->GetPixelType().GetTypeId()->name() ); + DumpLine( "BitsPerPixel", image->GetPixelType().GetBpe() ); + DumpLine( "Dimension", image->GetDimension() ); + + result << "Dimensions: "; + for (unsigned int dim = 0; dim < image->GetDimension(); ++dim) + result << image->GetDimension(dim) << " "; + result << "\n"; + + // geometry data + result << "Geometry: \n"; + Geometry3D* geometry = image->GetGeometry(); + if (geometry) + { + AffineTransform3D* transform = geometry->GetIndexToWorldTransform(); + if (transform) + { + result << " " << "Matrix: "; + const AffineTransform3D::MatrixType& matrix = transform->GetMatrix(); + for (unsigned int i = 0; i < 3; ++i) + for (unsigned int j = 0; j < 3; ++j) + result << matrix[i][j] << " "; + result << "\n"; + + result << " " << "Offset: "; + const AffineTransform3D::OutputVectorType& offset = transform->GetOffset(); + for (unsigned int i = 0; i < 3; ++i) + result << offset[i] << " "; + result << "\n"; + + result << " " << "Center: "; + const AffineTransform3D::InputPointType& center = transform->GetCenter(); + for (unsigned int i = 0; i < 3; ++i) + result << center[i] << " "; + result << "\n"; + + result << " " << "Translation: "; + const AffineTransform3D::OutputVectorType& translation = transform->GetTranslation(); + for (unsigned int i = 0; i < 3; ++i) + result << translation[i] << " "; + result << "\n"; + + result << " " << "Scale: "; + const double* scale = transform->GetScale(); + for (unsigned int i = 0; i < 3; ++i) + result << scale[i] << " "; + result << "\n"; + + result << " " << "Origin: "; + const Point3D& origin = geometry->GetOrigin(); + for (unsigned int i = 0; i < 3; ++i) + result << origin[i] << " "; + result << "\n"; + + result << " " << "Spacing: "; + const Vector3D& spacing = geometry->GetSpacing(); + for (unsigned int i = 0; i < 3; ++i) + result << spacing[i] << " "; + result << "\n"; + + result << " " << "TimeBounds: "; + const TimeBounds timeBounds = geometry->GetTimeBounds(); + for (unsigned int i = 0; i < 2; ++i) + result << timeBounds[i] << " "; + result << "\n"; + + + } + } + + ResetUserLocale(); + + MITK_DEBUG << "\n----------------------------------------\n" + << result.str() + << "----------------------------------------\n"; + + return result.str(); +} + +bool +mitk::TestDICOMLoading::CompareSpacedValueFields( const std::string& reference, + const std::string& test, + double eps ) +{ + // TODO this should better do a real comparison and tolerate float differences up to 'eps' + + return reference == test; +} + +bool +mitk::TestDICOMLoading::CompareImageInformationDumps( const std::string& referenceDump, + const std::string& testDump ) +{ + KeyValueMap reference = ParseDump(referenceDump); + KeyValueMap test = ParseDump(testDump); + + bool testResult(true); + + // verify all expected values + for (KeyValueMap::const_iterator refIter = reference.begin(); + refIter != reference.end(); + ++refIter) + { + const std::string& refKey = refIter->first; + const std::string& refValue = refIter->second; + + if ( reference.find(refKey) != reference.end() ) + { + const std::string& testValue = test[refKey]; + + testResult &= CompareSpacedValueFields( refValue, testValue ); + } + else + { + MITK_ERROR << "Reference dump contains a key'" << refKey << "' (value '" << refValue << "')." ; + MITK_ERROR << "This key is expected to be generated for tests (but was not). Most probably you need to update your test data."; + return false; + } + } + + // now check test dump does not contain any additional keys + for (KeyValueMap::const_iterator testIter = test.begin(); + testIter != test.end(); + ++testIter) + { + const std::string& key = testIter->first; + const std::string& value = testIter->second; + + if ( reference.find(key) == reference.end() ) + { + MITK_ERROR << "Test dump contains an unexpected key'" << key << "' (value '" << value << "')." ; + MITK_ERROR << "This key is not expected. Most probably you need to update your test data."; + return false; + } + } + + return testResult; +} + +mitk::TestDICOMLoading::KeyValueMap +mitk::TestDICOMLoading::ParseDump( const std::string& dump ) +{ + KeyValueMap parsedResult; + + std::string shredder(dump); + + std::stack surroundingKeys; + + std::stack expectedIndents; + expectedIndents.push(0); + + while (true) + { + std::string::size_type newLinePos = shredder.find( '\n' ); + if (newLinePos == std::string::npos) break; + + std::string line = shredder.substr( 0, newLinePos ); + shredder = shredder.erase( 0, newLinePos+1 ); + + MITK_DEBUG << "Line: '" << line << "'"; + + std::string::size_type keyPosition = line.find_first_not_of( ' ' ); + std::string::size_type colonPosition = line.find( ':' ); + + std::string key = line.substr(keyPosition, colonPosition - keyPosition); + std::string::size_type firstSpacePosition = key.find_first_of(" "); + if (firstSpacePosition != std::string::npos) + { + key.erase(firstSpacePosition); + } + + if ( keyPosition > expectedIndents.top() ) + { + // more indent than before + expectedIndents.push(keyPosition); + } + else if (keyPosition == expectedIndents.top() ) + { + if (!surroundingKeys.empty()) + { + surroundingKeys.pop(); // last of same length + } + } + else + { + // less indent than before + do expectedIndents.pop(); + while (expectedIndents.top() != keyPosition); // unwind until current indent is found + } + + if (!surroundingKeys.empty()) + { + key = surroundingKeys.top() + "." + key; // construct current key name + } + + surroundingKeys.push(key); // this is the new embracing key + + std::string value = line.substr(colonPosition+1); + + MITK_DEBUG << " Key: '" << key << "' value '" << value << "'" ; + + parsedResult[key] = value; // store parsing result + } + + return parsedResult; +} + diff --git a/Core/Code/Testing/DICOMTesting/mitkTestDICOMLoading.h b/Core/Code/Testing/DICOMTesting/mitkTestDICOMLoading.h new file mode 100644 index 0000000000..833adc0c57 --- /dev/null +++ b/Core/Code/Testing/DICOMTesting/mitkTestDICOMLoading.h @@ -0,0 +1,60 @@ +#ifndef mitkTestDICOMLoading_h +#define mitkTestDICOMLoading_h + +#include "mitkDicomSeriesReader.h" + +namespace mitk +{ + +class TestDICOMLoading +{ + public: + + typedef DicomSeriesReader::StringContainer StringContainer; + typedef std::list NodeList; + typedef std::list ImageList; + + TestDICOMLoading(); + + ImageList + LoadFiles( const StringContainer& files ); + + /** + \brief Dump relevant image information for later comparison. + \sa CompareImageInformationDumps + */ + std::string + DumpImageInformation( const Image* image ); + + /** + \brief Compare two image information dumps. + \return true, if dumps are sufficiently equal (see parameters) + \sa DumpImageInformation + */ + bool + CompareImageInformationDumps( const std::string& reference, + const std::string& test ); + + private: + + typedef std::map KeyValueMap; + + void SetDefaultLocale(); + + void ResetUserLocale(); + + KeyValueMap ParseDump( const std::string& dump ); + + bool CompareSpacedValueFields( const std::string& reference, + const std::string& test, + double eps = mitk::eps ); + + const char* m_PreviousCLocale; + std::locale m_PreviousCppLocale; + +}; + +} + +#endif +