diff --git a/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp b/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp index f4695678ee..3b94acf8a2 100644 --- a/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp +++ b/Modules/ImageStatistics/Testing/mitkImageStatisticsCalculatorTest.cpp @@ -1,1836 +1,1836 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkImageStatisticsCalculator.h" #include #include #include #include #include #include #include #include #include #include #include #include /** * \brief Test class for mitkImageStatisticsCalculator * * This test covers: * - instantiation of an ImageStatisticsCalculator class * - correctness of statistics when using PlanarFigures for masking */ class mitkImageStatisticsCalculatorTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkImageStatisticsCalculatorTestSuite); MITK_TEST(TestUninitializedImage); MITK_TEST(TestCase1); MITK_TEST(TestCase2); MITK_TEST(TestCase3); MITK_TEST(TestCase4); MITK_TEST(TestCase5); MITK_TEST(TestCase6); MITK_TEST(TestCase7); MITK_TEST(TestCase8); MITK_TEST(TestCase9); MITK_TEST(TestCase10); MITK_TEST(TestCase11); MITK_TEST(TestCase12); MITK_TEST(TestImageMaskingEmpty); MITK_TEST(TestImageMaskingNonEmpty); MITK_TEST(TestRecomputeOnModifiedMask); MITK_TEST(TestPic3DStatistics); MITK_TEST(TestPic3DAxialPlanarFigureMaskStatistics); MITK_TEST(TestPic3DSagittalPlanarFigureMaskStatistics); MITK_TEST(TestPic3DCoronalPlanarFigureMaskStatistics); MITK_TEST(TestPic3DImageMaskStatistics_label1); MITK_TEST(TestPic3DImageMaskStatistics_label2); MITK_TEST(TestPic3DIgnorePixelValueMaskStatistics); MITK_TEST(TestPic3DSecondaryMaskStatistics); MITK_TEST(TestUS4DCylStatistics_time1); MITK_TEST(TestUS4DCylAxialPlanarFigureMaskStatistics_time1); MITK_TEST(TestUS4DCylSagittalPlanarFigureMaskStatistics_time1); MITK_TEST(TestUS4DCylCoronalPlanarFigureMaskStatistics_time1); MITK_TEST(TestUS4DCylImageMaskStatistics_time1_label_1); MITK_TEST(TestUS4DCylImageMaskStatistics_time2_label_1); MITK_TEST(TestUS4DCylImageMaskStatistics_time1_label_2); MITK_TEST(TestUS4DCylIgnorePixelValueMaskStatistics_time1); MITK_TEST(TestUS4DCylSecondaryMaskStatistics_time1); CPPUNIT_TEST_SUITE_END(); public: void setUp() override; void tearDown() override; void TestUninitializedImage(); void TestCase1(); void TestCase2(); void TestCase3(); void TestCase4(); void TestCase5(); void TestCase6(); void TestCase7(); void TestCase8(); void TestCase9(); void TestCase10(); void TestCase11(); void TestCase12(); void TestImageMaskingEmpty(); void TestImageMaskingNonEmpty(); void TestRecomputeOnModifiedMask(); void TestPic3DStatistics(); void TestPic3DAxialPlanarFigureMaskStatistics(); void TestPic3DSagittalPlanarFigureMaskStatistics(); void TestPic3DCoronalPlanarFigureMaskStatistics(); void TestPic3DImageMaskStatistics_label1(); void TestPic3DImageMaskStatistics_label2(); void TestPic3DIgnorePixelValueMaskStatistics(); void TestPic3DSecondaryMaskStatistics(); void TestUS4DCylStatistics_time1(); void TestUS4DCylAxialPlanarFigureMaskStatistics_time1(); void TestUS4DCylSagittalPlanarFigureMaskStatistics_time1(); void TestUS4DCylCoronalPlanarFigureMaskStatistics_time1(); void TestUS4DCylImageMaskStatistics_time1_label_1(); void TestUS4DCylImageMaskStatistics_time2_label_1(); void TestUS4DCylImageMaskStatistics_time1_label_2(); void TestUS4DCylIgnorePixelValueMaskStatistics_time1(); void TestUS4DCylSecondaryMaskStatistics_time1(); void TestDifferentNBinsForHistogramStatistics(); void TestDifferentBinSizeForHistogramStatistic(); void TestSwitchFromBinSizeToNBins(); void TestSwitchFromNBinsToBinSize(); private: mitk::Image::ConstPointer m_TestImage; mitk::Image::ConstPointer m_Pic3DImage; mitk::Image::Pointer m_Pic3DImageMask; mitk::Image::Pointer m_Pic3DImageMask2; mitk::PlanarFigure::Pointer m_Pic3DPlanarFigureAxial; mitk::PlanarFigure::Pointer m_Pic3DPlanarFigureSagittal; mitk::PlanarFigure::Pointer m_Pic3DPlanarFigureCoronal; mitk::Image::ConstPointer m_US4DImage; mitk::Image::Pointer m_US4DImageMask; mitk::Image::Pointer m_US4DImageMask2; mitk::PlanarFigure::Pointer m_US4DPlanarFigureAxial; mitk::PlanarFigure::Pointer m_US4DPlanarFigureSagittal; mitk::PlanarFigure::Pointer m_US4DPlanarFigureCoronal; mitk::PlaneGeometry::Pointer m_Geometry; // calculate statistics for the given image and planarpolygon const mitk::ImageStatisticsContainer::Pointer ComputeStatistics( mitk::Image::ConstPointer image, mitk::PlanarFigure::Pointer polygon ); // calculate statistics for the given image and mask const mitk::ImageStatisticsContainer::Pointer ComputeStatistics(mitk::Image::ConstPointer image, mitk::Image::Pointer image_mask ); // universal function to calculate statistics const mitk::ImageStatisticsContainer::Pointer ComputeStatisticsNew(mitk::Image::ConstPointer image, mitk::MaskGenerator::Pointer maskGen=nullptr, mitk::MaskGenerator::Pointer secondardMaskGen=nullptr, unsigned short label=1); - void VerifyStatistics(mitk::ImageStatisticsContainer::StatisticsObject stats, + void VerifyStatistics(mitk::ImageStatisticsContainer::ImageStatisticsObject stats, double testMean, double testSD, double testMedian=0); - void VerifyStatistics(mitk::ImageStatisticsContainer::StatisticsObject stats, + void VerifyStatistics(mitk::ImageStatisticsContainer::ImageStatisticsObject stats, unsigned long N, double mean, double MPP, double median, double skewness, double kurtosis, double uniformity, double UPP, double variance, double stdev, double min, double max, double RMS, double entropy, vnl_vector minIndex, vnl_vector maxIndex); }; void mitkImageStatisticsCalculatorTestSuite::tearDown() { m_TestImage = nullptr; m_Pic3DImage = nullptr; m_Pic3DImageMask = nullptr; m_Pic3DImageMask2 = nullptr; m_Pic3DPlanarFigureAxial = nullptr; m_Pic3DPlanarFigureSagittal = nullptr; m_Pic3DPlanarFigureCoronal = nullptr; m_US4DImage = nullptr; m_US4DImageMask = nullptr; m_US4DImageMask2 = nullptr; m_US4DPlanarFigureAxial = nullptr; m_US4DPlanarFigureSagittal = nullptr; m_US4DPlanarFigureCoronal = nullptr; m_Geometry = nullptr; } void mitkImageStatisticsCalculatorTestSuite::setUp() { std::string filename = this->GetTestDataFilePath("ImageStatisticsTestData/testimage.dcm"); std::string Pic3DFile = this->GetTestDataFilePath("Pic3D.nrrd"); std::string Pic3DImageMaskFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3D-labels.nrrd"); std::string Pic3DImageMaskFile2 = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3D-labels2.nrrd"); std::string Pic3DAxialPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3DAxialPlanarFigure.pf"); std::string Pic3DSagittalPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3DSagittalPlanarFigure.pf"); std::string Pic3DCoronalPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/Pic3DCoronalPlanarFigure.pf"); std::string US4DFile = this->GetTestDataFilePath("US4DCyl.nrrd"); std::string US4DImageMaskFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4D-labels.nrrd"); std::string US4DImageMaskFile2 = this->GetTestDataFilePath("ImageStatisticsTestData/US4D-labels2.nrrd"); std::string US4DAxialPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4DAxialPlanarFigure.pf"); std::string US4DSagittalPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4DSagittalPlanarFigure.pf"); std::string US4DCoronalPlanarFigureFile = this->GetTestDataFilePath("ImageStatisticsTestData/US4DCoronalPlanarFigure.pf"); if (filename.empty() || Pic3DFile.empty() || Pic3DImageMaskFile.empty() || Pic3DAxialPlanarFigureFile.empty() || Pic3DSagittalPlanarFigureFile.empty() || Pic3DCoronalPlanarFigureFile.empty() || US4DFile.empty() || US4DImageMaskFile.empty() || US4DAxialPlanarFigureFile.empty() || US4DSagittalPlanarFigureFile.empty() || US4DCoronalPlanarFigureFile.empty()) { MITK_TEST_FAILED_MSG( << "Could not find test file" ) } MITK_TEST_OUTPUT(<< "Loading test image '" << filename << "'") m_TestImage = mitk::IOUtil::Load(filename); MITK_TEST_CONDITION_REQUIRED( m_TestImage.IsNotNull(), "Loaded an mitk::Image" ); m_Geometry = m_TestImage->GetSlicedGeometry()->GetPlaneGeometry(0); MITK_TEST_CONDITION_REQUIRED( m_Geometry.IsNotNull(), "Getting image geometry" ); m_Pic3DImage = mitk::IOUtil::Load(Pic3DFile); MITK_TEST_CONDITION_REQUIRED( m_Pic3DImage.IsNotNull(), "Loaded Pic3D" ); m_Pic3DImageMask = mitk::IOUtil::Load(Pic3DImageMaskFile); MITK_TEST_CONDITION_REQUIRED( m_Pic3DImageMask.IsNotNull(), "Loaded Pic3D image mask" ); m_Pic3DImageMask2 = mitk::IOUtil::Load(Pic3DImageMaskFile2); MITK_TEST_CONDITION_REQUIRED( m_Pic3DImageMask2.IsNotNull(), "Loaded Pic3D image secondary mask" ); m_Pic3DPlanarFigureAxial = mitk::IOUtil::Load(Pic3DAxialPlanarFigureFile); MITK_TEST_CONDITION_REQUIRED( m_Pic3DPlanarFigureAxial.IsNotNull(), "Loaded Pic3D axial planarFigure" ); m_Pic3DPlanarFigureSagittal = mitk::IOUtil::Load(Pic3DSagittalPlanarFigureFile); MITK_TEST_CONDITION_REQUIRED( m_Pic3DPlanarFigureSagittal.IsNotNull(), "Loaded Pic3D sagittal planarFigure" ); m_Pic3DPlanarFigureCoronal = mitk::IOUtil::Load(Pic3DCoronalPlanarFigureFile); MITK_TEST_CONDITION_REQUIRED( m_Pic3DPlanarFigureCoronal.IsNotNull(), "Loaded Pic3D coronal planarFigure" ); m_US4DImage = mitk::IOUtil::Load(US4DFile); MITK_TEST_CONDITION_REQUIRED( m_US4DImage.IsNotNull(), "Loaded US4D" ); m_US4DImageMask = mitk::IOUtil::Load(US4DImageMaskFile); MITK_TEST_CONDITION_REQUIRED( m_US4DImageMask.IsNotNull(), "Loaded US4D image mask" ); m_US4DImageMask2 = mitk::IOUtil::Load(US4DImageMaskFile2); MITK_TEST_CONDITION_REQUIRED( m_US4DImageMask2.IsNotNull(), "Loaded US4D image mask2" ); m_US4DPlanarFigureAxial = mitk::IOUtil::Load(US4DAxialPlanarFigureFile); MITK_TEST_CONDITION_REQUIRED( m_US4DPlanarFigureAxial.IsNotNull(), "Loaded US4D axial planarFigure" ); m_US4DPlanarFigureSagittal = mitk::IOUtil::Load(US4DSagittalPlanarFigureFile); MITK_TEST_CONDITION_REQUIRED( m_US4DPlanarFigureSagittal.IsNotNull(), "Loaded US4D sagittal planarFigure" ); m_US4DPlanarFigureCoronal = mitk::IOUtil::Load(US4DCoronalPlanarFigureFile); MITK_TEST_CONDITION_REQUIRED( m_US4DPlanarFigureCoronal.IsNotNull(), "Loaded US4D coronal planarFigure" ); } void mitkImageStatisticsCalculatorTestSuite::TestCase1() { /***************************** * one whole white pixel * -> mean of 255 expected ******************************/ MITK_INFO << std::endl << "Test case 1:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 10.5 ; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 10.5; pnt4[1] = 4.5; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); auto statisticsContainer = ComputeStatistics(m_TestImage, figure1.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 255.0, 0.0, 255.0); } void mitkImageStatisticsCalculatorTestSuite::TestCase2() { /***************************** * half pixel in x-direction (white) * -> mean of 255 expected ******************************/ MITK_INFO << std::endl << "Test case 2:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 10.0 ; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 10.0; pnt4[1] = 4.5; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); auto statisticsContainer = ComputeStatistics(m_TestImage, figure1.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 255.0, 0.0, 255.0); } void mitkImageStatisticsCalculatorTestSuite::TestCase3() { /***************************** * half pixel in diagonal-direction (white) * -> mean of 255 expected ******************************/ MITK_INFO << std::endl << "Test case 3:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 10.5 ; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); figure1->GetPolyLine(0); auto statisticsContainer = ComputeStatistics(m_TestImage, figure1.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 255.0, 0.0, 255.0); } void mitkImageStatisticsCalculatorTestSuite::TestCase4() { /***************************** * one pixel (white) + 2 half pixels (white) + 1 half pixel (black) * -> mean of 191.25 expected ******************************/ MITK_INFO << std::endl << "Test case 4:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 1.1; pnt1[1] = 1.1; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 2.0; pnt2[1] = 2.0; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 3.0; pnt3[1] = 1.0; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 2.0; pnt4[1] = 0.0; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); auto statisticsContainer = ComputeStatistics(m_TestImage, figure1.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 191.25, 110.41, 242.250); } void mitkImageStatisticsCalculatorTestSuite::TestCase5() { /***************************** * whole pixel (white) + half pixel (gray) in x-direction * -> mean of 191.5 expected ******************************/ MITK_INFO << std::endl << "Test case 5:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.0; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.5; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 11.0; pnt4[1] = 4.5; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); auto statisticsContainer = ComputeStatistics(m_TestImage, figure1.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 191.50, 63.50, 134.340); } void mitkImageStatisticsCalculatorTestSuite::TestCase6() { /***************************** * quarter pixel (black) + whole pixel (white) + half pixel (gray) in x-direction * -> mean of 191.5 expected ******************************/ MITK_INFO << std::endl << "Test case 6:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.0; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.25; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.25; pnt3[1] = 4.5; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 11.0; pnt4[1] = 4.5; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); auto statisticsContainer = ComputeStatistics(m_TestImage, figure1.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 191.5, 63.50, 134.340); } void mitkImageStatisticsCalculatorTestSuite::TestCase7() { /***************************** * half pixel (black) + whole pixel (white) + half pixel (gray) in x-direction * -> mean of 127.66 expected ******************************/ MITK_INFO << std::endl << "Test case 7:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure1 = mitk::PlanarPolygon::New(); figure1->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.0; pnt1[1] = 3.5; figure1->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.0; pnt2[1] = 3.5; figure1->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 9.0; pnt3[1] = 4.0; figure1->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 11.0; pnt4[1] = 4.0; figure1->SetControlPoint( 3, pnt4, true ); figure1->GetPolyLine(0); auto statisticsContainer = ComputeStatistics(m_TestImage, figure1.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 127.66, 104.1, 140.250); } void mitkImageStatisticsCalculatorTestSuite::TestCase8() { /***************************** * whole pixel (gray) * -> mean of 128 expected ******************************/ MITK_INFO << std::endl << "Test case 8:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.5; pnt1[1] = 10.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 11.5; pnt2[1] = 11.5; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 12.5; pnt3[1] = 11.5; figure2->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 12.5; pnt4[1] = 10.5; figure2->SetControlPoint( 3, pnt4, true ); figure2->GetPolyLine(0); auto statisticsContainer = ComputeStatistics(m_TestImage, figure2.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 128.0, 0.0, 128.0); } void mitkImageStatisticsCalculatorTestSuite::TestCase9() { /***************************** * whole pixel (gray) + half pixel (white) in y-direction * -> mean of 191.5 expected ******************************/ MITK_INFO << std::endl << "Test case 9:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.5; pnt1[1] = 10.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 11.5; pnt2[1] = 12.0; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 12.5; pnt3[1] = 12.0; figure2->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 12.5; pnt4[1] = 10.5; figure2->SetControlPoint( 3, pnt4, true ); figure2->GetPolyLine(0); auto statisticsContainer = ComputeStatistics(m_TestImage, figure2.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 191.5, 63.50, 134.340); } void mitkImageStatisticsCalculatorTestSuite::TestCase10() { /***************************** * 2 whole pixel (white) + 2 whole pixel (black) in y-direction * -> mean of 127.66 expected ******************************/ MITK_INFO << std::endl << "Test case 10:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 11.5; pnt1[1] = 10.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 11.5; pnt2[1] = 13.5; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 12.5; pnt3[1] = 13.5; figure2->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 12.5; pnt4[1] = 10.5; figure2->SetControlPoint( 3, pnt4, true ); figure2->GetPolyLine(0); auto statisticsContainer = ComputeStatistics(m_TestImage, figure2.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 127.66, 104.1, 140.250); } void mitkImageStatisticsCalculatorTestSuite::TestCase11() { /***************************** * 9 whole pixels (white) + 3 half pixels (white) * + 3 whole pixel (black) [ + 3 slightly less than half pixels (black)] * -> mean of 204.0 expected ******************************/ MITK_INFO << std::endl << "Test case 11:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 0.5; pnt1[1] = 0.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 3.5; pnt2[1] = 3.5; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 8.4999; pnt3[1] = 3.5; figure2->SetControlPoint( 2, pnt3, true ); mitk::Point2D pnt4; pnt4[0] = 5.4999; pnt4[1] = 0.5; figure2->SetControlPoint( 3, pnt4, true ); figure2->GetPolyLine(0); auto statisticsContainer = ComputeStatistics(m_TestImage, figure2.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 204.0, 102.00, 242.250); } void mitkImageStatisticsCalculatorTestSuite::TestCase12() { /***************************** * half pixel (white) + whole pixel (white) + half pixel (black) * -> mean of 212.66 expected ******************************/ MITK_INFO << std::endl << "Test case 12:-----------------------------------------------------------------------------------"; mitk::PlanarPolygon::Pointer figure2 = mitk::PlanarPolygon::New(); figure2->SetPlaneGeometry( m_Geometry ); mitk::Point2D pnt1; pnt1[0] = 9.5; pnt1[1] = 0.5; figure2->PlaceFigure( pnt1 ); mitk::Point2D pnt2; pnt2[0] = 9.5; pnt2[1] = 2.5; figure2->SetControlPoint( 1, pnt2, true ); mitk::Point2D pnt3; pnt3[0] = 11.5; pnt3[1] = 2.5; figure2->SetControlPoint( 2, pnt3, true ); figure2->GetPolyLine(0); auto statisticsContainer = ComputeStatistics(m_TestImage, figure2.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 212.66, 59.860, 248.640); } void mitkImageStatisticsCalculatorTestSuite::TestImageMaskingEmpty() { MITK_INFO << std::endl << "TestImageMaskingEmpty:-----------------------------------------------------------------------------------"; mitk::Image::Pointer mask_image = mitk::ImageGenerator::GenerateImageFromReference( m_TestImage->Clone(), 0 ); auto statisticsContainer = ComputeStatistics( m_TestImage, mask_image ); // test if no statisticsContainer for timestep 0 exists MITK_TEST_CONDITION(!statisticsContainer->TimeStepExists(0), "No statistics for TimeStep 0 does exist."); MITK_TEST_FOR_EXCEPTION(mitk::Exception, statisticsContainer->GetStatisticsForTimeStep(0)); } void mitkImageStatisticsCalculatorTestSuite::TestImageMaskingNonEmpty() { MITK_INFO << std::endl << "TestImageMaskingNonEmpty:-----------------------------------------------------------------------------------"; mitk::Image::Pointer mask_image = mitk::ImageGenerator::GenerateImageFromReference( m_TestImage->Clone(), 0 ); // activate voxel in the mask image if (mask_image->GetDimension() == 3) { std::vector< itk::Index<3U> > activated_indices; itk::Index<3U> index = { { 10, 8, 0 } }; activated_indices.push_back(index); index[0] = 9; index[1] = 8; index[2] = 0; activated_indices.push_back(index); index[0] = 9; index[1] = 7; index[2] = 0; activated_indices.push_back(index); index[0] = 10; index[1] = 7; index[2] = 0; activated_indices.push_back(index); std::vector< itk::Index<3U> >::const_iterator indexIter = activated_indices.begin(); mitk::ImagePixelWriteAccessor< unsigned char, 3> writeAccess(mask_image); while (indexIter != activated_indices.end()) { writeAccess.SetPixelByIndex((*indexIter++), 1); } } if (mask_image->GetDimension() == 4) { std::vector< itk::Index<4U> > activated_indices; itk::Index<4U> index = { { 10, 8, 0, 0 } }; activated_indices.push_back(index); index[0] = 9; index[1] = 8; index[2] = 0; index[3] = 0; activated_indices.push_back(index); index[0] = 9; index[1] = 7; index[2] = 0; index[3] = 0; activated_indices.push_back(index); index[0] = 10; index[1] = 7; index[2] = 0; index[3] = 0; activated_indices.push_back(index); std::vector< itk::Index<4U> >::const_iterator indexIter = activated_indices.begin(); mitk::ImagePixelWriteAccessor< unsigned char, 4> writeAccess(mask_image); while (indexIter != activated_indices.end()) { writeAccess.SetPixelByIndex((*indexIter++), 1); } } auto statisticsContainer = ComputeStatistics(m_TestImage, mask_image); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 127.5, 127.5, 12.750); } void mitkImageStatisticsCalculatorTestSuite::TestRecomputeOnModifiedMask() { MITK_INFO << std::endl << "TestRecomputeOnModifiedMask:-----------------------------------------------------------------------------------"; mitk::Image::Pointer mask_image = mitk::ImageGenerator::GenerateImageFromReference( m_TestImage->Clone(), 0 ); mitk::ImageStatisticsCalculator::Pointer statisticsCalculator = mitk::ImageStatisticsCalculator::New(); statisticsCalculator->SetInputImage( m_TestImage ); mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New(); imgMaskGen->SetImageMask(mask_image); statisticsCalculator->SetMask(imgMaskGen.GetPointer()); auto statisticsContainer = statisticsCalculator->GetStatistics(); // test if no statisticsContainer for timestep 0 exists MITK_TEST_CONDITION(!statisticsContainer->TimeStepExists(0), "No statistics for TimeStep 0 does exist."); MITK_TEST_FOR_EXCEPTION(mitk::Exception, statisticsContainer->GetStatisticsForTimeStep(0)); // activate voxel in the mask image if (mask_image->GetDimension() == 3) { itk::Index<3U> test_index = { { 11, 8, 0 } }; mitk::ImagePixelWriteAccessor< unsigned char, 3> writeAccess(mask_image); writeAccess.SetPixelByIndex(test_index, 1); } if (mask_image->GetDimension() == 4) { itk::Index<4U> test_index = { { 11, 8, 0, 0 } }; mitk::ImagePixelWriteAccessor< unsigned char, 4> writeAccess(mask_image); writeAccess.SetPixelByIndex(test_index, 1); } //Delete if T25625 has been resolved imgMaskGen->Modified(); statisticsContainer = statisticsCalculator->GetStatistics(); MITK_TEST_CONDITION(statisticsContainer->TimeStepExists(0), "Statistics for TimeStep 0 does exist."); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); this->VerifyStatistics(statisticsObjectTimestep0, 128.0, 0.0, 128.0); auto numberOfVoxels = statisticsObjectTimestep0.GetValueConverted( mitk::ImageStatisticsConstants::NUMBEROFVOXELS()); MITK_TEST_CONDITION(numberOfVoxels == 1, "Calculated mask voxel count '" << numberOfVoxels << "' is equal to the desired value '" << 1 << "'" ); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DStatistics() { MITK_INFO << std::endl << "Test plain Pic3D:-----------------------------------------------------------------------------------"; unsigned long expected_N = 3211264; double expected_mean = -365.80015345982144; double expected_MPP = 111.80226129535752; double expected_median = -105.16000366210938; double expected_skewness = -0.26976612134147004; double expected_kurtosis = 1.4655017209571437; double expected_uniformity = 0.06087994379480554; double expected_UPP = 0.011227934437026977; double expected_variance = 224036.80150510342; double expected_standarddev = 473.32525973700518; double expected_min = -1023; double expected_max = 1361; double expected_RMS = 598.20276978323352; double expected_entropy = 4.6727423654570357; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 0; expected_minIndex[1] = 0; expected_minIndex[2] = 0; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 139; expected_maxIndex[1] = 182; expected_maxIndex[2] = 43; auto statisticsContainer = ComputeStatisticsNew(m_Pic3DImage); auto statisticsObject = statisticsContainer->GetStatisticsForTimeStep(0); VerifyStatistics(statisticsObject, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DAxialPlanarFigureMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D axial pf:-----------------------------------------------------------------------------------"; double expected_entropy = 5.6719817476387417; double expected_kurtosis = 5.8846935191205221; double expected_MPP = 230.43933685003768; double expected_max = 1206; double expected_mean = 182.30282131661443; double expected_median = 95.970001220703125; double expected_min = -156; unsigned long expected_N = 3190; double expected_RMS = 301.93844376702253; double expected_skewness = 1.6400489794326298; double expected_standarddev = 240.69172225993557; double expected_UPP = 0.024889790784288681; double expected_uniformity = 0.027579917650180332; double expected_variance = 57932.505164453964; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 156; expected_minIndex[1] = 133; expected_minIndex[2] = 24; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 125; expected_maxIndex[1] = 167; expected_maxIndex[2] = 24; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_Pic3DImage); pfMaskGen->SetPlanarFigure(m_Pic3DPlanarFigureAxial); auto statisticsContainer = ComputeStatisticsNew(m_Pic3DImage, pfMaskGen.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); VerifyStatistics(statisticsObjectTimestep0, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DSagittalPlanarFigureMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D sagittal pf:-----------------------------------------------------------------------------------"; double expected_entropy = 5.6051911962074286; double expected_kurtosis = 6.5814062739142338; double expected_MPP = 249.03202846975088; double expected_max = 1240; double expected_mean = 233.93602693602693; double expected_median = 174.9849853515625; double expected_min = -83; unsigned long expected_N = 1188; double expected_RMS = 332.03230188484594; double expected_skewness = 1.7489809015501814; double expected_standarddev = 235.62551813489128; double expected_UPP = 0.026837539253364174; double expected_uniformity = 0.027346982734188126; double expected_variance = 55519.384796335973; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 128; expected_minIndex[1] = 119; expected_minIndex[2] = 22; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 128; expected_maxIndex[1] = 167; expected_maxIndex[2] = 22; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_Pic3DImage); pfMaskGen->SetPlanarFigure(m_Pic3DPlanarFigureSagittal); auto statisticsContainer = ComputeStatisticsNew(m_Pic3DImage, pfMaskGen.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); VerifyStatistics(statisticsObjectTimestep0, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DCoronalPlanarFigureMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D coronal pf:-----------------------------------------------------------------------------------"; double expected_entropy = 6.0677398647867449; double expected_kurtosis = 1.6242929941303372; double expected_MPP = 76.649350649350652; double expected_max = 156; double expected_mean = -482.14807692307693; double expected_median = -660.07501220703125; double expected_min = -897; unsigned long expected_N = 520; double expected_RMS = 595.09446729069839; double expected_skewness = 0.51691492278851858; double expected_standarddev = 348.81321207686312; double expected_UPP = 0.0021560650887573964; double expected_uniformity = 0.020295857988165685; double expected_variance = 121670.6569193787; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 217; expected_minIndex[1] = 127; expected_minIndex[2] = 43; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 209; expected_maxIndex[1] = 127; expected_maxIndex[2] = 39; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_Pic3DImage); pfMaskGen->SetPlanarFigure(m_Pic3DPlanarFigureCoronal); auto statisticsContainer = ComputeStatisticsNew(m_Pic3DImage, pfMaskGen.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); VerifyStatistics(statisticsObjectTimestep0, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DImageMaskStatistics_label1() { MITK_INFO << std::endl << "Test Pic3D image mask label 1 pf:-----------------------------------------------------------------------------------"; double expected_entropy = 5.695858251095868; double expected_kurtosis = 4.2728827997815717; double expected_MPP = 413.52408256880733; double expected_max = 1206; double expected_mean = 413.52408256880733; double expected_median = 324; double expected_min = 6; unsigned long expected_N = 872; double expected_RMS = 472.02024695145235; double expected_skewness = 1.3396074364415382; double expected_standarddev = 227.59821323493802; double expected_UPP = 0.029758648261930806; double expected_uniformity = 0.029758648261930806; double expected_variance = 51800.946667736309; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 135; expected_minIndex[1] = 158; expected_minIndex[2] = 24; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 125; expected_maxIndex[1] = 167; expected_maxIndex[2] = 24; mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New(); imgMaskGen->SetImageMask(m_Pic3DImageMask); imgMaskGen->SetInputImage(m_Pic3DImage); imgMaskGen->SetTimeStep(0); auto statisticsContainer = ComputeStatisticsNew(m_Pic3DImage, imgMaskGen.GetPointer(), nullptr, 1); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); VerifyStatistics(statisticsObjectTimestep0, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DImageMaskStatistics_label2() { MITK_INFO << std::endl << "Test Pic3D image mask label 2 pf:-----------------------------------------------------------------------------------"; double expected_entropy = 4.3685781901212764; double expected_kurtosis = 9.7999112757587934; double expected_MPP = -nan(""); double expected_max = -145; double expected_mean = -897.92833876221493; double expected_median = -969.16499900817871; double expected_min = -1008; unsigned long expected_N = 307; double expected_RMS = 913.01496468179471; double expected_skewness = 2.6658524648889736; double expected_standarddev = 165.29072623903585; double expected_UPP = 0; double expected_uniformity = 0.087544695434434425; double expected_variance = 27321.024180627897; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 170; expected_minIndex[1] = 60; expected_minIndex[2] = 24; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 173; expected_maxIndex[1] = 57; expected_maxIndex[2] = 24; mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New(); imgMaskGen->SetImageMask(m_Pic3DImageMask); imgMaskGen->SetInputImage(m_Pic3DImage); imgMaskGen->SetTimeStep(0); auto statisticsContainer = ComputeStatisticsNew(m_Pic3DImage, imgMaskGen.GetPointer(), nullptr, 2); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); VerifyStatistics(statisticsObjectTimestep0, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DIgnorePixelValueMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D ignore zero pixels:-----------------------------------------------------------------------------------"; double expected_entropy = 4.671045011438645; double expected_kurtosis = 1.4638176488404484; double expected_MPP = 111.80226129535752; double expected_max = 1361; double expected_mean = -366.48547402877585; double expected_median = -105.16000366210938; double expected_min = -1023; unsigned long expected_N = 3205259; double expected_RMS = 598.76286909522139; double expected_skewness = -0.26648854845130782; double expected_standarddev = 473.50329537717545; double expected_UPP = 0.011270044547276429; double expected_uniformity = 0.061029773286547614; double expected_variance = 224205.37073304466; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 0; expected_minIndex[1] = 0; expected_minIndex[2] = 0; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 139; expected_maxIndex[1] = 182; expected_maxIndex[2] = 43; mitk::IgnorePixelMaskGenerator::Pointer ignPixelValMask = mitk::IgnorePixelMaskGenerator::New(); ignPixelValMask->SetInputImage(m_Pic3DImage); ignPixelValMask->SetIgnoredPixelValue(0); ignPixelValMask->SetTimeStep(0); auto statisticsContainer = ComputeStatisticsNew(m_Pic3DImage, ignPixelValMask.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); VerifyStatistics(statisticsObjectTimestep0, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestPic3DSecondaryMaskStatistics() { MITK_INFO << std::endl << "Test Pic3D ignore zero pixels AND Image mask 2:-----------------------------------------------------------------------------------"; double expected_entropy = 5.9741637167320176; double expected_kurtosis = 3.490663358061596; double expected_MPP = 332.43534482758622; double expected_max = 1206; double expected_mean = 320.63333333333333; double expected_median = 265.06500244140625; double expected_min = -57; unsigned long expected_N = 720; double expected_RMS = 433.57749531594055; double expected_skewness = 1.1047775627624981; double expected_standarddev = 291.86248474238687; double expected_UPP = 0.020628858024691339; double expected_uniformity = 0.021377314814814797; double expected_variance = 85183.710000000006; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 116; expected_minIndex[1] = 170; expected_minIndex[2] = 24; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 125; expected_maxIndex[1] = 167; expected_maxIndex[2] = 24; mitk::IgnorePixelMaskGenerator::Pointer ignPixelValMask = mitk::IgnorePixelMaskGenerator::New(); ignPixelValMask->SetInputImage(m_Pic3DImage); ignPixelValMask->SetIgnoredPixelValue(0); ignPixelValMask->SetTimeStep(0); mitk::ImageMaskGenerator::Pointer imgMaskGen2 = mitk::ImageMaskGenerator::New(); imgMaskGen2->SetImageMask(m_Pic3DImageMask2); imgMaskGen2->SetInputImage(m_Pic3DImage); imgMaskGen2->SetTimeStep(0); auto statisticsContainer = ComputeStatisticsNew(m_Pic3DImage, imgMaskGen2.GetPointer(), ignPixelValMask.GetPointer()); auto statisticsObjectTimestep0 = statisticsContainer->GetStatisticsForTimeStep(0); VerifyStatistics(statisticsObjectTimestep0, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylStatistics_time1() { MITK_INFO << std::endl << "Test plain US4D timeStep1:-----------------------------------------------------------------------------------"; double expected_entropy = 4.8272774900452502; double expected_kurtosis = 6.1336513352934432; double expected_MPP = 53.395358640738536; double expected_max = 199; double expected_mean = 35.771298153622375; double expected_median = 20.894999504089355; double expected_min = 0; unsigned long expected_N = 3409920; double expected_RMS = 59.244523377028408; double expected_skewness = 1.8734292240015058; double expected_standarddev = 47.226346233600559; double expected_UPP = 0.12098731125004937; double expected_uniformity = 0.12098731125004937; double expected_variance = 2230.3277785759178; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 0; expected_minIndex[1] = 0; expected_minIndex[2] = 0; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 268; expected_maxIndex[1] = 101; expected_maxIndex[2] = 0; auto statisticsContainer = ComputeStatisticsNew(m_US4DImage); auto statisticsObjectTimestep1 = statisticsContainer->GetStatisticsForTimeStep(1); VerifyStatistics(statisticsObjectTimestep1, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylAxialPlanarFigureMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4D axial pf timeStep1:-----------------------------------------------------------------------------------"; double expected_entropy = 6.218151288002292; double expected_kurtosis = 1.7322676370242023; double expected_MPP = 121.11663807890223; double expected_max = 199; double expected_mean = 121.11663807890223; double expected_median = 120.14999771118164; double expected_min = 9; unsigned long expected_N = 2332; double expected_RMS = 134.41895158590751; double expected_skewness = -0.1454808104597369; double expected_standarddev = 58.30278317472294; double expected_UPP = 0.021354765820606133; double expected_uniformity = 0.021354765820606133; double expected_variance = 3399.214525918756; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 129; expected_minIndex[1] = 131; expected_minIndex[2] = 19; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 126; expected_maxIndex[1] = 137; expected_maxIndex[2] = 19; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_US4DImage); pfMaskGen->SetPlanarFigure(m_US4DPlanarFigureAxial); auto statisticsContainer = ComputeStatisticsNew(m_US4DImage, pfMaskGen.GetPointer()); auto statisticsObjectTimestep1 = statisticsContainer->GetStatisticsForTimeStep(1); VerifyStatistics(statisticsObjectTimestep1, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylSagittalPlanarFigureMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4D sagittal pf timeStep1:-----------------------------------------------------------------------------------"; double expected_entropy = 5.2003987046387508; double expected_kurtosis = 2.7574491062430142; double expected_MPP = 26.212534059945504; double expected_max = 59; double expected_mean = 26.176870748299319; double expected_median = 26.254999160766602; double expected_min = 0; unsigned long expected_N = 735; double expected_RMS = 28.084905283121476; double expected_skewness = 0.18245181360752327; double expected_standarddev = 10.175133541567705; double expected_UPP = 0.032921467906890628; double expected_uniformity = 0.032921467906890628; double expected_variance = 103.53334258873615; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 147; expected_minIndex[1] = 94; expected_minIndex[2] = 21; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 147; expected_maxIndex[1] = 77; expected_maxIndex[2] = 24; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_US4DImage); pfMaskGen->SetPlanarFigure(m_US4DPlanarFigureSagittal); auto statisticsContainer = ComputeStatisticsNew(m_US4DImage, pfMaskGen.GetPointer()); auto statisticsObjectTimestep1 = statisticsContainer->GetStatisticsForTimeStep(1); VerifyStatistics(statisticsObjectTimestep1, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylCoronalPlanarFigureMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4D coronal pf timeStep1:-----------------------------------------------------------------------------------"; double expected_entropy = 5.8892941136639161; double expected_kurtosis = 4.6434920707409564; double expected_MPP = 55.486426346239433; double expected_max = 199; double expected_mean = 55.118479221927501; double expected_median = 36.815000534057617; double expected_min = 0; unsigned long expected_N = 2262; double expected_RMS = 71.98149752438627; double expected_skewness = 1.4988288344523237; double expected_standarddev = 46.29567187238105; double expected_UPP = 0.023286748110675673; double expected_uniformity = 0.023286748110675673; double expected_variance = 2143.2892341151742; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 214; expected_minIndex[1] = 169; expected_minIndex[2] = 10; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 99; expected_maxIndex[1] = 169; expected_maxIndex[2] = 17; mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_US4DImage); pfMaskGen->SetPlanarFigure(m_US4DPlanarFigureCoronal); auto statisticsContainer = ComputeStatisticsNew(m_US4DImage, pfMaskGen.GetPointer()); auto statisticsObjectTimestep1 = statisticsContainer->GetStatisticsForTimeStep(1); VerifyStatistics(statisticsObjectTimestep1, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylImageMaskStatistics_time1_label_1() { MITK_INFO << std::endl << "Test US4D image mask time 1 label 1:-----------------------------------------------------------------------------------"; double expected_entropy = 5.0082903903398677; double expected_kurtosis = 3.6266994778237809; double expected_MPP = 169.58938547486034; double expected_max = 199; double expected_mean = 169.58938547486034; double expected_median = 187.44000244140625; double expected_min = 63; unsigned long expected_N = 716; double expected_RMS = 173.09843164831432; double expected_skewness = -1.2248969838579555; double expected_standarddev = 34.677188083311712; double expected_UPP = 0.076601073624418703; double expected_uniformity = 0.076601073624418703; double expected_variance = 1202.5073733653758; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 82; expected_minIndex[1] = 158; expected_minIndex[2] = 19; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 126; expected_maxIndex[1] = 140; expected_maxIndex[2] = 19; mitk::ImageMaskGenerator::Pointer imgMask1 = mitk::ImageMaskGenerator::New(); imgMask1->SetInputImage(m_US4DImage); imgMask1->SetImageMask(m_US4DImageMask); auto statisticsContainer = ComputeStatisticsNew(m_US4DImage, imgMask1.GetPointer(), nullptr, 1); auto statisticsObjectTimestep1 = statisticsContainer->GetStatisticsForTimeStep(1); VerifyStatistics(statisticsObjectTimestep1, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylImageMaskStatistics_time2_label_1() { MITK_INFO << std::endl << "Test US4D image mask time 2 label 1:-----------------------------------------------------------------------------------"; double expected_entropy = 5.1857604214916506; double expected_kurtosis = 3.0692303858330683; double expected_MPP = 167.97194163860831; double expected_max = 199; double expected_mean = 167.97194163860831; double expected_median = 184.39499664306641; double expected_min = 72; unsigned long expected_N = 891; double expected_RMS = 171.67986611998634; double expected_skewness = -1.1221651136259736; double expected_standarddev = 35.488071983870803; double expected_UPP = 0.063124070232188439; double expected_uniformity = 0.063124070232188439; double expected_variance = 1259.4032531323958; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 103; expected_minIndex[1] = 212; expected_minIndex[2] = 19; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 102; expected_maxIndex[1] = 168; expected_maxIndex[2] = 19; mitk::ImageMaskGenerator::Pointer imgMask1 = mitk::ImageMaskGenerator::New(); imgMask1->SetInputImage(m_US4DImage); imgMask1->SetImageMask(m_US4DImageMask); auto statisticsContainer = ComputeStatisticsNew(m_US4DImage, imgMask1.GetPointer(), nullptr, 1); auto statisticsObjectTimestep2 = statisticsContainer->GetStatisticsForTimeStep(2); VerifyStatistics(statisticsObjectTimestep2, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylImageMaskStatistics_time1_label_2() { MITK_INFO << std::endl << "Test US4D image mask time 1 label 2:-----------------------------------------------------------------------------------"; double expected_entropy = 5.0822234230119001; double expected_kurtosis = 2.4346603343623747; double expected_MPP = 20.733626373626375; double expected_max = 46; double expected_mean = 20.624836029733274; double expected_median = 20.010000228881836; double expected_min = 0; unsigned long expected_N = 2287; double expected_RMS = 22.508347574573804; double expected_skewness = 0.13837218490626488; double expected_standarddev = 9.0134260569684965; double expected_UPP = 0.034783970308787; double expected_uniformity = 0.034783970308787; double expected_variance = 81.241849284438644; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 178; expected_minIndex[1] = 76; expected_minIndex[2] = 19; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 198; expected_maxIndex[1] = 90; expected_maxIndex[2] = 19; mitk::ImageMaskGenerator::Pointer imgMask1 = mitk::ImageMaskGenerator::New(); imgMask1->SetInputImage(m_US4DImage); imgMask1->SetImageMask(m_US4DImageMask); auto statisticsContainer = ComputeStatisticsNew(m_US4DImage, imgMask1.GetPointer(), nullptr, 2); auto statisticsObjectTimestep1 = statisticsContainer->GetStatisticsForTimeStep(1); VerifyStatistics(statisticsObjectTimestep1, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylIgnorePixelValueMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4D ignore zero pixels:-----------------------------------------------------------------------------------"; double expected_entropy = 5.8609813848087962; double expected_kurtosis = 4.7556214582883651; double expected_MPP = 53.395358640738536; double expected_max = 199; double expected_mean = 53.395358640738536; double expected_median = 35.649999618530273; double expected_min = 1; unsigned long expected_N = 2284417; double expected_RMS = 72.382339046507084; double expected_skewness = 1.588289859859108; double expected_standarddev = 48.868585834566694; double expected_UPP = 0.023927063695115193; double expected_uniformity = 0.023927063695115193; double expected_variance = 2388.1386814704128; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 187; expected_minIndex[1] = 19; expected_minIndex[2] = 0; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 268; expected_maxIndex[1] = 101; expected_maxIndex[2] = 0; mitk::IgnorePixelMaskGenerator::Pointer ignPixelValMask = mitk::IgnorePixelMaskGenerator::New(); ignPixelValMask->SetInputImage(m_US4DImage); ignPixelValMask->SetIgnoredPixelValue(0); ignPixelValMask->SetTimeStep(1); auto statisticsContainer = ComputeStatisticsNew(m_US4DImage, ignPixelValMask.GetPointer()); auto statisticsObjectTimestep1 = statisticsContainer->GetStatisticsForTimeStep(1); VerifyStatistics(statisticsObjectTimestep1, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } void mitkImageStatisticsCalculatorTestSuite::TestUS4DCylSecondaryMaskStatistics_time1() { MITK_INFO << std::endl << "Test US4d ignore zero pixels AND Image mask 2:-----------------------------------------------------------------------------------"; double expected_entropy = 4.9955858614274558; double expected_kurtosis = 17.471042803365179; double expected_MPP = 32.791403286978507; double expected_max = 199; double expected_mean = 32.791403286978507; double expected_median = 25.75; double expected_min = 1; unsigned long expected_N = 17402; double expected_RMS = 42.776697859745241; double expected_skewness = 3.3991813038552596; double expected_standarddev = 27.469433016621732; double expected_UPP = 0.043040554251756687; double expected_uniformity = 0.043040554251756687; double expected_variance = 754.56975025466807; vnl_vector expected_minIndex; expected_minIndex.set_size(3); expected_minIndex[0] = 177; expected_minIndex[1] = 27; expected_minIndex[2] = 36; vnl_vector expected_maxIndex; expected_maxIndex.set_size(3); expected_maxIndex[0] = 109; expected_maxIndex[1] = 116; expected_maxIndex[2] = 36; mitk::IgnorePixelMaskGenerator::Pointer ignPixelValMask = mitk::IgnorePixelMaskGenerator::New(); ignPixelValMask->SetInputImage(m_US4DImage); ignPixelValMask->SetIgnoredPixelValue(0); mitk::ImageMaskGenerator::Pointer imgMaskGen2 = mitk::ImageMaskGenerator::New(); imgMaskGen2->SetImageMask(m_US4DImageMask2); imgMaskGen2->SetInputImage(m_US4DImage); auto statisticsContainer = ComputeStatisticsNew(m_US4DImage, imgMaskGen2.GetPointer(), ignPixelValMask.GetPointer()); auto statisticsObjectTimestep1 = statisticsContainer->GetStatisticsForTimeStep(1); VerifyStatistics(statisticsObjectTimestep1, expected_N, expected_mean, expected_MPP, expected_median, expected_skewness, expected_kurtosis, expected_uniformity, expected_UPP, expected_variance, expected_standarddev, expected_min, expected_max, expected_RMS, expected_entropy, expected_minIndex, expected_maxIndex); } const mitk::ImageStatisticsContainer::Pointer mitkImageStatisticsCalculatorTestSuite::ComputeStatistics( mitk::Image::ConstPointer image, mitk::PlanarFigure::Pointer polygon ) { mitk::ImageStatisticsCalculator::Pointer statisticsCalculator = mitk::ImageStatisticsCalculator::New(); statisticsCalculator->SetInputImage( image ); statisticsCalculator->SetNBinsForHistogramStatistics(10); mitk::PlanarFigureMaskGenerator::Pointer planFigMaskGen = mitk::PlanarFigureMaskGenerator::New(); planFigMaskGen->SetInputImage(image); planFigMaskGen->SetPlanarFigure(polygon); statisticsCalculator->SetMask(planFigMaskGen.GetPointer()); try { return statisticsCalculator->GetStatistics(); } catch( ... ) { return nullptr; } } const mitk::ImageStatisticsContainer::Pointer mitkImageStatisticsCalculatorTestSuite::ComputeStatistics(mitk::Image::ConstPointer image, mitk::Image::Pointer image_mask ) { mitk::ImageStatisticsCalculator::Pointer statisticsCalculator = mitk::ImageStatisticsCalculator::New(); statisticsCalculator->SetInputImage(image); statisticsCalculator->SetNBinsForHistogramStatistics(10); mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New(); imgMaskGen->SetImageMask(image_mask); statisticsCalculator->SetMask(imgMaskGen.GetPointer()); return statisticsCalculator->GetStatistics(); } const mitk::ImageStatisticsContainer::Pointer mitkImageStatisticsCalculatorTestSuite::ComputeStatisticsNew(mitk::Image::ConstPointer image, mitk::MaskGenerator::Pointer maskGen, mitk::MaskGenerator::Pointer secondardMaskGen, unsigned short label) { mitk::ImageStatisticsCalculator::Pointer imgStatCalc = mitk::ImageStatisticsCalculator::New(); imgStatCalc->SetInputImage(image); if (maskGen.IsNotNull()) { imgStatCalc->SetMask(maskGen.GetPointer()); if (secondardMaskGen.IsNotNull()) { imgStatCalc->SetSecondaryMask(secondardMaskGen.GetPointer()); } } return imgStatCalc->GetStatistics(label); } -void mitkImageStatisticsCalculatorTestSuite::VerifyStatistics(mitk::ImageStatisticsContainer::StatisticsObject stats, +void mitkImageStatisticsCalculatorTestSuite::VerifyStatistics(mitk::ImageStatisticsContainer::ImageStatisticsObject stats, double testMean, double testSD, double testMedian) { auto mean = stats.GetValueConverted(mitk::ImageStatisticsConstants::MEAN()); int tmpMean = mean * 100; double calculatedMean = tmpMean / 100.0; MITK_TEST_CONDITION( calculatedMean == testMean, "Calculated mean grayvalue '" << calculatedMean << "' is equal to the desired value '" << testMean << "'" ); auto standardDeviation = stats.GetValueConverted(mitk::ImageStatisticsConstants::STANDARDDEVIATION()); int tmpSD = standardDeviation * 100; double calculatedSD = tmpSD / 100.0; MITK_TEST_CONDITION( calculatedSD == testSD, "Calculated grayvalue sd '" << calculatedSD << "' is equal to the desired value '" << testSD <<"'" ); auto median = stats.GetValueConverted(mitk::ImageStatisticsConstants::MEDIAN()); int tmpMedian = median * 100; double calculatedMedian = tmpMedian / 100.0; MITK_TEST_CONDITION( testMedian == calculatedMedian, "Calculated median grayvalue '" << calculatedMedian << "' is equal to the desired value '" << testMedian << "'"); } -void mitkImageStatisticsCalculatorTestSuite::VerifyStatistics(mitk::ImageStatisticsContainer::StatisticsObject stats, +void mitkImageStatisticsCalculatorTestSuite::VerifyStatistics(mitk::ImageStatisticsContainer::ImageStatisticsObject stats, unsigned long N, double mean, double MPP, double median, double skewness, double kurtosis, double uniformity, double UPP, double variance, double stdev, double min, double max, double RMS, double entropy, vnl_vector minIndex, vnl_vector maxIndex) { auto numberOfVoxelsObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::NUMBEROFVOXELS()); auto meanObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::MEAN()); auto mppObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::MPP()); auto medianObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::MEDIAN()); auto skewnessObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::SKEWNESS()); auto kurtosisObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::KURTOSIS()); auto uniformityObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::UNIFORMITY()); auto uppObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::UPP()); auto varianceObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::VARIANCE()); auto standardDeviationObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::STANDARDDEVIATION()); auto minObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::MINIMUM()); auto maxObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::MAXIMUM()); auto rmsObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::RMS()); auto entropyObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::ENTROPY()); auto minIndexObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::MINIMUMPOSITION()); auto maxIndexObject = stats.GetValueConverted(mitk::ImageStatisticsConstants::MAXIMUMPOSITION()); MITK_TEST_CONDITION(numberOfVoxelsObject - N == 0, "calculated N: " << numberOfVoxelsObject << " expected N: " << N); MITK_TEST_CONDITION(std::abs(meanObject - mean) < mitk::eps, "calculated mean: " << meanObject << " expected mean: " << mean); // in one test case MPP is None because the roi has no positive pixels if (!std::isnan(mppObject)) { MITK_TEST_CONDITION(std::abs(mppObject - MPP) < mitk::eps, "calculated MPP: " << mppObject << " expected MPP: " << MPP); } MITK_TEST_CONDITION(std::abs(medianObject - median) < mitk::eps, "calculated median: " << medianObject << " expected median: " << median); MITK_TEST_CONDITION(std::abs(skewnessObject - skewness) < mitk::eps, "calculated skewness: " << skewnessObject << " expected skewness: " << skewness); MITK_TEST_CONDITION(std::abs(kurtosisObject - kurtosis) < mitk::eps, "calculated kurtosis: " << kurtosisObject << " expected kurtosis: " << kurtosis); MITK_TEST_CONDITION(std::abs(uniformityObject - uniformity) < mitk::eps, "calculated uniformity: " << uniformityObject << " expected uniformity: " << uniformity); MITK_TEST_CONDITION(std::abs(uppObject - UPP) < mitk::eps, "calculated UPP: " << uppObject << " expected UPP: " << UPP); MITK_TEST_CONDITION(std::abs(varianceObject - variance) < mitk::eps, "calculated variance: " << varianceObject << " expected variance: " << variance); MITK_TEST_CONDITION(std::abs(standardDeviationObject - stdev) < mitk::eps, "calculated stdev: " << standardDeviationObject << " expected stdev: " << stdev); MITK_TEST_CONDITION(std::abs(minObject - min) < mitk::eps, "calculated min: " << minObject << " expected min: " << min); MITK_TEST_CONDITION(std::abs(maxObject - max) < mitk::eps, "calculated max: " << maxObject << " expected max: " << max); MITK_TEST_CONDITION(std::abs(rmsObject - RMS) < mitk::eps, "calculated RMS: " << rmsObject << " expected RMS: " << RMS); MITK_TEST_CONDITION(std::abs(entropyObject - entropy) < mitk::eps, "calculated entropy: " << entropyObject << " expected entropy: " << entropy); for (unsigned int i = 0; i < minIndex.size(); ++i) { MITK_TEST_CONDITION(std::abs(minIndexObject[i] - minIndex[i]) < mitk::eps, "minIndex [" << i << "] = " << minIndexObject[i] << " expected: " << minIndex[i]); } for (unsigned int i = 0; i < maxIndex.size(); ++i) { MITK_TEST_CONDITION(std::abs(maxIndexObject[i] - maxIndex[i]) < mitk::eps, "maxIndex [" << i << "] = " << maxIndexObject[i] << " expected: " << maxIndex[i]); } } void mitkImageStatisticsCalculatorTestSuite::TestUninitializedImage() { /***************************** * loading uninitialized image to datastorage ******************************/ MITK_INFO << std::endl << "Test uninitialized image: -----------------------------------------------------------------------------------"; MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::Exception) mitk::Image::Pointer image = mitk::Image::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(image); mitk::ImageStatisticsCalculator::Pointer is = mitk::ImageStatisticsCalculator::New(); is->GetStatistics(); MITK_TEST_FOR_EXCEPTION_END(mitk::Exception) } MITK_TEST_SUITE_REGISTRATION(mitkImageStatisticsCalculator) diff --git a/Modules/ImageStatistics/Testing/mitkImageStatisticsHotspotTest.cpp b/Modules/ImageStatistics/Testing/mitkImageStatisticsHotspotTest.cpp index 925f2f6210..2c527c2df0 100644 --- a/Modules/ImageStatistics/Testing/mitkImageStatisticsHotspotTest.cpp +++ b/Modules/ImageStatistics/Testing/mitkImageStatisticsHotspotTest.cpp @@ -1,653 +1,653 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkImageStatisticsCalculator.h" #include "itkMultiGaussianImageSource.h" #include "mitkTestingMacros.h" #include "mitkImageCast.h" #include #include #include #include #include #include #include /** \section hotspotCalculationTestCases Testcases To see the different Hotspot-Testcases have a look at the \ref hotspottestdoc. Note from an intensive session of checking the test results: - itk::MultiGaussianImageSource needs a review - the test idea is ok, but the combination of XML files for parameters and MultiGaussianImageSource has serious flaws - the XML file should contain exactly the parameters that MultiGaussianImageSource requires - in contrast, now the XML file mentions index coordinates for gaussian centers while the MultiGaussianImageSource expects world coordinates - this requires a transformation (index * spacing assuming no rotation) that was actually broken until recently */ struct mitkImageStatisticsHotspotTestClass { /** \brief Test parameters for one test case. Describes all aspects of a single test case: - parameters to generate a test image - parameters of a ROI that describes where to calculate statistics - expected statistics results */ struct Parameters { public: // XML-Tag /** \brief XML-Tag "image-rows": size of x-dimension */ int m_ImageRows; /** \brief XML-Tag "image-columns": size of y-dimension */ int m_ImageColumns; /** \brief XML-Tag "image-slices": size of z-dimension */ int m_ImageSlices; /** \brief XML-Tag "numberOfGaussians": number of used gauss-functions */ int m_NumberOfGaussian; /** \brief XML-Tags "spacingX", "spacingY", "spacingZ": spacing of image in every direction */ double m_Spacing[3]; /** \brief XML-Tag "entireHotSpotInImage" */ unsigned int m_EntireHotspotInImage; // XML-Tag /** \brief XML-Tag "centerIndexX: gaussian parameter \warning This parameter READS the centerIndexX parameter from file and is THEN MISUSED to calculate some position in world coordinates, so we require double. */ std::vector m_CenterX; /** \brief XML-Tag "centerIndexY: gaussian parameter \warning This parameter READS the centerIndexX parameter from file and is THEN MISUSED to calculate some position in world coordinates, so we require double. */ std::vector m_CenterY; /** \brief XML-Tag "centerIndexZ: gaussian parameter \warning This parameter READS the centerIndexX parameter from file and is THEN MISUSED to calculate some position in world coordinates, so we require double. */ std::vector m_CenterZ; /** \brief XML-Tag "deviationX: gaussian parameter */ std::vector m_SigmaX; /** \brief XML-Tag "deviationY: gaussian parameter */ std::vector m_SigmaY; /** \brief XML-Tag "deviationZ: gaussian parameter */ std::vector m_SigmaZ; /** \brief XML-Tag "altitude: gaussian parameter */ std::vector m_Altitude; // XML-Tag /** \brief XML-Tag "numberOfLabels": number of different labels which appear in the mask */ unsigned int m_NumberOfLabels; /** \brief XML-Tag "hotspotRadiusInMM": radius of hotspot */ double m_HotspotRadiusInMM; // XML-Tag /** \brief XML-Tag "maximumSizeX": maximum position of ROI in x-dimension */ vnl_vector m_MaxIndexX; /** \brief XML-Tag "minimumSizeX": minimum position of ROI in x-dimension */ vnl_vector m_MinIndexX; /** \brief XML-Tag "maximumSizeX": maximum position of ROI in y-dimension */ vnl_vector m_MaxIndexY; /** \brief XML-Tag "minimumSizeX": minimum position of ROI in y-dimension */ vnl_vector m_MinIndexY; /** \brief XML-Tag "maximumSizeX": maximum position of ROI in z-dimension */ vnl_vector m_MaxIndexZ; /** \brief XML-Tag "minimumSizeX": minimum position of ROI in z-dimension */ vnl_vector m_MinIndexZ; /** \brief XML-Tag "label": value of label */ vnl_vector m_Label; //XML-Tag /** \brief XML-Tag "minimum": minimum inside hotspot */ vnl_vector m_HotspotMin; /** \brief XML-Tag "maximum": maximum inside hotspot */ vnl_vector m_HotspotMax; /** \brief XML-Tag "mean": mean value of hotspot */ vnl_vector m_HotspotMean; /** \brief XML-Tag "maximumIndexX": x-coordinate of maximum-location inside hotspot */ vnl_vector m_HotspotMaxIndexX; /** \brief XML-Tag "maximumIndexX": y-coordinate of maximum-location inside hotspot */ vnl_vector m_HotspotMaxIndexY; /** \brief XML-Tag "maximumIndexX": z-coordinate of maximum-location inside hotspot */ vnl_vector m_HotspotMaxIndexZ; /** \brief XML-Tag "maximumIndexX": x-coordinate of maximum-location inside hotspot */ vnl_vector m_HotspotMinIndexX; /** \brief XML-Tag "maximumIndexX": y-coordinate of maximum-location inside hotspot */ vnl_vector m_HotspotMinIndexY; /** \brief XML-Tag "maximumIndexX": z-coordinate of maximum-location inside hotspot */ vnl_vector m_HotspotMinIndexZ; /** \brief XML-Tag "maximumIndexX": x-coordinate of hotspot-location */ vnl_vector m_HotspotIndexX; /** \brief XML-Tag "maximumIndexX": y-coordinate of hotspot-location */ vnl_vector m_HotspotIndexY; /** \brief XML-Tag "maximumIndexX": z-coordinate of hotspot-location */ vnl_vector m_HotspotIndexZ; }; /** \brief Find/Convert integer attribute in itk::DOMNode. */ static int GetIntegerAttribute(itk::DOMNode* domNode, const std::string& tag) { assert(domNode); MITK_TEST_CONDITION_REQUIRED( domNode->HasAttribute(tag), "Tag '" << tag << "' is defined in test parameters" ); std::string attributeValue = domNode->GetAttribute(tag); int resultValue; try { //MITK_TEST_OUTPUT( << "Converting tag value '" << attributeValue << "' for tag '" << tag << "' to integer"); std::stringstream(attributeValue) >> resultValue; return resultValue; } catch(std::exception& /*e*/) { MITK_TEST_CONDITION_REQUIRED(false, "Convert tag value '" << attributeValue << "' for tag '" << tag << "' to integer"); return 0; // just to satisfy compiler } } /** \brief Find/Convert double attribute in itk::DOMNode. */ static double GetDoubleAttribute(itk::DOMNode* domNode, const std::string& tag) { assert(domNode); MITK_TEST_CONDITION_REQUIRED( domNode->HasAttribute(tag), "Tag '" << tag << "' is defined in test parameters" ); std::string attributeValue = domNode->GetAttribute(tag); double resultValue; try { //MITK_TEST_OUTPUT( << "Converting tag value '" << attributeValue << "' for tag '" << tag << "' to double"); std::stringstream(attributeValue) >> resultValue; return resultValue; } catch(std::exception& /*e*/) { MITK_TEST_CONDITION_REQUIRED(false, "Convert tag value '" << attributeValue << "' for tag '" << tag << "' to double"); return 0.0; // just to satisfy compiler } } /** \brief Read XML file describing the test parameters. Reads XML file given in first commandline parameter in order to construct a Parameters structure. The XML file should be structurs as the following example, i.e. we describe the three test aspects of Parameters in four different tags, with all the details described as tag attributes. */ /** \verbatim \endverbatim */ static Parameters ParseParameters(int argc, char* argv[]) { MITK_TEST_CONDITION_REQUIRED(argc == 2, "Test is invoked with exactly 1 parameter (XML parameters file)"); MITK_INFO << "Reading parameters from file '" << argv[1] << "'"; std::string filename = argv[1]; Parameters result; itk::DOMNodeXMLReader::Pointer xmlReader = itk::DOMNodeXMLReader::New(); xmlReader->SetFileName( filename ); try { xmlReader->Update(); itk::DOMNode::Pointer domRoot = xmlReader->GetOutput(); typedef std::vector NodeList; NodeList testimages; domRoot->GetChildren("testimage", testimages); MITK_TEST_CONDITION_REQUIRED( testimages.size() == 1, "One test image defined" ) itk::DOMNode* testimage = testimages[0]; result.m_ImageRows = GetIntegerAttribute( testimage, "image-rows" ); result.m_ImageColumns = GetIntegerAttribute( testimage, "image-columns" ); result.m_ImageSlices = GetIntegerAttribute( testimage, "image-slices" ); result.m_NumberOfGaussian = GetIntegerAttribute( testimage, "numberOfGaussians" ); result.m_Spacing[0] = GetDoubleAttribute(testimage, "spacingX"); result.m_Spacing[1] = GetDoubleAttribute(testimage, "spacingY"); result.m_Spacing[2] = GetDoubleAttribute(testimage, "spacingZ"); result.m_EntireHotspotInImage = GetIntegerAttribute( testimage, "entireHotSpotInImage" ); MITK_TEST_OUTPUT( << "Read size parameters (x,y,z): " << result.m_ImageRows << "," << result.m_ImageColumns << "," << result.m_ImageSlices); MITK_TEST_OUTPUT( << "Read spacing parameters (x,y,z): " << result.m_Spacing[0] << "," << result.m_Spacing[1] << "," << result.m_Spacing[2]); NodeList gaussians; testimage->GetChildren("gaussian", gaussians); MITK_TEST_CONDITION_REQUIRED( gaussians.size() >= 1, "At least one gaussian is defined" ) result.m_CenterX.resize(result.m_NumberOfGaussian); result.m_CenterY.resize(result.m_NumberOfGaussian); result.m_CenterZ.resize(result.m_NumberOfGaussian); result.m_SigmaX.resize(result.m_NumberOfGaussian); result.m_SigmaY.resize(result.m_NumberOfGaussian); result.m_SigmaZ.resize(result.m_NumberOfGaussian); result.m_Altitude.resize(result.m_NumberOfGaussian); for(int i = 0; i < result.m_NumberOfGaussian ; ++i) { itk::DOMNode* gaussian = gaussians[i]; result.m_CenterX[i] = GetIntegerAttribute(gaussian, "centerIndexX"); result.m_CenterY[i] = GetIntegerAttribute(gaussian, "centerIndexY"); result.m_CenterZ[i] = GetIntegerAttribute(gaussian, "centerIndexZ"); result.m_SigmaX[i] = GetDoubleAttribute(gaussian, "deviationX"); result.m_SigmaY[i] = GetDoubleAttribute(gaussian, "deviationY"); result.m_SigmaZ[i] = GetDoubleAttribute(gaussian, "deviationZ"); result.m_Altitude[i] = GetDoubleAttribute(gaussian, "altitude"); result.m_CenterX[i] = result.m_CenterX[i] * result.m_Spacing[0]; result.m_CenterY[i] = result.m_CenterY[i] * result.m_Spacing[1]; result.m_CenterZ[i] = result.m_CenterZ[i] * result.m_Spacing[2]; result.m_SigmaX[i] = result.m_SigmaX[i] * result.m_Spacing[0]; result.m_SigmaY[i] = result.m_SigmaY[i] * result.m_Spacing[1]; result.m_SigmaZ[i] = result.m_SigmaZ[i] * result.m_Spacing[2]; } NodeList segmentations; domRoot->GetChildren("segmentation", segmentations); MITK_TEST_CONDITION_REQUIRED( segmentations.size() == 1, "One segmentation defined"); itk::DOMNode* segmentation = segmentations[0]; result.m_NumberOfLabels = GetIntegerAttribute(segmentation, "numberOfLabels"); result.m_HotspotRadiusInMM = GetDoubleAttribute(segmentation, "hotspotRadiusInMM"); // read ROI parameters, fill result structure NodeList rois; segmentation->GetChildren("roi", rois); MITK_TEST_CONDITION_REQUIRED( rois.size() >= 1, "At least one ROI defined" ) result.m_MaxIndexX.set_size(result.m_NumberOfLabels); result.m_MinIndexX.set_size(result.m_NumberOfLabels); result.m_MaxIndexY.set_size(result.m_NumberOfLabels); result.m_MinIndexY.set_size(result.m_NumberOfLabels); result.m_MaxIndexZ.set_size(result.m_NumberOfLabels); result.m_MinIndexZ.set_size(result.m_NumberOfLabels); result.m_Label.set_size(result.m_NumberOfLabels); for(unsigned int i = 0; i < rois.size(); ++i) { result.m_MaxIndexX[i] = GetIntegerAttribute(rois[i], "maximumIndexX"); result.m_MinIndexX[i] = GetIntegerAttribute(rois[i], "minimumIndexX"); result.m_MaxIndexY[i] = GetIntegerAttribute(rois[i], "maximumIndexY"); result.m_MinIndexY[i] = GetIntegerAttribute(rois[i], "minimumIndexY"); result.m_MaxIndexZ[i] = GetIntegerAttribute(rois[i], "maximumIndexZ"); result.m_MinIndexZ[i] = GetIntegerAttribute(rois[i], "minimumIndexZ"); result.m_Label[i] = GetIntegerAttribute(rois[i], "label"); } // read statistic parameters, fill result structure NodeList statistics; domRoot->GetChildren("statistic", statistics); MITK_TEST_CONDITION_REQUIRED( statistics.size() >= 1 , "At least one statistic defined" ) MITK_TEST_CONDITION_REQUIRED( statistics.size() == rois.size(), "Same number of rois and corresponding statistics defined"); result.m_HotspotMin.set_size(statistics.size()); result.m_HotspotMax.set_size(statistics.size()); result.m_HotspotMean.set_size(statistics.size()); result.m_HotspotMinIndexX.set_size(statistics.size()); result.m_HotspotMinIndexY.set_size(statistics.size()); result.m_HotspotMinIndexZ.set_size(statistics.size()); result.m_HotspotMaxIndexX.set_size(statistics.size()); result.m_HotspotMaxIndexY.set_size(statistics.size()); result.m_HotspotMaxIndexZ.set_size(statistics.size()); result.m_HotspotIndexX.set_size(statistics.size()); result.m_HotspotIndexY.set_size(statistics.size()); result.m_HotspotIndexZ.set_size(statistics.size()); for(unsigned int i = 0; i < statistics.size(); ++i) { result.m_HotspotMin[i] = GetDoubleAttribute(statistics[i], "minimum"); result.m_HotspotMax[i] = GetDoubleAttribute(statistics[i], "maximum"); result.m_HotspotMean[i] = GetDoubleAttribute(statistics[i], "mean"); result.m_HotspotMinIndexX[i] = GetIntegerAttribute(statistics[i], "minimumIndexX"); result.m_HotspotMinIndexY[i] = GetIntegerAttribute(statistics[i], "minimumIndexY"); result.m_HotspotMinIndexZ[i] = GetIntegerAttribute(statistics[i], "minimumIndexZ"); result.m_HotspotMaxIndexX[i] = GetIntegerAttribute(statistics[i], "maximumIndexX"); result.m_HotspotMaxIndexY[i] = GetIntegerAttribute(statistics[i], "maximumIndexY"); result.m_HotspotMaxIndexZ[i] = GetIntegerAttribute(statistics[i], "maximumIndexZ"); result.m_HotspotIndexX[i] = GetIntegerAttribute(statistics[i], "hotspotIndexX"); result.m_HotspotIndexY[i] = GetIntegerAttribute(statistics[i], "hotspotIndexY"); result.m_HotspotIndexZ[i] = GetIntegerAttribute(statistics[i], "hotspotIndexZ"); } } catch (std::exception& e) { MITK_TEST_CONDITION_REQUIRED(false, "Reading test parameters from XML file. Error message: " << e.what()); } return result; } /** \brief Generate an image that contains a couple of 3D gaussian distributions. Uses the given parameters to produce a test image using class MultiGaussianImageSource. */ static mitk::Image::Pointer BuildTestImage(const Parameters& testParameters) { mitk::Image::Pointer result; typedef double PixelType; const int Dimension = 3; typedef itk::Image ImageType; ImageType::Pointer image = ImageType::New(); typedef itk::MultiGaussianImageSource< ImageType > MultiGaussianImageSource; MultiGaussianImageSource::Pointer gaussianGenerator = MultiGaussianImageSource::New(); ImageType::SizeValueType size[3]; size[0] = testParameters.m_ImageColumns; size[1] = testParameters.m_ImageRows; size[2] = testParameters.m_ImageSlices; itk::MultiGaussianImageSource::VectorType centerXVec, centerYVec, centerZVec, sigmaXVec, sigmaYVec, sigmaZVec, altitudeVec; for(int i = 0; i < testParameters.m_NumberOfGaussian; ++i) { centerXVec.push_back(testParameters.m_CenterX[i]); centerYVec.push_back(testParameters.m_CenterY[i]); centerZVec.push_back(testParameters.m_CenterZ[i]); sigmaXVec.push_back(testParameters.m_SigmaX[i]); sigmaYVec.push_back(testParameters.m_SigmaY[i]); sigmaZVec.push_back(testParameters.m_SigmaZ[i]); altitudeVec.push_back(testParameters.m_Altitude[i]); } ImageType::SpacingType spacing; for( int i = 0; i < Dimension; ++i ) spacing[i] = testParameters.m_Spacing[i]; gaussianGenerator->SetSize( size ); gaussianGenerator->SetSpacing( spacing ); gaussianGenerator->SetRadius(testParameters.m_HotspotRadiusInMM); gaussianGenerator->SetNumberOfGausssians(testParameters.m_NumberOfGaussian); gaussianGenerator->AddGaussian(centerXVec, centerYVec, centerZVec, sigmaXVec, sigmaYVec, sigmaZVec, altitudeVec); gaussianGenerator->Update(); image = gaussianGenerator->GetOutput(); mitk::CastToMitkImage(image, result); return result; } /** \brief Calculates hotspot statistics for given test image and ROI parameters. Uses ImageStatisticsCalculator to find a hotspot in a defined ROI within the given image. */ - static mitk::ImageStatisticsContainer::StatisticsObject CalculateStatistics(mitk::Image* image, const Parameters& testParameters, unsigned int label) + static mitk::ImageStatisticsContainer::ImageStatisticsObject CalculateStatistics(mitk::Image* image, const Parameters& testParameters, unsigned int label) { const unsigned int Dimension = 3; typedef itk::Image MaskImageType; MaskImageType::Pointer mask = MaskImageType::New(); MaskImageType::SizeType size; MaskImageType::SpacingType spacing; MaskImageType::IndexType start; mitk::ImageStatisticsCalculator::Pointer statisticsCalculator = mitk::ImageStatisticsCalculator::New(); statisticsCalculator->SetInputImage(image); mitk::Image::Pointer mitkMaskImage; if((testParameters.m_MaxIndexX[label] > testParameters.m_MinIndexX[label] && testParameters.m_MinIndexX[label] >= 0) && (testParameters.m_MaxIndexY[label] > testParameters.m_MinIndexY[label] && testParameters.m_MinIndexY[label] >= 0) && (testParameters.m_MaxIndexZ[label] > testParameters.m_MinIndexZ[label] && testParameters.m_MinIndexZ[label] >= 0)) { for(unsigned int i = 0; i < Dimension; ++i) { start[i] = 0; spacing[i] = testParameters.m_Spacing[i]; } size[0] = testParameters.m_ImageColumns; size[1] = testParameters.m_ImageRows; size[2] = testParameters.m_ImageSlices; MaskImageType::RegionType region; region.SetIndex(start); region.SetSize(size); mask->SetSpacing(spacing); mask->SetRegions(region); mask->Allocate(); typedef itk::ImageRegionIteratorWithIndex MaskImageIteratorType; MaskImageIteratorType maskIt(mask, region); for(maskIt.GoToBegin(); !maskIt.IsAtEnd(); ++maskIt) { maskIt.Set(0); } for(unsigned int i = 0; i < testParameters.m_NumberOfLabels; ++i) { for(maskIt.GoToBegin(); !maskIt.IsAtEnd(); ++maskIt) { MaskImageType::IndexType index = maskIt.GetIndex(); if((index[0] >= testParameters.m_MinIndexX[i] && index[0] <= testParameters.m_MaxIndexX[i] ) && (index[1] >= testParameters.m_MinIndexY[i] && index[1] <= testParameters.m_MaxIndexY[i] ) && (index[2] >= testParameters.m_MinIndexZ[i] && index[2] <= testParameters.m_MaxIndexZ[i] )) { maskIt.Set(testParameters.m_Label[i]); } } } mitk::CastToMitkImage(mask, mitkMaskImage); mitk::ImageMaskGenerator::Pointer imgMaskGen = mitk::ImageMaskGenerator::New(); imgMaskGen->SetImageMask(mitkMaskImage); mitk::HotspotMaskGenerator::Pointer hotspotMaskGen = mitk::HotspotMaskGenerator::New(); hotspotMaskGen->SetInputImage(image); hotspotMaskGen->SetLabel(testParameters.m_Label[label]); hotspotMaskGen->SetMask(imgMaskGen.GetPointer()); hotspotMaskGen->SetHotspotRadiusInMM(testParameters.m_HotspotRadiusInMM); if(testParameters.m_EntireHotspotInImage == 1) { MITK_INFO << "Hotspot must be completly inside image"; hotspotMaskGen->SetHotspotMustBeCompletelyInsideImage(true); } else { MITK_INFO << "Hotspot must not be completly inside image"; hotspotMaskGen->SetHotspotMustBeCompletelyInsideImage(false); } statisticsCalculator->SetMask(hotspotMaskGen.GetPointer()); MITK_DEBUG << "Masking is set to hotspot+image mask"; } else { mitk::HotspotMaskGenerator::Pointer hotspotMaskGen = mitk::HotspotMaskGenerator::New(); hotspotMaskGen->SetInputImage(image); hotspotMaskGen->SetHotspotRadiusInMM(testParameters.m_HotspotRadiusInMM); if(testParameters.m_EntireHotspotInImage == 1) { MITK_INFO << "Hotspot must be completly inside image"; hotspotMaskGen->SetHotspotMustBeCompletelyInsideImage(true); } else { MITK_INFO << "Hotspot must not be completly inside image"; hotspotMaskGen->SetHotspotMustBeCompletelyInsideImage(false); } MITK_DEBUG << "Masking is set to hotspot only"; } return statisticsCalculator->GetStatistics()->GetStatisticsForTimeStep(0); } static void ValidateStatisticsItem(const std::string& label, double testvalue, double reference, double tolerance) { double diff = ::fabs(reference - testvalue); MITK_TEST_CONDITION( diff < tolerance, "'" << label << "' value close enough to reference value " "(value=" << testvalue << ", reference=" << reference << ", diff=" << diff << ")" ); } static void ValidateStatisticsItem(const std::string& label, const vnl_vector& testvalue, const vnl_vector& reference) { double diffX = ::fabs(double(testvalue[0] - reference[0])); double diffY = ::fabs(double(testvalue[1] - reference[1])); double diffZ = ::fabs(double(testvalue[2] - reference[2])); std::stringstream testPosition; testPosition << testvalue[0] << "," << testvalue[1] << "," << testvalue[2]; std::stringstream referencePosition; referencePosition << reference[0] << "," << reference[1] << "," << reference[2]; MITK_TEST_CONDITION( diffX < mitk::eps && diffY < mitk::eps && diffZ < mitk::eps, "'" << label << "' close enough to reference value " << "(value=[" << testPosition.str() << "]," << " reference=[" << referencePosition.str() << "]"); } /** \brief Compares calculated against actual statistics values. Checks validness of all statistics aspects. Lets test fail if any aspect is not sufficiently equal. */ - static void ValidateStatistics(const mitk::ImageStatisticsContainer::StatisticsObject hotspotStatistics, const Parameters& testParameters, unsigned int label) + static void ValidateStatistics(const mitk::ImageStatisticsContainer::ImageStatisticsObject hotspotStatistics, const Parameters& testParameters, unsigned int label) { // check all expected test result against actual results double eps = 0.25; // value above the largest tested difference auto mean = hotspotStatistics.GetValueConverted(mitk::ImageStatisticsConstants::MEAN()); auto max = hotspotStatistics.GetValueConverted(mitk::ImageStatisticsConstants::MAXIMUM()); auto min = hotspotStatistics.GetValueConverted(mitk::ImageStatisticsConstants::MINIMUM()); ValidateStatisticsItem("Hotspot mean", mean, testParameters.m_HotspotMean[label], eps); ValidateStatisticsItem("Hotspot maximum", max, testParameters.m_HotspotMax[label], eps); ValidateStatisticsItem("Hotspot minimum", min, testParameters.m_HotspotMin[label], eps); vnl_vector referenceHotspotCenterIndex; referenceHotspotCenterIndex.set_size(3); referenceHotspotCenterIndex[0] = testParameters.m_HotspotIndexX[label]; referenceHotspotCenterIndex[1] = testParameters.m_HotspotIndexY[label]; referenceHotspotCenterIndex[2] = testParameters.m_HotspotIndexZ[label]; // ValidateStatisticsItem("Hotspot center position", statistics.GetHotspotStatistics().GetHotspotIndex(), referenceHotspotCenterIndex); TODO: new image statistics calculator does not give hotspot position // TODO we do not test minimum/maximum positions within the peak/hotspot region, because // these positions are not unique, i.e. there are multiple valid minima/maxima positions. // One solution would be to modify the test cases in order to achive clear positions. // The BETTER/CORRECT solution would be to change the singular position into a set of positions / a region } }; /** \brief Verifies that hotspot statistics part of ImageStatisticsCalculator. The test reads parameters from an XML-file to generate a test-image, calculates the hotspot statistics of the image and checks if the calculated statistics are the same as the specified values of the XML-file. */ int mitkImageStatisticsHotspotTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkImageStatisticsHotspotTest") try { mitkImageStatisticsHotspotTestClass::Parameters parameters = mitkImageStatisticsHotspotTestClass::ParseParameters(argc,argv); mitk::Image::Pointer image = mitkImageStatisticsHotspotTestClass::BuildTestImage(parameters); MITK_TEST_CONDITION_REQUIRED( image.IsNotNull(), "Generate test image" ); for(unsigned int label = 0; label < parameters.m_NumberOfLabels; ++label) { - mitk::ImageStatisticsContainer::StatisticsObject statistics = mitkImageStatisticsHotspotTestClass::CalculateStatistics(image, parameters, label); + mitk::ImageStatisticsContainer::ImageStatisticsObject statistics = mitkImageStatisticsHotspotTestClass::CalculateStatistics(image, parameters, label); mitkImageStatisticsHotspotTestClass::ValidateStatistics(statistics, parameters, label); std::cout << std::endl; } } catch (std::exception& e) { std::cout << "Error: " << e.what() << std::endl; MITK_TEST_CONDITION_REQUIRED( false, "Exception occurred during test execution: " << e.what() ); } catch(...) { MITK_TEST_CONDITION_REQUIRED( false, "Exception occurred during test execution." ); } MITK_TEST_END() } diff --git a/Modules/ImageStatistics/mitkImageStatisticsCalculator.cpp b/Modules/ImageStatistics/mitkImageStatisticsCalculator.cpp index 771e715948..55d494689b 100644 --- a/Modules/ImageStatistics/mitkImageStatisticsCalculator.cpp +++ b/Modules/ImageStatistics/mitkImageStatisticsCalculator.cpp @@ -1,564 +1,564 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkImageStatisticsCalculator.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace mitk { void ImageStatisticsCalculator::SetInputImage(mitk::Image::ConstPointer image) { if (image != m_Image) { m_Image = image; this->Modified(); } } void ImageStatisticsCalculator::SetMask(mitk::MaskGenerator::Pointer mask) { if (mask != m_MaskGenerator) { m_MaskGenerator = mask; this->Modified(); } } void ImageStatisticsCalculator::SetSecondaryMask(mitk::MaskGenerator::Pointer mask) { if (mask != m_SecondaryMaskGenerator) { m_SecondaryMaskGenerator = mask; this->Modified(); } } void ImageStatisticsCalculator::SetNBinsForHistogramStatistics(unsigned int nBins) { if (nBins != m_nBinsForHistogramStatistics) { m_nBinsForHistogramStatistics = nBins; this->Modified(); this->m_UseBinSizeOverNBins = false; } if (m_UseBinSizeOverNBins) { this->Modified(); this->m_UseBinSizeOverNBins = false; } } unsigned int ImageStatisticsCalculator::GetNBinsForHistogramStatistics() const { return m_nBinsForHistogramStatistics; } void ImageStatisticsCalculator::SetBinSizeForHistogramStatistics(double binSize) { if (binSize != m_binSizeForHistogramStatistics) { m_binSizeForHistogramStatistics = binSize; this->Modified(); this->m_UseBinSizeOverNBins = true; } if (!m_UseBinSizeOverNBins) { this->Modified(); this->m_UseBinSizeOverNBins = true; } } double ImageStatisticsCalculator::GetBinSizeForHistogramStatistics() const { return m_binSizeForHistogramStatistics; } mitk::ImageStatisticsContainer::Pointer ImageStatisticsCalculator::GetStatistics(LabelIndex label) { if (m_Image.IsNull()) { mitkThrow() << "no image"; } if (!m_Image->IsInitialized()) { mitkThrow() << "Image not initialized!"; } if (IsUpdateRequired(label)) { // auto aStatisticContainer = ImageStatisticsContainer::New(); auto timeGeometry = m_Image->GetTimeGeometry(); // aStatisticContainer->SetTimeGeometry(timeGeometry); // always compute statistics on all timesteps for (unsigned int timeStep = 0; timeStep < m_Image->GetTimeSteps(); timeStep++) { if (m_MaskGenerator.IsNotNull()) { m_MaskGenerator->SetTimeStep(timeStep); //See T25625: otherwise, the mask is not computed again after setting a different time step m_MaskGenerator->Modified(); m_InternalMask = m_MaskGenerator->GetMask(); if (m_MaskGenerator->GetReferenceImage().IsNotNull()) { m_InternalImageForStatistics = m_MaskGenerator->GetReferenceImage(); } else { m_InternalImageForStatistics = m_Image; } } else { m_InternalImageForStatistics = m_Image; } if (m_SecondaryMaskGenerator.IsNotNull()) { m_SecondaryMaskGenerator->SetTimeStep(timeStep); m_SecondaryMask = m_SecondaryMaskGenerator->GetMask(); } ImageTimeSelector::Pointer imgTimeSel = ImageTimeSelector::New(); imgTimeSel->SetInput(m_InternalImageForStatistics); imgTimeSel->SetTimeNr(timeStep); imgTimeSel->UpdateLargestPossibleRegion(); imgTimeSel->Update(); m_ImageTimeSlice = imgTimeSel->GetOutput(); // Calculate statistics with/without mask if (m_MaskGenerator.IsNull() && m_SecondaryMaskGenerator.IsNull()) { // 1) calculate statistics unmasked: AccessByItk_2(m_ImageTimeSlice, InternalCalculateStatisticsUnmasked, timeGeometry, timeStep) } else { // 2) calculate statistics masked AccessByItk_2(m_ImageTimeSlice, InternalCalculateStatisticsMasked, timeGeometry, timeStep) } // this->Modified(); } } auto it = m_StatisticContainers.find(label); if (it != m_StatisticContainers.end()) { return it->second; } else { mitkThrow() << "unknown label"; return nullptr; } } template void ImageStatisticsCalculator::InternalCalculateStatisticsUnmasked( typename itk::Image *image, const TimeGeometry *timeGeometry, TimeStepType timeStep) { typedef typename itk::Image ImageType; typedef typename itk::ExtendedStatisticsImageFilter ImageStatisticsFilterType; typedef typename itk::MinMaxImageFilterWithIndex MinMaxFilterType; // reset statistics container if exists ImageStatisticsContainer::Pointer statisticContainerForImage; LabelIndex labelNoMask = 1; auto it = m_StatisticContainers.find(labelNoMask); if (it != m_StatisticContainers.end()) { statisticContainerForImage = it->second; // statisticContainerForImage->Reset(); // statisticContainerForImage->SetTimeGeometry(timeGeometry); } else { statisticContainerForImage = ImageStatisticsContainer::New(); statisticContainerForImage->SetTimeGeometry(const_cast(timeGeometry)); m_StatisticContainers.emplace(labelNoMask, statisticContainerForImage); } - auto statObj = ImageStatisticsContainer::StatisticsObject(); + auto statObj = ImageStatisticsContainer::ImageStatisticsObject(); typename ImageStatisticsFilterType::Pointer statisticsFilter = ImageStatisticsFilterType::New(); statisticsFilter->SetInput(image); statisticsFilter->SetCoordinateTolerance(0.001); statisticsFilter->SetDirectionTolerance(0.001); // TODO: this is single threaded. Implement our own image filter that does this multi threaded // typename itk::MinimumMaximumImageCalculator::Pointer imgMinMaxFilter = // itk::MinimumMaximumImageCalculator::New(); imgMinMaxFilter->SetImage(image); // imgMinMaxFilter->Compute(); vnl_vector minIndex, maxIndex; typename MinMaxFilterType::Pointer minMaxFilter = MinMaxFilterType::New(); minMaxFilter->SetInput(image); minMaxFilter->UpdateLargestPossibleRegion(); typename ImageType::PixelType minval = minMaxFilter->GetMin(); typename ImageType::PixelType maxval = minMaxFilter->GetMax(); typename ImageType::IndexType tmpMinIndex = minMaxFilter->GetMinIndex(); typename ImageType::IndexType tmpMaxIndex = minMaxFilter->GetMaxIndex(); // typename ImageType::IndexType tmpMinIndex = imgMinMaxFilter->GetIndexOfMinimum(); // typename ImageType::IndexType tmpMaxIndex = imgMinMaxFilter->GetIndexOfMaximum(); minIndex.set_size(tmpMaxIndex.GetIndexDimension()); maxIndex.set_size(tmpMaxIndex.GetIndexDimension()); for (unsigned int i = 0; i < tmpMaxIndex.GetIndexDimension(); i++) { minIndex[i] = tmpMinIndex[i]; maxIndex[i] = tmpMaxIndex[i]; } statObj.AddStatistic(mitk::ImageStatisticsConstants::MINIMUMPOSITION(), minIndex); statObj.AddStatistic(mitk::ImageStatisticsConstants::MAXIMUMPOSITION(), maxIndex); // convert m_binSize in m_nBins if necessary unsigned int nBinsForHistogram; if (m_UseBinSizeOverNBins) { nBinsForHistogram = std::max(static_cast(std::ceil(maxval - minval)) / m_binSizeForHistogramStatistics, 10.); // do not allow less than 10 bins } else { nBinsForHistogram = m_nBinsForHistogramStatistics; } statisticsFilter->SetHistogramParameters(nBinsForHistogram, minval, maxval); try { statisticsFilter->Update(); } catch (const itk::ExceptionObject &e) { mitkThrow() << "Image statistics calculation failed due to following ITK Exception: \n " << e.what(); } auto voxelVolume = GetVoxelVolume(image); auto numberOfPixels = image->GetLargestPossibleRegion().GetNumberOfPixels(); auto volume = static_cast(numberOfPixels) * voxelVolume; auto variance = statisticsFilter->GetSigma() * statisticsFilter->GetSigma(); auto rms = std::sqrt(std::pow(statisticsFilter->GetMean(), 2.) + statisticsFilter->GetVariance()); // variance = sigma^2 statObj.AddStatistic(mitk::ImageStatisticsConstants::NUMBEROFVOXELS(), static_cast(numberOfPixels)); statObj.AddStatistic(mitk::ImageStatisticsConstants::VOLUME(), volume); statObj.AddStatistic(mitk::ImageStatisticsConstants::MEAN(), statisticsFilter->GetMean()); statObj.AddStatistic(mitk::ImageStatisticsConstants::MINIMUM(), static_cast(statisticsFilter->GetMinimum())); statObj.AddStatistic(mitk::ImageStatisticsConstants::MAXIMUM(), static_cast(statisticsFilter->GetMaximum())); statObj.AddStatistic(mitk::ImageStatisticsConstants::STANDARDDEVIATION(), statisticsFilter->GetSigma()); statObj.AddStatistic(mitk::ImageStatisticsConstants::VARIANCE(), variance); statObj.AddStatistic(mitk::ImageStatisticsConstants::SKEWNESS(), statisticsFilter->GetSkewness()); statObj.AddStatistic(mitk::ImageStatisticsConstants::KURTOSIS(), statisticsFilter->GetKurtosis()); statObj.AddStatistic(mitk::ImageStatisticsConstants::RMS(), rms); statObj.AddStatistic(mitk::ImageStatisticsConstants::MPP(), statisticsFilter->GetMPP()); statObj.AddStatistic(mitk::ImageStatisticsConstants::ENTROPY(), statisticsFilter->GetEntropy()); statObj.AddStatistic(mitk::ImageStatisticsConstants::MEDIAN(), statisticsFilter->GetMedian()); statObj.AddStatistic(mitk::ImageStatisticsConstants::UNIFORMITY(), statisticsFilter->GetUniformity()); statObj.AddStatistic(mitk::ImageStatisticsConstants::UPP(), statisticsFilter->GetUPP()); statObj.m_Histogram = statisticsFilter->GetHistogram().GetPointer(); statisticContainerForImage->SetStatisticsForTimeStep(timeStep, statObj); } template double ImageStatisticsCalculator::GetVoxelVolume(typename itk::Image *image) const { auto spacing = image->GetSpacing(); double voxelVolume = 1.; for (unsigned int i = 0; i < image->GetImageDimension(); i++) { voxelVolume *= spacing[i]; } return voxelVolume; } template void ImageStatisticsCalculator::InternalCalculateStatisticsMasked(typename itk::Image *image, const TimeGeometry *timeGeometry, unsigned int timeStep) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef typename MaskType::PixelType LabelPixelType; typedef itk::ExtendedLabelStatisticsImageFilter ImageStatisticsFilterType; typedef MaskUtilities MaskUtilType; typedef typename itk::MinMaxLabelImageFilterWithIndex MinMaxLabelFilterType; typedef typename ImageType::PixelType InputImgPixelType; // workaround: if m_SecondaryMaskGenerator ist not null but m_MaskGenerator is! (this is the case if we request a // 'ignore zuero valued pixels' mask in the gui but do not define a primary mask) bool swapMasks = false; if (m_SecondaryMask.IsNotNull() && m_InternalMask.IsNull()) { m_InternalMask = m_SecondaryMask; m_SecondaryMask = nullptr; swapMasks = true; } // maskImage has to have the same dimension as image typename MaskType::Pointer maskImage = MaskType::New(); try { // try to access the pixel values directly (no copying or casting). Only works if mask pixels are of pixelType // unsigned short maskImage = ImageToItkImage(m_InternalMask); } catch (const itk::ExceptionObject &) { // if the pixel type of the mask is not short, then we have to make a copy of m_InternalMask (and cast the values) CastToItkImage(m_InternalMask, maskImage); } // if we have a secondary mask (say a ignoreZeroPixelMask) we need to combine the masks (corresponds to AND) if (m_SecondaryMask.IsNotNull()) { // dirty workaround for a bug when pf mask + any other mask is used in conjunction. We need a proper fix for this // (Fabian Isensee is responsible and probably working on it!) if (m_InternalMask->GetDimension() == 2 && (m_SecondaryMask->GetDimension() == 3 || m_SecondaryMask->GetDimension() == 4)) { mitk::Image::ConstPointer old_img = m_SecondaryMaskGenerator->GetReferenceImage(); m_SecondaryMaskGenerator->SetInputImage(m_MaskGenerator->GetReferenceImage()); m_SecondaryMask = m_SecondaryMaskGenerator->GetMask(); m_SecondaryMaskGenerator->SetInputImage(old_img); } typename MaskType::Pointer secondaryMaskImage = MaskType::New(); secondaryMaskImage = ImageToItkImage(m_SecondaryMask); // secondary mask should be a ignore zero value pixel mask derived from image. it has to be cropped to the mask // region (which may be planar or simply smaller) typename MaskUtilities::Pointer secondaryMaskMaskUtil = MaskUtilities::New(); secondaryMaskMaskUtil->SetImage(secondaryMaskImage.GetPointer()); secondaryMaskMaskUtil->SetMask(maskImage.GetPointer()); typename MaskType::Pointer adaptedSecondaryMaskImage = secondaryMaskMaskUtil->ExtractMaskImageRegion(); typename itk::MaskImageFilter2::Pointer maskFilter = itk::MaskImageFilter2::New(); maskFilter->SetInput1(maskImage); maskFilter->SetInput2(adaptedSecondaryMaskImage); maskFilter->SetMaskingValue( 1); // all pixels of maskImage where secondaryMaskImage==1 will be kept, all the others are set to 0 maskFilter->UpdateLargestPossibleRegion(); maskImage = maskFilter->GetOutput(); } typename MaskUtilType::Pointer maskUtil = MaskUtilType::New(); maskUtil->SetImage(image); maskUtil->SetMask(maskImage.GetPointer()); // if mask is smaller than image, extract the image region where the mask is typename ImageType::Pointer adaptedImage = ImageType::New(); adaptedImage = maskUtil->ExtractMaskImageRegion(); // this also checks mask sanity // find min, max, minindex and maxindex typename MinMaxLabelFilterType::Pointer minMaxFilter = MinMaxLabelFilterType::New(); minMaxFilter->SetInput(adaptedImage); minMaxFilter->SetLabelInput(maskImage); minMaxFilter->UpdateLargestPossibleRegion(); // set histogram parameters for each label individually (min/max may be different for each label) typedef typename std::map MapType; typedef typename std::pair PairType; std::vector relevantLabels = minMaxFilter->GetRelevantLabels(); MapType minVals; MapType maxVals; std::map nBins; for (LabelPixelType label : relevantLabels) { minVals.insert(PairType(label, minMaxFilter->GetMin(label))); maxVals.insert(PairType(label, minMaxFilter->GetMax(label))); unsigned int nBinsForHistogram; if (m_UseBinSizeOverNBins) { nBinsForHistogram = std::max(static_cast(std::ceil(minMaxFilter->GetMax(label) - minMaxFilter->GetMin(label))) / m_binSizeForHistogramStatistics, 10.); // do not allow less than 10 bins } else { nBinsForHistogram = m_nBinsForHistogramStatistics; } nBins.insert(typename std::pair(label, nBinsForHistogram)); } typename ImageStatisticsFilterType::Pointer imageStatisticsFilter = ImageStatisticsFilterType::New(); imageStatisticsFilter->SetDirectionTolerance(0.001); imageStatisticsFilter->SetCoordinateTolerance(0.001); imageStatisticsFilter->SetInput(adaptedImage); imageStatisticsFilter->SetLabelInput(maskImage); imageStatisticsFilter->SetHistogramParametersForLabels(nBins, minVals, maxVals); imageStatisticsFilter->Update(); std::list labels = imageStatisticsFilter->GetRelevantLabels(); auto it = labels.begin(); while (it != labels.end()) { ImageStatisticsContainer::Pointer statisticContainerForLabelImage; auto labelIt = m_StatisticContainers.find(*it); // reset if statisticContainer already exist if (labelIt != m_StatisticContainers.end()) { statisticContainerForLabelImage = labelIt->second; // statisticContainerForLabelImage->Reset(); // statisticContainerForLabelImage->SetTimeGeometry(timeGeometry); } // create new statisticContainer else { statisticContainerForLabelImage = ImageStatisticsContainer::New(); statisticContainerForLabelImage->SetTimeGeometry(const_cast(timeGeometry)); // link label (*it) to statisticContainer m_StatisticContainers.emplace(*it, statisticContainerForLabelImage); } - ImageStatisticsContainer::StatisticsObject statObj; + ImageStatisticsContainer::ImageStatisticsObject statObj; // find min, max, minindex and maxindex // make sure to only look in the masked region, use a masker for this vnl_vector minIndex, maxIndex; mitk::Point3D worldCoordinateMin; mitk::Point3D worldCoordinateMax; mitk::Point3D indexCoordinateMin; mitk::Point3D indexCoordinateMax; m_InternalImageForStatistics->GetGeometry()->IndexToWorld(minMaxFilter->GetMinIndex(*it), worldCoordinateMin); m_InternalImageForStatistics->GetGeometry()->IndexToWorld(minMaxFilter->GetMaxIndex(*it), worldCoordinateMax); m_Image->GetGeometry()->WorldToIndex(worldCoordinateMin, indexCoordinateMin); m_Image->GetGeometry()->WorldToIndex(worldCoordinateMax, indexCoordinateMax); minIndex.set_size(3); maxIndex.set_size(3); // for (unsigned int i=0; i < tmpMaxIndex.GetIndexDimension(); i++) for (unsigned int i = 0; i < 3; i++) { minIndex[i] = indexCoordinateMin[i]; maxIndex[i] = indexCoordinateMax[i]; } statObj.AddStatistic(mitk::ImageStatisticsConstants::MINIMUMPOSITION(), minIndex); statObj.AddStatistic(mitk::ImageStatisticsConstants::MAXIMUMPOSITION(), maxIndex); assert(std::abs(minMaxFilter->GetMax(*it) - imageStatisticsFilter->GetMaximum(*it)) < mitk::eps); assert(std::abs(minMaxFilter->GetMin(*it) - imageStatisticsFilter->GetMinimum(*it)) < mitk::eps); auto voxelVolume = GetVoxelVolume(image); auto numberOfVoxels = static_cast(imageStatisticsFilter->GetSum(*it) / (double)imageStatisticsFilter->GetMean(*it)); auto volume = static_cast(numberOfVoxels) * voxelVolume; auto rms = std::sqrt(std::pow(imageStatisticsFilter->GetMean(*it), 2.) + imageStatisticsFilter->GetVariance(*it)); // variance = sigma^2 auto variance = imageStatisticsFilter->GetSigma(*it) * imageStatisticsFilter->GetSigma(*it); statObj.AddStatistic(mitk::ImageStatisticsConstants::NUMBEROFVOXELS(), numberOfVoxels); statObj.AddStatistic(mitk::ImageStatisticsConstants::VOLUME(), volume); statObj.AddStatistic(mitk::ImageStatisticsConstants::MEAN(), imageStatisticsFilter->GetMean(*it)); statObj.AddStatistic(mitk::ImageStatisticsConstants::MINIMUM(), imageStatisticsFilter->GetMinimum(*it)); statObj.AddStatistic(mitk::ImageStatisticsConstants::MAXIMUM(), imageStatisticsFilter->GetMaximum(*it)); statObj.AddStatistic(mitk::ImageStatisticsConstants::STANDARDDEVIATION(), imageStatisticsFilter->GetSigma(*it)); statObj.AddStatistic(mitk::ImageStatisticsConstants::VARIANCE(), variance); statObj.AddStatistic(mitk::ImageStatisticsConstants::SKEWNESS(), imageStatisticsFilter->GetSkewness(*it)); statObj.AddStatistic(mitk::ImageStatisticsConstants::KURTOSIS(), imageStatisticsFilter->GetKurtosis(*it)); statObj.AddStatistic(mitk::ImageStatisticsConstants::RMS(), rms); statObj.AddStatistic(mitk::ImageStatisticsConstants::MPP(), imageStatisticsFilter->GetMPP(*it)); statObj.AddStatistic(mitk::ImageStatisticsConstants::ENTROPY(), imageStatisticsFilter->GetEntropy(*it)); statObj.AddStatistic(mitk::ImageStatisticsConstants::MEDIAN(), imageStatisticsFilter->GetMedian(*it)); statObj.AddStatistic(mitk::ImageStatisticsConstants::UNIFORMITY(), imageStatisticsFilter->GetUniformity(*it)); statObj.AddStatistic(mitk::ImageStatisticsConstants::UPP(), imageStatisticsFilter->GetUPP(*it)); statObj.m_Histogram = imageStatisticsFilter->GetHistogram(*it).GetPointer(); statisticContainerForLabelImage->SetStatisticsForTimeStep(timeStep, statObj); ++it; } // swap maskGenerators back if (swapMasks) { m_SecondaryMask = m_InternalMask; m_InternalMask = nullptr; } } bool ImageStatisticsCalculator::IsUpdateRequired(LabelIndex label) const { unsigned long thisClassTimeStamp = this->GetMTime(); unsigned long inputImageTimeStamp = m_Image->GetMTime(); auto it = m_StatisticContainers.find(label); if (it == m_StatisticContainers.end()) { return true; } unsigned long statisticsTimeStamp = it->second->GetMTime(); if (thisClassTimeStamp > statisticsTimeStamp) // inputs have changed { return true; } if (inputImageTimeStamp > statisticsTimeStamp) // image has changed { return true; } if (m_MaskGenerator.IsNotNull()) { unsigned long maskGeneratorTimeStamp = m_MaskGenerator->GetMTime(); if (maskGeneratorTimeStamp > statisticsTimeStamp) // there is a mask generator and it has changed { return true; } } if (m_SecondaryMaskGenerator.IsNotNull()) { unsigned long maskGeneratorTimeStamp = m_SecondaryMaskGenerator->GetMTime(); if (maskGeneratorTimeStamp > statisticsTimeStamp) // there is a secondary mask generator and it has changed { return true; } } return false; } } // namespace mitk diff --git a/Modules/ImageStatistics/mitkImageStatisticsContainer.cpp b/Modules/ImageStatistics/mitkImageStatisticsContainer.cpp index 59aae39bb2..d7f7d2fcd7 100644 --- a/Modules/ImageStatistics/mitkImageStatisticsContainer.cpp +++ b/Modules/ImageStatistics/mitkImageStatisticsContainer.cpp @@ -1,235 +1,235 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include namespace mitk { ImageStatisticsContainer::ImageStatisticsContainer() { this->Reset(); } // The order is derived from the old (<2018) image statistics plugin. - const ImageStatisticsContainer::StatisticsObject::StatisticNameVector - ImageStatisticsContainer::StatisticsObject::m_DefaultNames = {ImageStatisticsConstants::MEAN(), + const ImageStatisticsContainer::ImageStatisticsObject::StatisticNameVector + ImageStatisticsContainer::ImageStatisticsObject::m_DefaultNames = {ImageStatisticsConstants::MEAN(), ImageStatisticsConstants::MEDIAN(), ImageStatisticsConstants::STANDARDDEVIATION(), ImageStatisticsConstants::RMS(), ImageStatisticsConstants::MAXIMUM(), ImageStatisticsConstants::MAXIMUMPOSITION(), ImageStatisticsConstants::MINIMUM(), ImageStatisticsConstants::MINIMUMPOSITION(), ImageStatisticsConstants::NUMBEROFVOXELS(), ImageStatisticsConstants::VOLUME(), ImageStatisticsConstants::SKEWNESS(), ImageStatisticsConstants::KURTOSIS(), ImageStatisticsConstants::UNIFORMITY(), ImageStatisticsConstants::ENTROPY(), ImageStatisticsConstants::MPP(), ImageStatisticsConstants::UPP()}; - ImageStatisticsContainer::StatisticsObject::StatisticsObject() { Reset(); } + ImageStatisticsContainer::ImageStatisticsObject::ImageStatisticsObject() { Reset(); } - void ImageStatisticsContainer::StatisticsObject::AddStatistic(const std::string &key, StatisticsVariantType value) + void ImageStatisticsContainer::ImageStatisticsObject::AddStatistic(const std::string &key, StatisticsVariantType value) { m_Statistics.emplace(key, value); if (std::find(m_DefaultNames.cbegin(), m_DefaultNames.cend(), key) == m_DefaultNames.cend()) { if (std::find(m_CustomNames.cbegin(), m_CustomNames.cend(), key) == m_CustomNames.cend()) { m_CustomNames.emplace_back(key); } } } - const ImageStatisticsContainer::StatisticsObject::StatisticNameVector & - ImageStatisticsContainer::StatisticsObject::GetDefaultStatisticNames() + const ImageStatisticsContainer::ImageStatisticsObject::StatisticNameVector & + ImageStatisticsContainer::ImageStatisticsObject::GetDefaultStatisticNames() { return m_DefaultNames; } - const ImageStatisticsContainer::StatisticsObject::StatisticNameVector & - ImageStatisticsContainer::StatisticsObject::GetCustomStatisticNames() const + const ImageStatisticsContainer::ImageStatisticsObject::StatisticNameVector & + ImageStatisticsContainer::ImageStatisticsObject::GetCustomStatisticNames() const { return m_CustomNames; } - ImageStatisticsContainer::StatisticsObject::StatisticNameVector - ImageStatisticsContainer::StatisticsObject::GetAllStatisticNames() const + ImageStatisticsContainer::ImageStatisticsObject::StatisticNameVector + ImageStatisticsContainer::ImageStatisticsObject::GetAllStatisticNames() const { StatisticNameVector names = GetDefaultStatisticNames(); names.insert(names.cend(), m_CustomNames.cbegin(), m_CustomNames.cend()); return names; } - ImageStatisticsContainer::StatisticsObject::StatisticNameVector - ImageStatisticsContainer::StatisticsObject::GetExistingStatisticNames() const + ImageStatisticsContainer::ImageStatisticsObject::StatisticNameVector + ImageStatisticsContainer::ImageStatisticsObject::GetExistingStatisticNames() const { StatisticNameVector names; std::transform(m_Statistics.begin(), m_Statistics.end(), std::back_inserter(names), [](const auto &pair) { return pair.first; }); return names; } - bool ImageStatisticsContainer::StatisticsObject::HasStatistic(const std::string &name) const + bool ImageStatisticsContainer::ImageStatisticsObject::HasStatistic(const std::string &name) const { return m_Statistics.find(name) != m_Statistics.cend(); } - ImageStatisticsContainer::StatisticsVariantType ImageStatisticsContainer::StatisticsObject::GetValueNonConverted( + ImageStatisticsContainer::StatisticsVariantType ImageStatisticsContainer::ImageStatisticsObject::GetValueNonConverted( const std::string &name) const { if (HasStatistic(name)) { return m_Statistics.find(name)->second; } else { mitkThrow() << "invalid statistic key, could not find"; } } - void ImageStatisticsContainer::StatisticsObject::Reset() + void ImageStatisticsContainer::ImageStatisticsObject::Reset() { m_Statistics.clear(); m_CustomNames.clear(); } bool ImageStatisticsContainer::TimeStepExists(TimeStepType timeStep) const { return m_TimeStepMap.find(timeStep) != m_TimeStepMap.end(); } - const ImageStatisticsContainer::StatisticsObject &ImageStatisticsContainer::GetStatisticsForTimeStep( + const ImageStatisticsContainer::ImageStatisticsObject &ImageStatisticsContainer::GetStatisticsForTimeStep( TimeStepType timeStep) const { auto it = m_TimeStepMap.find(timeStep); if (it != m_TimeStepMap.end()) { return it->second; } mitkThrow() << "StatisticsObject for timeStep " << timeStep << " not found!"; } - void ImageStatisticsContainer::SetStatisticsForTimeStep(TimeStepType timeStep, StatisticsObject statistics) + void ImageStatisticsContainer::SetStatisticsForTimeStep(TimeStepType timeStep, ImageStatisticsObject statistics) { if (timeStep < this->GetTimeSteps()) { m_TimeStepMap.emplace(timeStep, statistics); this->Modified(); } else { mitkThrow() << "Given timeStep " << timeStep << " out of timeStep geometry bounds. TimeSteps in geometry: " << this->GetTimeSteps(); } } void ImageStatisticsContainer::PrintSelf(std::ostream &os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); for (unsigned int i = 0; i < this->GetTimeSteps(); i++) { auto statisticsValues = GetStatisticsForTimeStep(i); os << std::endl << indent << "Statistics instance for timeStep " << i << ":"; auto statisticKeys = statisticsValues.GetExistingStatisticNames(); os << std::endl << indent << "Number of entries: " << statisticKeys.size(); for (const auto &aKey : statisticKeys) { os << std::endl << indent.GetNextIndent() << aKey << ": " << statisticsValues.GetValueNonConverted(aKey); } } } unsigned int ImageStatisticsContainer::GetNumberOfTimeSteps() const { return this->GetTimeSteps(); } void ImageStatisticsContainer::Reset() { for (auto iter = m_TimeStepMap.begin(); iter != m_TimeStepMap.end(); iter++) { iter->second.Reset(); } } itk::LightObject::Pointer ImageStatisticsContainer::InternalClone() const { itk::LightObject::Pointer ioPtr = Superclass::InternalClone(); Self::Pointer rval = dynamic_cast(ioPtr.GetPointer()); if (rval.IsNull()) { itkExceptionMacro(<< "downcast to type " << "StatisticsContainer" << " failed."); } rval->SetTimeStepMap(m_TimeStepMap); rval->SetTimeGeometry(this->GetTimeGeometry()->Clone()); return ioPtr; } void ImageStatisticsContainer::SetTimeStepMap(TimeStepMapType map) { m_TimeStepMap = map; } - ImageStatisticsContainer::StatisticsObject::StatisticNameVector GetAllStatisticNames( + ImageStatisticsContainer::ImageStatisticsObject::StatisticNameVector GetAllStatisticNames( const ImageStatisticsContainer *container) { - ImageStatisticsContainer::StatisticsObject::StatisticNameVector names = - ImageStatisticsContainer::StatisticsObject::GetDefaultStatisticNames(); + ImageStatisticsContainer::ImageStatisticsObject::StatisticNameVector names = + ImageStatisticsContainer::ImageStatisticsObject::GetDefaultStatisticNames(); if (container) { std::set customKeys; for (unsigned int i = 0; i < container->GetTimeSteps(); i++) { auto statisticKeys = container->GetStatisticsForTimeStep(i).GetCustomStatisticNames(); customKeys.insert(statisticKeys.cbegin(), statisticKeys.cend()); } names.insert(names.cend(), customKeys.cbegin(), customKeys.cend()); } return names; } - ImageStatisticsContainer::StatisticsObject::StatisticNameVector GetAllStatisticNames( + ImageStatisticsContainer::ImageStatisticsObject::StatisticNameVector GetAllStatisticNames( std::vector containers) { - ImageStatisticsContainer::StatisticsObject::StatisticNameVector names = - ImageStatisticsContainer::StatisticsObject::GetDefaultStatisticNames(); + ImageStatisticsContainer::ImageStatisticsObject::StatisticNameVector names = + ImageStatisticsContainer::ImageStatisticsObject::GetDefaultStatisticNames(); std::set customKeys; for (auto container : containers) { for (unsigned int i = 0; i < container->GetTimeSteps(); i++) { auto statisticKeys = container->GetStatisticsForTimeStep(i).GetCustomStatisticNames(); customKeys.insert(statisticKeys.cbegin(), statisticKeys.cend()); } } names.insert(names.end(), customKeys.begin(), customKeys.end()); return names; }; } // namespace mitk diff --git a/Modules/ImageStatistics/mitkImageStatisticsContainer.h b/Modules/ImageStatistics/mitkImageStatisticsContainer.h index 48f2e76e4e..c0011dd2dc 100644 --- a/Modules/ImageStatistics/mitkImageStatisticsContainer.h +++ b/Modules/ImageStatistics/mitkImageStatisticsContainer.h @@ -1,166 +1,166 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIMAGESTATISTICSCONTAINER #define MITKIMAGESTATISTICSCONTAINER #include #include #include #include #include namespace mitk { /** @brief Container class for storing a StatisticsObject for each timestep. Stored statistics are: - for the defined statistics, see GetAllStatisticNames - Histogram of Pixel Values */ class MITKIMAGESTATISTICS_EXPORT ImageStatisticsContainer : public mitk::BaseData { public: mitkClassMacro(ImageStatisticsContainer, mitk::BaseData) itkFactorylessNewMacro(Self) itkCloneMacro(Self) using HistogramType = itk::Statistics::Histogram; using RealType = double; using LabelIndex = unsigned int; using IndexType = vnl_vector; using VoxelCountType = unsigned long; using StatisticsVariantType = boost::variant; using StatisticsMapType = std::map < std::string, StatisticsVariantType>; using StatisticsKeyType = std::string; virtual void SetRequestedRegionToLargestPossibleRegion() override {} virtual bool RequestedRegionIsOutsideOfTheBufferedRegion() override { return false; } virtual bool VerifyRequestedRegion() override { return true; } virtual void SetRequestedRegion(const itk::DataObject*) override {} /** @brief Container class for storing the computed image statistics. @details The statistics are stored in a map with value as boost::variant. The type used to create the boost::variant is important as only this type can be recovered lateron. */ - class MITKIMAGESTATISTICS_EXPORT StatisticsObject { + class MITKIMAGESTATISTICS_EXPORT ImageStatisticsObject { public: - StatisticsObject(); + ImageStatisticsObject(); /** @brief Adds a statistic to the statistics object @details if already a statistic with that name is included, it is overwritten */ void AddStatistic(const std::string& key, StatisticsVariantType value); using StatisticNameVector = std::vector; /** @brief Returns the names of the default statistics @details The order is derived from the image statistics plugin. */ static const StatisticNameVector& GetDefaultStatisticNames(); /** @brief Returns the names of all custom statistics (defined at runtime and no default names). */ const StatisticNameVector& GetCustomStatisticNames() const; /** @brief Returns the names of all statistics (default and custom defined) Additional custom keys are added at the end in a sorted order. */ StatisticNameVector GetAllStatisticNames() const; StatisticNameVector GetExistingStatisticNames() const; bool HasStatistic(const std::string& name) const; /** @brief Converts the requested value to the defined type @param name defined string on creation (AddStatistic) @exception if no statistics with key name was found. */ template TType GetValueConverted(const std::string& name) const { auto value = GetValueNonConverted(name); return boost::get(value); } /** @brief Returns the requested value @exception if no statistics with key name was found. */ StatisticsVariantType GetValueNonConverted(const std::string& name) const; void Reset(); HistogramType::ConstPointer m_Histogram=nullptr; private: StatisticsMapType m_Statistics; StatisticNameVector m_CustomNames; static const StatisticNameVector m_DefaultNames; }; - using TimeStepMapType = std::map; + using TimeStepMapType = std::map; unsigned int GetNumberOfTimeSteps() const; /** @brief Deletes all stored values*/ void Reset(); /** @brief Returns the statisticObject for the given Timestep @pre timeStep must be valid */ - const StatisticsObject& GetStatisticsForTimeStep(TimeStepType timeStep) const; + const ImageStatisticsObject& GetStatisticsForTimeStep(TimeStepType timeStep) const; /** @brief Sets the statisticObject for the given Timestep @pre timeStep must be valid */ - void SetStatisticsForTimeStep(TimeStepType timeStep, StatisticsObject statistics); + void SetStatisticsForTimeStep(TimeStepType timeStep, ImageStatisticsObject statistics); /** @brief Checks if the Time step exists @pre timeStep must be valid */ bool TimeStepExists(TimeStepType timeStep) const; protected: ImageStatisticsContainer(); virtual void PrintSelf(std::ostream &os, itk::Indent indent) const override; private: itk::LightObject::Pointer InternalClone() const override; void SetTimeStepMap(TimeStepMapType map); TimeStepMapType m_TimeStepMap; }; - MITKIMAGESTATISTICS_EXPORT ImageStatisticsContainer::StatisticsObject::StatisticNameVector GetAllStatisticNames(const ImageStatisticsContainer* container); - MITKIMAGESTATISTICS_EXPORT ImageStatisticsContainer::StatisticsObject::StatisticNameVector GetAllStatisticNames(std::vector containers); + MITKIMAGESTATISTICS_EXPORT ImageStatisticsContainer::ImageStatisticsObject::StatisticNameVector GetAllStatisticNames(const ImageStatisticsContainer* container); + MITKIMAGESTATISTICS_EXPORT ImageStatisticsContainer::ImageStatisticsObject::StatisticNameVector GetAllStatisticNames(std::vector containers); } #endif // MITKIMAGESTATISTICSCONTAINER diff --git a/Modules/ImageStatistics/mitkIntensityProfile.cpp b/Modules/ImageStatistics/mitkIntensityProfile.cpp index fc72f28352..8cade2320e 100644 --- a/Modules/ImageStatistics/mitkIntensityProfile.cpp +++ b/Modules/ImageStatistics/mitkIntensityProfile.cpp @@ -1,382 +1,382 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include "mitkIntensityProfile.h" using namespace mitk; template static void ReadPixel(const PixelType&, Image::Pointer image, const itk::Index<3>& index, ScalarType* returnValue) { switch (image->GetDimension()) { case 2: { ImagePixelReadAccessor readAccess(image, image->GetSliceData(0)); *returnValue = readAccess.GetPixelByIndex(reinterpret_cast&>(index)); break; } case 3: { ImagePixelReadAccessor readAccess(image, image->GetVolumeData(0)); *returnValue = readAccess.GetPixelByIndex(index); break; } default: *returnValue = 0; break; } } static IntensityProfile::Pointer ComputeIntensityProfile(Image::Pointer image, itk::PolyLineParametricPath<3>::Pointer path) { IntensityProfile::Pointer intensityProfile = IntensityProfile::New(); itk::PolyLineParametricPath<3>::InputType input = path->StartOfInput(); BaseGeometry* imageGeometry = image->GetGeometry(); const PixelType pixelType = image->GetPixelType(); IntensityProfile::MeasurementVectorType measurementVector; itk::PolyLineParametricPath<3>::OffsetType offset; Point3D worldPoint; itk::Index<3> index; do { imageGeometry->IndexToWorld(path->Evaluate(input), worldPoint); imageGeometry->WorldToIndex(worldPoint, index); mitkPixelTypeMultiplex3(ReadPixel, pixelType, image, index, measurementVector.GetDataPointer()); intensityProfile->PushBack(measurementVector); offset = path->IncrementInput(input); } while ((offset[0] | offset[1] | offset[2]) != 0); return intensityProfile; } template static typename itk::InterpolateImageFunction::Pointer CreateInterpolateImageFunction(InterpolateImageFunction::Enum interpolator) { switch (interpolator) { case InterpolateImageFunction::NearestNeighbor: return itk::NearestNeighborInterpolateImageFunction::New().GetPointer(); case InterpolateImageFunction::Linear: return itk::LinearInterpolateImageFunction::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Blackman_3: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Blackman_4: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Blackman_5: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Cosine_3: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Cosine_4: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Cosine_5: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Hamming_3: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Hamming_4: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Hamming_5: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Lanczos_3: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Lanczos_4: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Lanczos_5: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Welch_3: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Welch_4: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); case InterpolateImageFunction::WindowedSinc_Welch_5: return itk::WindowedSincInterpolateImageFunction >::New().GetPointer(); default: return itk::NearestNeighborInterpolateImageFunction::New().GetPointer(); } } template static void ComputeIntensityProfile(itk::Image* image, itk::PolyLineParametricPath<3>::Pointer path, unsigned int numSamples, InterpolateImageFunction::Enum interpolator, IntensityProfile::Pointer intensityProfile) { typename itk::InterpolateImageFunction >::Pointer interpolateImageFunction = CreateInterpolateImageFunction >(interpolator); interpolateImageFunction->SetInputImage(image); const itk::PolyLineParametricPath<3>::InputType startOfInput = path->StartOfInput(); const itk::PolyLineParametricPath<3>::InputType delta = 1.0 / (numSamples - 1); IntensityProfile::MeasurementVectorType measurementVector; for (unsigned int i = 0; i < numSamples; ++i) { measurementVector[0] = interpolateImageFunction->EvaluateAtContinuousIndex(path->Evaluate(startOfInput + i * delta)); intensityProfile->PushBack(measurementVector); } } static IntensityProfile::Pointer ComputeIntensityProfile(Image::Pointer image, itk::PolyLineParametricPath<3>::Pointer path, unsigned int numSamples, InterpolateImageFunction::Enum interpolator) { IntensityProfile::Pointer intensityProfile = IntensityProfile::New(); AccessFixedDimensionByItk_n(image, ComputeIntensityProfile, 3, (path, numSamples, interpolator, intensityProfile)); return intensityProfile; } class AddPolyLineElementToPath { public: AddPolyLineElementToPath(const PlaneGeometry* planarFigureGeometry, const BaseGeometry* imageGeometry, itk::PolyLineParametricPath<3>::Pointer path) : m_PlanarFigureGeometry(planarFigureGeometry), m_ImageGeometry(imageGeometry), m_Path(path) { } void operator()(const PlanarFigure::PolyLineElement& polyLineElement) { m_PlanarFigureGeometry->Map(polyLineElement, m_WorldPoint); m_ImageGeometry->WorldToIndex(m_WorldPoint, m_ContinuousIndexPoint); m_Vertex.CastFrom(m_ContinuousIndexPoint); m_Path->AddVertex(m_Vertex); } private: const PlaneGeometry* m_PlanarFigureGeometry; const BaseGeometry* m_ImageGeometry; itk::PolyLineParametricPath<3>::Pointer m_Path; Point3D m_WorldPoint; Point3D m_ContinuousIndexPoint; itk::PolyLineParametricPath<3>::ContinuousIndexType m_Vertex; }; static itk::PolyLineParametricPath<3>::Pointer CreatePathFromPlanarFigure(BaseGeometry* imageGeometry, PlanarFigure* planarFigure) { itk::PolyLineParametricPath<3>::Pointer path = itk::PolyLineParametricPath<3>::New(); const PlanarFigure::PolyLineType polyLine = planarFigure->GetPolyLine(0); std::for_each(polyLine.begin(), polyLine.end(), AddPolyLineElementToPath(planarFigure->GetPlaneGeometry(), imageGeometry, path)); return path; } static void AddPointToPath(const BaseGeometry* imageGeometry, const Point3D& point, itk::PolyLineParametricPath<3>::Pointer path) { Point3D continuousIndexPoint; imageGeometry->WorldToIndex(point, continuousIndexPoint); itk::PolyLineParametricPath<3>::ContinuousIndexType vertex; vertex.CastFrom(continuousIndexPoint); path->AddVertex(vertex); } static itk::PolyLineParametricPath<3>::Pointer CreatePathFromPoints(BaseGeometry* imageGeometry, const Point3D& startPoint, const Point3D& endPoint) { itk::PolyLineParametricPath<3>::Pointer path = itk::PolyLineParametricPath<3>::New(); AddPointToPath(imageGeometry, startPoint, path); AddPointToPath(imageGeometry, endPoint, path); return path; } IntensityProfile::Pointer mitk::ComputeIntensityProfile(Image::Pointer image, PlanarFigure::Pointer planarFigure) { return ::ComputeIntensityProfile(image, CreatePathFromPlanarFigure(image->GetGeometry(), planarFigure)); } IntensityProfile::Pointer mitk::ComputeIntensityProfile(Image::Pointer image, PlanarLine::Pointer planarLine, unsigned int numSamples, InterpolateImageFunction::Enum interpolator) { return ::ComputeIntensityProfile(image, CreatePathFromPlanarFigure(image->GetGeometry(), planarLine.GetPointer()), numSamples, interpolator); } IntensityProfile::Pointer mitk::ComputeIntensityProfile(Image::Pointer image, const Point3D& startPoint, const Point3D& endPoint, unsigned int numSamples, InterpolateImageFunction::Enum interpolator) { return ::ComputeIntensityProfile(image, CreatePathFromPoints(image->GetGeometry(), startPoint, endPoint), numSamples, interpolator); } IntensityProfile::InstanceIdentifier mitk::ComputeGlobalMaximum(IntensityProfile::ConstPointer intensityProfile, IntensityProfile::MeasurementType &max) { max = -vcl_numeric_limits::min(); IntensityProfile::InstanceIdentifier maxIndex = 0; IntensityProfile::ConstIterator end = intensityProfile->End(); IntensityProfile::MeasurementType measurement; for (IntensityProfile::ConstIterator it = intensityProfile->Begin(); it != end; ++it) { measurement = it.GetMeasurementVector()[0]; if (measurement > max) { max = measurement; maxIndex = it.GetInstanceIdentifier(); } } return maxIndex; } IntensityProfile::InstanceIdentifier mitk::ComputeGlobalMinimum(IntensityProfile::ConstPointer intensityProfile, IntensityProfile::MeasurementType &min) { min = vcl_numeric_limits::max(); IntensityProfile::InstanceIdentifier minIndex = 0; IntensityProfile::ConstIterator end = intensityProfile->End(); IntensityProfile::MeasurementType measurement; for (IntensityProfile::ConstIterator it = intensityProfile->Begin(); it != end; ++it) { measurement = it.GetMeasurementVector()[0]; if (measurement < min) { min = measurement; minIndex = it.GetInstanceIdentifier(); } } return minIndex; } IntensityProfile::InstanceIdentifier mitk::ComputeCenterOfMaximumArea(IntensityProfile::ConstPointer intensityProfile, IntensityProfile::InstanceIdentifier radius) { //const IntensityProfile::MeasurementType min = intensityProfile->GetMeasurementVector(ComputeGlobalMinimum(intensityProfile))[0]; IntensityProfile::MeasurementType min; ComputeGlobalMinimum(intensityProfile, min); const IntensityProfile::InstanceIdentifier areaWidth = 1 + 2 * radius; IntensityProfile::MeasurementType maxArea = 0; for (IntensityProfile::InstanceIdentifier i = 0; i < areaWidth; ++i) maxArea += intensityProfile->GetMeasurementVector(i)[0] - min; const IntensityProfile::InstanceIdentifier lastIndex = intensityProfile->Size() - areaWidth; IntensityProfile::InstanceIdentifier centerOfMaxArea = radius; IntensityProfile::MeasurementType area = maxArea; for (IntensityProfile::InstanceIdentifier i = 1; i <= lastIndex; ++i) { area += intensityProfile->GetMeasurementVector(i + areaWidth - 1)[0] - min; area -= intensityProfile->GetMeasurementVector(i - 1)[0] - min; if (area > maxArea) { maxArea = area; centerOfMaxArea = i + radius; // TODO: If multiple areas in the neighborhood have the same intensity chose the middle one instead of the first one. } } return centerOfMaxArea; } std::vector mitk::CreateVectorFromIntensityProfile(IntensityProfile::ConstPointer intensityProfile) { std::vector result; result.reserve(intensityProfile->Size()); IntensityProfile::ConstIterator end = intensityProfile->End(); for (IntensityProfile::ConstIterator it = intensityProfile->Begin(); it != end; ++it) result.push_back(it.GetMeasurementVector()[0]); return result; } IntensityProfile::Pointer mitk::CreateIntensityProfileFromVector(const std::vector& vector) { const IntensityProfile::InstanceIdentifier size = vector.size(); IntensityProfile::Pointer result = IntensityProfile::New(); result->Resize(size); for (IntensityProfile::InstanceIdentifier i = 0; i < size; ++i) result->SetMeasurement(i, 0, vector[i]); return result; } -void mitk::ComputeIntensityProfileStatistics(IntensityProfile::ConstPointer intensityProfile, ImageStatisticsContainer::StatisticsObject& stats) +void mitk::ComputeIntensityProfileStatistics(IntensityProfile::ConstPointer intensityProfile, ImageStatisticsContainer::ImageStatisticsObject& stats) { typedef std::vector StatsVecType; StatsVecType statsVec = mitk::CreateVectorFromIntensityProfile( intensityProfile ); IntensityProfile::MeasurementType min; IntensityProfile::MeasurementType max; mitk::ComputeGlobalMinimum( intensityProfile, min ); mitk::ComputeGlobalMaximum( intensityProfile, max ); auto numSamples = static_cast(statsVec.size()); double mean = 0.0; double rms = 0.0; for ( StatsVecType::const_iterator it = statsVec.begin(); it != statsVec.end(); ++it ) { double val = *it; mean += val; rms += val*val; } mean /= static_cast(numSamples); rms /= static_cast(numSamples); double var = 0.0; for ( StatsVecType::const_iterator it = statsVec.begin(); it != statsVec.end(); ++it ) { double diff = *it - mean; var += diff*diff; } var /= (static_cast(numSamples) - 1 ); rms = sqrt( rms ); stats.AddStatistic(mitk::ImageStatisticsConstants::MINIMUM(), min); stats.AddStatistic(mitk::ImageStatisticsConstants::MAXIMUM(), max); stats.AddStatistic(mitk::ImageStatisticsConstants::NUMBEROFVOXELS(), numSamples); stats.AddStatistic(mitk::ImageStatisticsConstants::MEAN(), mean); stats.AddStatistic(mitk::ImageStatisticsConstants::STANDARDDEVIATION(), sqrt(var)); stats.AddStatistic(mitk::ImageStatisticsConstants::VARIANCE(), var); stats.AddStatistic(mitk::ImageStatisticsConstants::RMS(), rms); } diff --git a/Modules/ImageStatistics/mitkIntensityProfile.h b/Modules/ImageStatistics/mitkIntensityProfile.h index 82d5787a09..60207dff01 100644 --- a/Modules/ImageStatistics/mitkIntensityProfile.h +++ b/Modules/ImageStatistics/mitkIntensityProfile.h @@ -1,137 +1,137 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkIntensityProfile_h #define mitkIntensityProfile_h #include #include #include #include #include namespace mitk { typedef itk::Statistics::ListSample::MeasurementVectorType> IntensityProfile; /** \brief Compute intensity profile of an image for each pixel along the first PolyLine of a given planar figure. * * \param[in] image A two or three-dimensional image which consists of single component pixels. * \param[in] planarFigure A planar figure from which the first PolyLine is used to evaluate the intensity profile. * * \return The computed intensity profile. */ MITKIMAGESTATISTICS_EXPORT IntensityProfile::Pointer ComputeIntensityProfile(Image::Pointer image, PlanarFigure::Pointer planarFigure); namespace InterpolateImageFunction { enum Enum { NearestNeighbor, Linear, WindowedSinc_Blackman_3, WindowedSinc_Blackman_4, WindowedSinc_Blackman_5, WindowedSinc_Cosine_3, WindowedSinc_Cosine_4, WindowedSinc_Cosine_5, WindowedSinc_Hamming_3, WindowedSinc_Hamming_4, WindowedSinc_Hamming_5, WindowedSinc_Lanczos_3, WindowedSinc_Lanczos_4, WindowedSinc_Lanczos_5, WindowedSinc_Welch_3, WindowedSinc_Welch_4, WindowedSinc_Welch_5 }; } /** \brief Compute intensity profile of an image for each sample along a planar line. * * \param[in] image A three-dimensional image which consists of single component pixels. * \param[in] planarLine A planar line along which the intensity profile will be evaluated. * \param[in] numSamples Number of samples along the planar line (must be at least 2). * \param[in] interpolator Image interpolation function which is used to read each sample. * * \return The computed intensity profile. */ MITKIMAGESTATISTICS_EXPORT IntensityProfile::Pointer ComputeIntensityProfile(Image::Pointer image, PlanarLine::Pointer planarLine, unsigned int numSamples, InterpolateImageFunction::Enum interpolator = InterpolateImageFunction::NearestNeighbor); /** \brief Compute intensity profile of an image for each sample between two points. * * \param[in] image A three-dimensional image which consists of single component pixels. * \param[in] startPoint A point at which the first sample is to be read. * \param[in] endPoint A point at which the last sample is to be read. * \param[in] numSamples Number of samples between startPoint and endPoint (must be at least 2). * \param[in] interpolator Image interpolation function which is used to read each sample. * * \return The computed intensity profile. */ MITKIMAGESTATISTICS_EXPORT IntensityProfile::Pointer ComputeIntensityProfile(Image::Pointer image, const Point3D& startPoint, const Point3D& endPoint, unsigned int numSamples, InterpolateImageFunction::Enum interpolator = InterpolateImageFunction::NearestNeighbor); /** \brief Compute global maximum of an intensity profile. * * \param[in] intensityProfile An intensity profile. * * \return Index of the global maximum. */ MITKIMAGESTATISTICS_EXPORT IntensityProfile::InstanceIdentifier ComputeGlobalMaximum(IntensityProfile::ConstPointer intensityProfile, IntensityProfile::MeasurementType &max); /** \brief Compute global minimum of an intensity profile. * * \param[in] intensityProfile An intensity profile. * * \return Index of the global minimum. */ MITKIMAGESTATISTICS_EXPORT IntensityProfile::InstanceIdentifier ComputeGlobalMinimum(IntensityProfile::ConstPointer intensityProfile, IntensityProfile::MeasurementType &min); /** \brief Compute statistics of an intensity profile. * * \param[in] intensityProfile An intensity profile. * * \param[in] stats An ImageStatisticsCalculator::Statistics object to hold the calculated statistics. * */ - MITKIMAGESTATISTICS_EXPORT void ComputeIntensityProfileStatistics(IntensityProfile::ConstPointer intensityProfile, ImageStatisticsContainer::StatisticsObject& stats); + MITKIMAGESTATISTICS_EXPORT void ComputeIntensityProfileStatistics(IntensityProfile::ConstPointer intensityProfile, ImageStatisticsContainer::ImageStatisticsObject& stats); /** \brief Compute center of maximum area under the curve of an intensity profile. * * \param[in] intensityProfile An intensity profile. * \param[in] radius Radius of the area (width of area equals 1 + 2 * radius). * * \return Index of the maximum area center. */ MITKIMAGESTATISTICS_EXPORT IntensityProfile::InstanceIdentifier ComputeCenterOfMaximumArea(IntensityProfile::ConstPointer intensityProfile, IntensityProfile::InstanceIdentifier radius); /** \brief Convert an intensity profile to a standard library vector. * * \param[in] intensityProfile An intensity profile. * * \return Standard library vector which contains the input intensity profile measurements. */ MITKIMAGESTATISTICS_EXPORT std::vector CreateVectorFromIntensityProfile(IntensityProfile::ConstPointer intensityProfile); /** \brief Convert a standard library vector to an intensity profile. * * \param[in] vector An standard library vector which contains intensity profile measurements. * * \return An intensity profile. */ MITKIMAGESTATISTICS_EXPORT IntensityProfile::Pointer CreateIntensityProfileFromVector(const std::vector& vector); } #endif diff --git a/Modules/ImageStatistics/mitkPointSetDifferenceStatisticsCalculator.h b/Modules/ImageStatistics/mitkPointSetDifferenceStatisticsCalculator.h index 8d0b1589fa..3fc2ba5427 100644 --- a/Modules/ImageStatistics/mitkPointSetDifferenceStatisticsCalculator.h +++ b/Modules/ImageStatistics/mitkPointSetDifferenceStatisticsCalculator.h @@ -1,110 +1,110 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_PointSetDifferenceStatisticsCalculator_H #define _MITK_PointSetDifferenceStatisticsCalculator_H #include #include #include "mitkImageStatisticsCalculator.h" #include namespace mitk { /** * \brief Class for calculating the difference between two corresponding point sets. * The user can access the single distances between corresponding points as well as a complete statistic (mean, sd, rms, median, max, min) * The point sets must be of equal size! */ class MITKIMAGESTATISTICS_EXPORT PointSetDifferenceStatisticsCalculator : public itk::Object { public: mitkClassMacroItkParent( PointSetDifferenceStatisticsCalculator, itk::Object ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) mitkNewMacro2Param(PointSetDifferenceStatisticsCalculator,mitk::PointSet::Pointer,mitk::PointSet::Pointer); /*! \brief set point sets to be compared */ void SetPointSets(mitk::PointSet::Pointer pSet1, mitk::PointSet::Pointer pSet2); /*! \brief returns a vector holding the differences between the corresponding points of the point sets */ std::vector GetDifferences(); /*! \brief returns a vector holding the squared differences between the corresponding points of the point sets */ std::vector GetSquaredDifferences(); /*! \brief returns the mean distance of all corresponding points of the point sets */ double GetMean(); /*! \brief returns the standard deviation of the distances between all corresponding points of the point sets */ double GetSD(); /*! \brief returns the variance of the distances between all corresponding points of the point sets */ double GetVariance(); /*! \brief returns the root mean squared distance of all corresponding points of the point sets */ double GetRMS(); /*! \brief returns the median distance of all corresponding points of the point sets */ double GetMedian(); /*! \brief returns the maximal distance of all corresponding points of the point sets */ double GetMax(); /*! \brief returns the minimal distance of all corresponding points of the point sets */ double GetMin(); /*! \brief returns the total number of corresponding points of the point sets */ double GetNumberOfPoints(); protected: PointSetDifferenceStatisticsCalculator(); PointSetDifferenceStatisticsCalculator(mitk::PointSet::Pointer,mitk::PointSet::Pointer); ~PointSetDifferenceStatisticsCalculator() override; /*! \brief Method for computing the complete statistics of the differences between the given point sets. */ void ComputeStatistics(); - mitk::ImageStatisticsContainer::StatisticsObject m_Statistics; ///< struct holding the statistics + mitk::ImageStatisticsContainer::ImageStatisticsObject m_Statistics; ///< struct holding the statistics std::vector m_DifferencesVector; ///< vector holding the differences between the corresponding points std::vector m_SquaredDifferencesVector; ///< vector holding the squared differences between the corresponding points mitk::PointSet::Pointer m_PointSet1; ///< first point set used for comparison mitk::PointSet::Pointer m_PointSet2; ///< second point set used for comparison bool m_StatisticsCalculated; ///< flag indicating whether statistics are already calculated or not. }; } #endif // #define _MITK_PointSetDifferenceStatisticsCalculator_H