diff --git a/Modules/Multilabel/Testing/files.cmake b/Modules/Multilabel/Testing/files.cmake index bf283fc5a7..0a03695261 100644 --- a/Modules/Multilabel/Testing/files.cmake +++ b/Modules/Multilabel/Testing/files.cmake @@ -1,9 +1,9 @@ set(MODULE_TESTS mitkLabelTest.cpp mitkLabelSetTest.cpp mitkLabelSetImageTest.cpp - mitkLabelSetImageIOTest.cpp + mitkLegacyLabelSetImageIOTest.cpp mitkLabelSetImageSurfaceStampFilterTest.cpp mitkTransferLabelTest.cpp ) diff --git a/Modules/Multilabel/Testing/mitkLabelSetImageIOTest.cpp b/Modules/Multilabel/Testing/mitkLabelSetImageIOTest.cpp deleted file mode 100644 index e5bc2b557d..0000000000 --- a/Modules/Multilabel/Testing/mitkLabelSetImageIOTest.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ - -#include -#include - -#include -#include -#include -#include -#include -#include - -std::string pathToImage; - -class mitkLabelSetImageIOTestSuite : public mitk::TestFixture -{ - CPPUNIT_TEST_SUITE(mitkLabelSetImageIOTestSuite); - MITK_TEST(TestReadWrite3DLabelSetImage); - MITK_TEST(TestReadWrite3DplusTLabelSetImage); - MITK_TEST(TestReadWrite3DplusTLabelSetImageWithArbitraryGeometry); - MITK_TEST(TestReadWriteProperties); - CPPUNIT_TEST_SUITE_END(); - -private: - mitk::Image::Pointer regularImage; - mitk::LabelSetImage::Pointer multilabelImage; - -public: - void setUp() override - { - regularImage = mitk::Image::New(); - } - - void tearDown() override - { - regularImage = nullptr; - multilabelImage = nullptr; - } - - void TestReadWrite3DLabelSetImage() - { - unsigned int dimensions[3] = {30, 20, 10}; - regularImage->Initialize(mitk::MakeScalarPixelType(), 3, dimensions); - - multilabelImage = mitk::LabelSetImage::New(); - multilabelImage->Initialize(regularImage); - mitk::LabelSet::Pointer newlayer = mitk::LabelSet::New(); - newlayer->SetLayer(1); - mitk::Label::Pointer label0 = mitk::Label::New(); - label0->SetName("Background"); - label0->SetValue(0); - - mitk::Label::Pointer label1 = mitk::Label::New(); - label1->SetName("Label1"); - label1->SetValue(1); - - mitk::Label::Pointer label2 = mitk::Label::New(); - label2->SetName("Label2"); - label2->SetValue(200); - - newlayer->AddLabel(label0); - newlayer->AddLabel(label1); - newlayer->AddLabel(label2); - newlayer->SetActiveLabel(200); - - multilabelImage->AddLayer(newlayer); - - pathToImage = mitk::IOUtil::CreateTemporaryDirectory(); - pathToImage.append("/LabelSetTestImage3D.nrrd"); - - mitk::IOUtil::Save(multilabelImage, pathToImage); - - auto loadedImage = - mitk::IOUtil::Load(pathToImage); - - // This information is currently not serialized but also checked within the Equals function - loadedImage->SetActiveLayer(multilabelImage->GetActiveLayer()); - - CPPUNIT_ASSERT_MESSAGE("Error reading label set image", loadedImage.IsNotNull()); - CPPUNIT_ASSERT_MESSAGE("Error reading label set image", mitk::Equal(*multilabelImage, *loadedImage, 0.0001, true)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("Error, read image has different UID", multilabelImage->GetUID(), loadedImage->GetUID()); - - itksys::SystemTools::RemoveFile(pathToImage); - } - - void TestReadWrite3DplusTLabelSetImage() - { - unsigned int dimensions[4] = {30, 20, 15, 10}; - regularImage->Initialize(mitk::MakeScalarPixelType(), 4, dimensions); - - multilabelImage = mitk::LabelSetImage::New(); - multilabelImage->Initialize(regularImage); - mitk::LabelSet::Pointer newlayer = mitk::LabelSet::New(); - newlayer->SetLayer(1); - mitk::Label::Pointer label0 = mitk::Label::New(); - label0->SetName("Background"); - label0->SetValue(0); - - mitk::Label::Pointer label1 = mitk::Label::New(); - label1->SetName("Label1"); - label1->SetValue(1); - - mitk::Label::Pointer label2 = mitk::Label::New(); - label2->SetName("Label2"); - label2->SetValue(200); - - newlayer->AddLabel(label0); - newlayer->AddLabel(label1); - newlayer->AddLabel(label2); - newlayer->SetActiveLabel(200); - - multilabelImage->AddLayer(newlayer); - - pathToImage = mitk::IOUtil::CreateTemporaryDirectory(); - pathToImage.append("/LabelSetTestImage3DplusT.nrrd"); - - mitk::IOUtil::Save(multilabelImage, pathToImage); - - auto loadedImage = - mitk::IOUtil::Load(pathToImage); - - // This information is currently not serialized but also checked within the Equals function - loadedImage->SetActiveLayer(multilabelImage->GetActiveLayer()); - - CPPUNIT_ASSERT_MESSAGE("Error reading label set image", loadedImage.IsNotNull()); - CPPUNIT_ASSERT_MESSAGE("Error reading label set image", mitk::Equal(*multilabelImage, *loadedImage, 0.0001, true)); - CPPUNIT_ASSERT_MESSAGE("Error reading time geometry of label set image", mitk::Equal(*(multilabelImage->GetTimeGeometry()), *(loadedImage->GetTimeGeometry()), 0.000000001, true)); - - itksys::SystemTools::RemoveFile(pathToImage); - } - - void TestReadWrite3DplusTLabelSetImageWithArbitraryGeometry() - { - unsigned int dimensions[4] = { 30, 20, 10, 4 }; - regularImage->Initialize(mitk::MakeScalarPixelType(), 4, dimensions); - - multilabelImage = mitk::LabelSetImage::New(); - multilabelImage->Initialize(regularImage); - mitk::LabelSet::Pointer newlayer = mitk::LabelSet::New(); - newlayer->SetLayer(1); - mitk::Label::Pointer label0 = mitk::Label::New(); - label0->SetName("Background"); - label0->SetValue(0); - - mitk::Label::Pointer label1 = mitk::Label::New(); - label1->SetName("Label1"); - label1->SetValue(1); - - mitk::Label::Pointer label2 = mitk::Label::New(); - label2->SetName("Label2"); - label2->SetValue(200); - - newlayer->AddLabel(label0); - newlayer->AddLabel(label1); - newlayer->AddLabel(label2); - newlayer->SetActiveLabel(200); - - multilabelImage->AddLayer(newlayer); - - auto geometry = multilabelImage->GetGeometry()->Clone(); - - auto refTimeGeometry = mitk::ArbitraryTimeGeometry::New(); - refTimeGeometry->AppendNewTimeStep(geometry, 0., 0.5); - refTimeGeometry->AppendNewTimeStep(geometry, 0.5, 1.); - refTimeGeometry->AppendNewTimeStep(geometry, 1., 2.); - refTimeGeometry->AppendNewTimeStep(geometry, 2., 5.5); - multilabelImage->SetTimeGeometry(refTimeGeometry); - - pathToImage = mitk::IOUtil::CreateTemporaryDirectory(); - pathToImage.append("/LabelSetTestImage3DplusTWithArbitraryTimeGeometry.nrrd"); - - mitk::IOUtil::Save(multilabelImage, pathToImage); - - auto loadedImage = - mitk::IOUtil::Load(pathToImage); - - // This information is currently not serialized but also checked within the Equals function - loadedImage->SetActiveLayer(multilabelImage->GetActiveLayer()); - - CPPUNIT_ASSERT_MESSAGE("Error reading label set image", loadedImage.IsNotNull()); - CPPUNIT_ASSERT_MESSAGE("Error reading label set image", mitk::Equal(*multilabelImage, *loadedImage, 0.0001, true)); - CPPUNIT_ASSERT_MESSAGE("Error reading time geometry of label set image", mitk::Equal(*refTimeGeometry, *(loadedImage->GetTimeGeometry()), 0.000000001, true)); - itksys::SystemTools::RemoveFile(pathToImage); - } - - void TestReadWriteProperties() - { - unsigned int dimensions[3] = { 30, 20, 10 }; - regularImage->Initialize(mitk::MakeScalarPixelType(), 3, dimensions); - - multilabelImage = mitk::LabelSetImage::New(); - multilabelImage->Initialize(regularImage); - mitk::LabelSet::Pointer newlayer = mitk::LabelSet::New(); - newlayer->SetLayer(1); - mitk::Label::Pointer label0 = mitk::Label::New(); - label0->SetName("Background"); - label0->SetValue(0); - newlayer->AddLabel(label0); - multilabelImage->AddLayer(newlayer); - - auto propPersistenceInfo = mitk::PropertyPersistenceInfo::New(); - propPersistenceInfo->SetNameAndKey("my.cool.test.property", "my_cool_test_property"); - mitk::CoreServicePointer propPersService(mitk::CoreServices::GetPropertyPersistence()); - propPersService->AddInfo(propPersistenceInfo); - - multilabelImage->SetProperty("my.cool.test.property", mitk::StringProperty::New("test_content")); - - pathToImage = mitk::IOUtil::CreateTemporaryDirectory(); - pathToImage.append("/LabelSetPropertiesTestImage.nrrd"); - - mitk::IOUtil::Save(multilabelImage, pathToImage); - - auto loadedImage = - mitk::IOUtil::Load(pathToImage); - - auto loadedProp = loadedImage->GetProperty("my.cool.test.property"); - CPPUNIT_ASSERT_MESSAGE("Error reading properties of label set image", loadedProp.IsNotNull()); - CPPUNIT_ASSERT_MESSAGE("Error reading properties of label set image", loadedProp->GetValueAsString() == "test_content"); - itksys::SystemTools::RemoveFile(pathToImage); - } - - -}; - -MITK_TEST_SUITE_REGISTRATION(mitkLabelSetImageIO) diff --git a/Modules/Multilabel/Testing/mitkLegacyLabelSetImageIOTest.cpp b/Modules/Multilabel/Testing/mitkLegacyLabelSetImageIOTest.cpp new file mode 100644 index 0000000000..80a7eb7fba --- /dev/null +++ b/Modules/Multilabel/Testing/mitkLegacyLabelSetImageIOTest.cpp @@ -0,0 +1,142 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include +#include + +#include +#include +#include +#include +#include +#include + +std::string pathToImage; + +class mitkLegacyLabelSetImageIOTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkLegacyLabelSetImageIOTestSuite); + MITK_TEST(TestRead3DLabelSetImage_Default); + MITK_TEST(TestRead3DLabelSetImage_Adapt); + MITK_TEST(TestRead3DLabelSetImage_Split); + MITK_TEST(TestRead3DplusTLabelSetImage); + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::LabelSet::Pointer m_labelSet1; + mitk::LabelSet::Pointer m_labelSet2; + mitk::LabelSet::Pointer m_labelSet2_adapted; + +public: + mitk::Label::Pointer GenerateLabel(mitk::Label::PixelType value, const std::string& name, float r, float g, float b) const + { + auto label = mitk::Label::New(value, name); + mitk::Color color; + color.SetRed(r); + color.SetGreen(g); + color.SetBlue(b); + label->SetColor(color); + + return label; + } + + void setUp() override + { + m_labelSet1 = mitk::LabelSet::New(); + auto label = GenerateLabel(1, "Label 1", 0.745098054f, 0.f, 0.196078435f); + m_labelSet1->AddLabel(label,false); + label = GenerateLabel(2, "Label 2", 0.952941179, 0.764705896, 0); + m_labelSet1->AddLabel(label, false); + + m_labelSet2 = mitk::LabelSet::New(); + label = GenerateLabel(1, "Label 3", 0.552941203, 0.713725507, 0); + m_labelSet2->AddLabel(label, false); + label = GenerateLabel(2, "Label 4", 0.631372571, 0.792156875, 0.945098042); + m_labelSet2->AddLabel(label, false); + label = GenerateLabel(3, "Label 5", 0.639215708, 0.250980407, 0.725490212); + m_labelSet2->AddLabel(label, false); + + m_labelSet2_adapted = mitk::LabelSet::New(); + label = GenerateLabel(3, "Label 3", 0.552941203, 0.713725507, 0); + m_labelSet2_adapted->AddLabel(label, false); + label = GenerateLabel(4, "Label 4", 0.631372571, 0.792156875, 0.945098042); + m_labelSet2_adapted->AddLabel(label, false); + label = GenerateLabel(5, "Label 5", 0.639215708, 0.250980407, 0.725490212); + m_labelSet2_adapted->AddLabel(label, false); + m_labelSet2_adapted->SetLayer(1); + } + + void tearDown() override + { + m_labelSet1 = nullptr; + m_labelSet2 = nullptr; + m_labelSet2_adapted = nullptr; + } + + void TestRead3DLabelSetImage_Default() + { + auto testImages = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LegacyLabelSetTestImage3D.nrrd")); + + CPPUNIT_ASSERT_MESSAGE("Error reading label set image", testImages.size()==1); + + auto lsimage1 = dynamic_cast(testImages[0].GetPointer()); + + CPPUNIT_ASSERT_MESSAGE("Number of layers is not correct", lsimage1->GetNumberOfLayers() == 2); + CPPUNIT_ASSERT_MESSAGE("Error layer 0 is not equal", mitk::Equal(*m_labelSet1, *(lsimage1->GetLabelSet(0)), mitk::eps, true)); + CPPUNIT_ASSERT_MESSAGE("Error layer 1 is not equal", mitk::Equal(*m_labelSet2_adapted, *(lsimage1->GetLabelSet(1)), mitk::eps, true)); + + CPPUNIT_ASSERT_MESSAGE("Error, read image has different UID", "c236532b-f95a-4f22-a4c6-7abe4e41ad10"== lsimage1->GetUID()); + } + + void TestRead3DLabelSetImage_Adapt() + { + mitk::IFileReader::Options options = { {"Multi layer handling", us::Any(std::string("Adapt label values"))} }; + auto testImages = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LegacyLabelSetTestImage3D.nrrd"), options); + + CPPUNIT_ASSERT_MESSAGE("Error reading label set image", testImages.size() == 1); + + auto lsimage1 = dynamic_cast(testImages[0].GetPointer()); + + CPPUNIT_ASSERT_MESSAGE("Number of layers is not correct", lsimage1->GetNumberOfLayers() == 2); + CPPUNIT_ASSERT_MESSAGE("Error layer 0 is not equal", mitk::Equal(*m_labelSet1, *(lsimage1->GetLabelSet(0)), mitk::eps, true)); + CPPUNIT_ASSERT_MESSAGE("Error layer 1 is not equal", mitk::Equal(*m_labelSet2_adapted, *(lsimage1->GetLabelSet(1)), mitk::eps, true)); + + CPPUNIT_ASSERT_MESSAGE("Error, read image has different UID", "c236532b-f95a-4f22-a4c6-7abe4e41ad10" == lsimage1->GetUID()); + } + + void TestRead3DLabelSetImage_Split() + { + mitk::IFileReader::Options options = { {"Multi layer handling", us::Any(std::string("Split layers"))} }; + auto testImages = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LegacyLabelSetTestImage3D.nrrd"), options); + + CPPUNIT_ASSERT_MESSAGE("Error reading label set image", testImages.size() == 2); + + auto lsimage1 = dynamic_cast(testImages[0].GetPointer()); + auto lsimage2 = dynamic_cast(testImages[1].GetPointer()); + + CPPUNIT_ASSERT_MESSAGE("Number of layers in image 1 isnot correct", lsimage1->GetNumberOfLayers() == 1); + CPPUNIT_ASSERT_MESSAGE("Number of layers in image 2 is not correct", lsimage2->GetNumberOfLayers() == 1); + CPPUNIT_ASSERT_MESSAGE("Error layer 0 is not equal", mitk::Equal(*m_labelSet1, *(lsimage1->GetLabelSet(0)), mitk::eps, true)); + CPPUNIT_ASSERT_MESSAGE("Error layer 1 is not equal", mitk::Equal(*m_labelSet2, *(lsimage2->GetLabelSet(0)), mitk::eps, true)); + + CPPUNIT_ASSERT_MESSAGE("Error, read image has same UID", "c236532b-f95a-4f22-a4c6-7abe4e41ad10" != lsimage1->GetUID()); + + } + + void TestRead3DplusTLabelSetImage() + { + + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkLegacyLabelSetImageIO) diff --git a/Modules/Multilabel/Testing/mitkTransferLabelTest.cpp b/Modules/Multilabel/Testing/mitkTransferLabelTest.cpp index 6df3b1d69a..218fe15e55 100644 --- a/Modules/Multilabel/Testing/mitkTransferLabelTest.cpp +++ b/Modules/Multilabel/Testing/mitkTransferLabelTest.cpp @@ -1,142 +1,229 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include class mitkTransferLabelTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkTransferLabelTestSuite); MITK_TEST(TestTransfer_defaults); MITK_TEST(TestTransfer_Merge_RegardLocks); MITK_TEST(TestTransfer_Merge_IgnoreLocks); MITK_TEST(TestTransfer_Replace_RegardLocks); MITK_TEST(TestTransfer_Replace_IgnoreLocks); MITK_TEST(TestTransfer_multipleLabels); + MITK_TEST(TestTransfer_Merge_RegardLocks_AtTimeStep); + MITK_TEST(TestTransfer_Merge_IgnoreLocks_AtTimeStep); + MITK_TEST(TestTransfer_Replace_RegardLocks_AtTimeStep); + MITK_TEST(TestTransfer_Replace_IgnoreLocks_AtTimeStep); + MITK_TEST(TestTransfer_multipleLabels_AtTimeStep); CPPUNIT_TEST_SUITE_END(); private: mitk::LabelSetImage::Pointer m_SourceImage; public: void setUp() override { m_SourceImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_source.nrrd")); } void tearDown() override { m_SourceImage = nullptr; } void TestTransfer_defaults() { auto destinationImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination.nrrd")); auto destinationLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination_lockedExterior.nrrd")); auto refmage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_replace_regardLocks.nrrd")); auto refLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_replace_regardLocks_lockedExterior.nrrd")); mitk::TransferLabelContent(m_SourceImage, destinationImage); mitk::TransferLabelContent(m_SourceImage, destinationLockedExteriorImage); CPPUNIT_ASSERT_MESSAGE("Transfer with default settings failed", mitk::Equal(*(destinationImage.GetPointer()), *(refmage.GetPointer()), mitk::eps, false)); CPPUNIT_ASSERT_MESSAGE("Transfer with default settings + exterior lock failed", mitk::Equal(*(destinationLockedExteriorImage.GetPointer()), *(refLockedExteriorImage.GetPointer()), mitk::eps, false)); } void TestTransfer_Merge_RegardLocks() { auto destinationImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination.nrrd")); auto destinationLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination_lockedExterior.nrrd")); auto refmage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_merge_regardLocks.nrrd")); auto refLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_merge_regardLocks_lockedExterior.nrrd")); mitk::TransferLabelContent(m_SourceImage, destinationImage, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Merge, mitk::MultiLabelSegmentation::OverwriteStyle::RegardLocks); mitk::TransferLabelContent(m_SourceImage, destinationLockedExteriorImage, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Merge, mitk::MultiLabelSegmentation::OverwriteStyle::RegardLocks); CPPUNIT_ASSERT_MESSAGE("Transfer with merge + regardLocks settings failed", mitk::Equal(*(destinationImage.GetPointer()), *(refmage.GetPointer()), mitk::eps, false)); CPPUNIT_ASSERT_MESSAGE("Transfer with merge + regardLocks + exterior lock settings failed", mitk::Equal(*(destinationLockedExteriorImage.GetPointer()), *(refLockedExteriorImage.GetPointer()), mitk::eps, false)); } void TestTransfer_Merge_IgnoreLocks() { auto destinationImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination.nrrd")); auto destinationLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination_lockedExterior.nrrd")); auto refmage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_merge_ignoreLocks.nrrd")); auto refLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_merge_ignoreLocks_lockedExterior.nrrd")); mitk::TransferLabelContent(m_SourceImage, destinationImage, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Merge, mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); mitk::TransferLabelContent(m_SourceImage, destinationLockedExteriorImage, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Merge, mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); CPPUNIT_ASSERT_MESSAGE("Transfer with merge + ignoreLocks settings failed", mitk::Equal(*(destinationImage.GetPointer()), *(refmage.GetPointer()), mitk::eps, false)); CPPUNIT_ASSERT_MESSAGE("Transfer with merge + ignoreLocks + exterior lock settings failed", mitk::Equal(*(destinationLockedExteriorImage.GetPointer()), *(refLockedExteriorImage.GetPointer()), mitk::eps, false)); } void TestTransfer_Replace_RegardLocks() { auto destinationImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination.nrrd")); auto destinationLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination_lockedExterior.nrrd")); auto refmage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_replace_regardLocks.nrrd")); auto refLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_replace_regardLocks_lockedExterior.nrrd")); mitk::TransferLabelContent(m_SourceImage, destinationImage, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Replace, mitk::MultiLabelSegmentation::OverwriteStyle::RegardLocks); mitk::TransferLabelContent(m_SourceImage, destinationLockedExteriorImage, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Replace, mitk::MultiLabelSegmentation::OverwriteStyle::RegardLocks); CPPUNIT_ASSERT_MESSAGE("Transfer with replace + regardLocks settings failed", mitk::Equal(*(destinationImage.GetPointer()), *(refmage.GetPointer()), mitk::eps, false)); CPPUNIT_ASSERT_MESSAGE("Transfer with replace + regardLocks + exterior lock settings failed", mitk::Equal(*(destinationLockedExteriorImage.GetPointer()), *(refLockedExteriorImage.GetPointer()), mitk::eps, false)); } void TestTransfer_Replace_IgnoreLocks() { auto destinationImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination.nrrd")); auto destinationLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination_lockedExterior.nrrd")); auto refmage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_replace_ignoreLocks.nrrd")); auto refLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_replace_ignoreLocks_lockedExterior.nrrd")); mitk::TransferLabelContent(m_SourceImage, destinationImage, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Replace, mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); mitk::TransferLabelContent(m_SourceImage, destinationLockedExteriorImage, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Replace, mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); CPPUNIT_ASSERT_MESSAGE("Transfer with replace + ignoreLocks settings failed", mitk::Equal(*(destinationImage.GetPointer()), *(refmage.GetPointer()), mitk::eps, false)); CPPUNIT_ASSERT_MESSAGE("Transfer with replace + ignoreLocks + exterior lock settings failed", mitk::Equal(*(destinationLockedExteriorImage.GetPointer()), *(refLockedExteriorImage.GetPointer()), mitk::eps, false)); } void TestTransfer_multipleLabels() { auto destinationImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination.nrrd")); auto destinationLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination_lockedExterior.nrrd")); auto refmage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_multipleLabels.nrrd")); auto refLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_multipleLabels_lockedExterior.nrrd")); mitk::TransferLabelContent(m_SourceImage, destinationImage, { {1,1}, {3,1}, {2,4}, {4,2} }, mitk::MultiLabelSegmentation::MergeStyle::Replace, mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); mitk::TransferLabelContent(m_SourceImage, destinationLockedExteriorImage, { {1,1}, {3,1}, {2,4}, {4,2} }, mitk::MultiLabelSegmentation::MergeStyle::Replace, mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); CPPUNIT_ASSERT_MESSAGE("Transfer multiple labels (1->1, 3->1, 2->4, 4->2) with replace + ignoreLocks settings failed", mitk::Equal(*(destinationImage.GetPointer()), *(refmage.GetPointer()), mitk::eps, false)); CPPUNIT_ASSERT_MESSAGE("Transfer multiple labels (1->1, 3->1, 2->4, 4->2) with replace + ignoreLocks + exterior lock settings failed", mitk::Equal(*(destinationLockedExteriorImage.GetPointer()), *(refLockedExteriorImage.GetPointer()), mitk::eps, false)); } + void TestTransfer_Merge_RegardLocks_AtTimeStep() + { + auto destinationImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination.nrrd")); + auto destinationLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination_lockedExterior.nrrd")); + auto refmage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_merge_regardLocks.nrrd")); + auto refLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_merge_regardLocks_lockedExterior.nrrd")); + + mitk::TransferLabelContentAtTimeStep(m_SourceImage, destinationImage, 0, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Merge, mitk::MultiLabelSegmentation::OverwriteStyle::RegardLocks); + mitk::TransferLabelContentAtTimeStep(m_SourceImage, destinationLockedExteriorImage, 0, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Merge, mitk::MultiLabelSegmentation::OverwriteStyle::RegardLocks); + + CPPUNIT_ASSERT_MESSAGE("Transfer with merge + regardLocks settings failed", + mitk::Equal(*(destinationImage.GetPointer()), *(refmage.GetPointer()), mitk::eps, false)); + CPPUNIT_ASSERT_MESSAGE("Transfer with merge + regardLocks + exterior lock settings failed", + mitk::Equal(*(destinationLockedExteriorImage.GetPointer()), *(refLockedExteriorImage.GetPointer()), mitk::eps, false)); + } + + void TestTransfer_Merge_IgnoreLocks_AtTimeStep() + { + auto destinationImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination.nrrd")); + auto destinationLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination_lockedExterior.nrrd")); + auto refmage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_merge_ignoreLocks.nrrd")); + auto refLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_merge_ignoreLocks_lockedExterior.nrrd")); + + mitk::TransferLabelContentAtTimeStep(m_SourceImage, destinationImage, 0, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Merge, mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); + mitk::TransferLabelContentAtTimeStep(m_SourceImage, destinationLockedExteriorImage, 0, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Merge, mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); + + CPPUNIT_ASSERT_MESSAGE("Transfer with merge + ignoreLocks settings failed", + mitk::Equal(*(destinationImage.GetPointer()), *(refmage.GetPointer()), mitk::eps, false)); + CPPUNIT_ASSERT_MESSAGE("Transfer with merge + ignoreLocks + exterior lock settings failed", + mitk::Equal(*(destinationLockedExteriorImage.GetPointer()), *(refLockedExteriorImage.GetPointer()), mitk::eps, false)); + } + + void TestTransfer_Replace_RegardLocks_AtTimeStep() + { + auto destinationImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination.nrrd")); + auto destinationLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination_lockedExterior.nrrd")); + auto refmage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_replace_regardLocks.nrrd")); + auto refLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_replace_regardLocks_lockedExterior.nrrd")); + + mitk::TransferLabelContentAtTimeStep(m_SourceImage, destinationImage, 0, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Replace, mitk::MultiLabelSegmentation::OverwriteStyle::RegardLocks); + mitk::TransferLabelContentAtTimeStep(m_SourceImage, destinationLockedExteriorImage, 0, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Replace, mitk::MultiLabelSegmentation::OverwriteStyle::RegardLocks); + + CPPUNIT_ASSERT_MESSAGE("Transfer with replace + regardLocks settings failed", + mitk::Equal(*(destinationImage.GetPointer()), *(refmage.GetPointer()), mitk::eps, false)); + CPPUNIT_ASSERT_MESSAGE("Transfer with replace + regardLocks + exterior lock settings failed", + mitk::Equal(*(destinationLockedExteriorImage.GetPointer()), *(refLockedExteriorImage.GetPointer()), mitk::eps, false)); + } + + void TestTransfer_Replace_IgnoreLocks_AtTimeStep() + { + auto destinationImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination.nrrd")); + auto destinationLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination_lockedExterior.nrrd")); + auto refmage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_replace_ignoreLocks.nrrd")); + auto refLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_replace_ignoreLocks_lockedExterior.nrrd")); + + mitk::TransferLabelContentAtTimeStep(m_SourceImage, destinationImage, 0, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Replace, mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); + mitk::TransferLabelContentAtTimeStep(m_SourceImage, destinationLockedExteriorImage, 0, { {1,1} }, mitk::MultiLabelSegmentation::MergeStyle::Replace, mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); + + CPPUNIT_ASSERT_MESSAGE("Transfer with replace + ignoreLocks settings failed", + mitk::Equal(*(destinationImage.GetPointer()), *(refmage.GetPointer()), mitk::eps, false)); + CPPUNIT_ASSERT_MESSAGE("Transfer with replace + ignoreLocks + exterior lock settings failed", + mitk::Equal(*(destinationLockedExteriorImage.GetPointer()), *(refLockedExteriorImage.GetPointer()), mitk::eps, false)); + } + + + void TestTransfer_multipleLabels_AtTimeStep() + { + auto destinationImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination.nrrd")); + auto destinationLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_destination_lockedExterior.nrrd")); + auto refmage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_multipleLabels.nrrd")); + auto refLockedExteriorImage = mitk::IOUtil::Load(GetTestDataFilePath("Multilabel/LabelTransferTest_result_multipleLabels_lockedExterior.nrrd")); + + mitk::TransferLabelContentAtTimeStep(m_SourceImage, destinationImage, 0, { {1,1}, {3,1}, {2,4}, {4,2} }, mitk::MultiLabelSegmentation::MergeStyle::Replace, mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); + mitk::TransferLabelContentAtTimeStep(m_SourceImage, destinationLockedExteriorImage, 0, { {1,1}, {3,1}, {2,4}, {4,2} }, mitk::MultiLabelSegmentation::MergeStyle::Replace, mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); + + CPPUNIT_ASSERT_MESSAGE("Transfer multiple labels (1->1, 3->1, 2->4, 4->2) with replace + ignoreLocks settings failed", + mitk::Equal(*(destinationImage.GetPointer()), *(refmage.GetPointer()), mitk::eps, false)); + CPPUNIT_ASSERT_MESSAGE("Transfer multiple labels (1->1, 3->1, 2->4, 4->2) with replace + ignoreLocks + exterior lock settings failed", + mitk::Equal(*(destinationLockedExteriorImage.GetPointer()), *(refLockedExteriorImage.GetPointer()), mitk::eps, false)); + } + + }; MITK_TEST_SUITE_REGISTRATION(mitkTransferLabel) diff --git a/Modules/Multilabel/autoload/IO/mitkLegacyLabelSetImageIO.cpp b/Modules/Multilabel/autoload/IO/mitkLegacyLabelSetImageIO.cpp index 5a32b5ca74..50bea6d8bc 100644 --- a/Modules/Multilabel/autoload/IO/mitkLegacyLabelSetImageIO.cpp +++ b/Modules/Multilabel/autoload/IO/mitkLegacyLabelSetImageIO.cpp @@ -1,266 +1,272 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef __mitkLabelSetImageWriter__cpp #define __mitkLabelSetImageWriter__cpp #include "mitkLegacyLabelSetImageIO.h" #include "mitkBasePropertySerializer.h" #include "mitkMultilabelIOMimeTypes.h" #include "mitkImageAccessByItk.h" #include "mitkMultiLabelIOHelper.h" #include "mitkLabelSetImageConverter.h" #include #include #include #include #include #include // itk #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkMetaDataDictionary.h" #include "itkMetaDataObject.h" #include "itkNrrdImageIO.h" #include namespace mitk { constexpr char* const OPTION_NAME_MULTI_LAYER = "Multi layer handling"; constexpr char* const OPTION_NAME_MULTI_LAYER_ADAPT = "Adapt label values"; constexpr char* const OPTION_NAME_MULTI_LAYER_SPLIT = "Split layers"; LegacyLabelSetImageIO::LegacyLabelSetImageIO() : AbstractFileReader(MitkMultilabelIOMimeTypes::LEGACYLABELSET_MIMETYPE(), "MITK LabelSetImage (legacy)") { this->InitializeDefaultMetaDataKeys(); AbstractFileReader::SetRanking(10); IFileIO::Options options; std::vector multiLayerStrategy; multiLayerStrategy.push_back(OPTION_NAME_MULTI_LAYER_ADAPT); multiLayerStrategy.push_back(OPTION_NAME_MULTI_LAYER_SPLIT); options[OPTION_NAME_MULTI_LAYER] = multiLayerStrategy; this->SetDefaultOptions(options); this->RegisterService(); } IFileIO::ConfidenceLevel LegacyLabelSetImageIO::GetConfidenceLevel() const { if (AbstractFileReader::GetConfidenceLevel() == Unsupported) return Unsupported; const std::string fileName = this->GetLocalFileName(); itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); io->SetFileName(fileName); io->ReadImageInformation(); itk::MetaDataDictionary imgMetaDataDictionary = io->GetMetaDataDictionary(); std::string value(""); itk::ExposeMetaData(imgMetaDataDictionary, "modality", value); if (value.compare("org.mitk.image.multilabel") == 0) { return Supported; } else return Unsupported; } std::vector ExtractLabelSetsFromMetaData(const itk::MetaDataDictionary& dictionary) { std::vector result; // get labels and add them as properties to the image char keybuffer[256]; unsigned int numberOfLayers = MultiLabelIOHelper::GetIntByKey(dictionary, "layers"); std::string _xmlStr; mitk::Label::Pointer label; for (unsigned int layerIdx = 0; layerIdx < numberOfLayers; layerIdx++) { sprintf(keybuffer, "layer_%03u", layerIdx); int numberOfLabels = MultiLabelIOHelper::GetIntByKey(dictionary, keybuffer); mitk::LabelSet::Pointer labelSet = mitk::LabelSet::New(); for (int labelIdx = 0; labelIdx < numberOfLabels; labelIdx++) { tinyxml2::XMLDocument doc; sprintf(keybuffer, "label_%03u_%05d", layerIdx, labelIdx); _xmlStr = MultiLabelIOHelper::GetStringByKey(dictionary, keybuffer); doc.Parse(_xmlStr.c_str(), _xmlStr.size()); auto* labelElem = doc.FirstChildElement("Label"); if (labelElem == nullptr) mitkThrow() << "Error parsing NRRD header for mitk::LabelSetImage IO"; label = mitk::MultiLabelIOHelper::LoadLabelFromXMLDocument(labelElem); if (label->GetValue() != mitk::LabelSetImage::UnlabeledLabelValue) { labelSet->AddLabel(label); labelSet->SetLayer(layerIdx); } else { MITK_INFO << "Multi label image contains a label specification for unlabeled pixels. This legacy information is ignored."; } } result.push_back(labelSet); } return result; } std::vector LegacyLabelSetImageIO::DoRead() { itk::NrrdImageIO::Pointer nrrdImageIO = itk::NrrdImageIO::New(); std::vector result; auto rawimage = ItkImageIO::LoadRawMitkImageFromImageIO(nrrdImageIO, this->GetLocalFileName()); const itk::MetaDataDictionary& dictionary = nrrdImageIO->GetMetaDataDictionary(); - auto groupImages = SplitVectorImage(rawimage); + std::vector groupImages = { rawimage }; + if (rawimage->GetChannelDescriptor().GetPixelType().GetPixelType() == itk::IOPixelEnum::VECTOR) + { + groupImages = SplitVectorImage(rawimage); + } + auto labelsets = ExtractLabelSetsFromMetaData(dictionary); if (labelsets.size() != groupImages.size()) { mitkThrow() << "Loaded data is in an invalid state. Number of extracted layer images and labels sets does not match. Found layer images: " << groupImages.size() << "; found labelsets: " << labelsets.size(); } auto props = ItkImageIO::ExtractMetaDataAsPropertyList(nrrdImageIO->GetMetaDataDictionary(), this->GetMimeType()->GetName(), this->m_DefaultMetaDataKeys); const Options userOptions = this->GetOptions(); const auto multiLayerStrategy = userOptions.find(OPTION_NAME_MULTI_LAYER)->second.ToString(); if (multiLayerStrategy == OPTION_NAME_MULTI_LAYER_SPLIT) { //just split layers in different multi label images auto labelSetIterator = labelsets.begin(); for (auto image : groupImages) { auto output = ConvertImageToLabelSetImage(image); output->AddLabelSetToLayer(0, *labelSetIterator); + output->GetLabelSet(0)->SetLayer(0); //meta data handling for (auto& [name, prop] : *(props->GetMap())) { output->SetProperty(name, prop->Clone()); //need to clone to avoid that all outputs pointing to the same prop instances. } // Handle UID //Remark if we split the legacy label set into distinct layer images, the outputs should have new IDs. So we don't get the old one. result.push_back(output.GetPointer()); labelSetIterator++; } } else { //Avoid label id collision. LabelSetImage::LabelValueType maxValue = LabelSetImage::UnlabeledLabelValue; auto imageIterator = groupImages.begin(); std::vector adaptedLabelSets; for (auto labelset : labelsets) { const auto setValues = labelset->GetUsedLabelValues(); //generate mapping table; std::vector > labelMapping; for (auto vIter = setValues.crbegin(); vIter != setValues.crend(); vIter++) { //have to use reverse loop because TransferLabelContent (used to adapt content in the same image; see below) //would potentially corrupt otherwise the content due to "value collision between old values still present //and already adapted values. By going from highest value to lowest, we avoid that. if (LabelSetImage::UnlabeledLabelValue != *vIter) labelMapping.push_back({ *vIter, *vIter + maxValue }); } if (LabelSetImage::UnlabeledLabelValue != maxValue) { //adapt labelset auto mappedLabelSet = GenerateLabelSetWithMappedValues(labelset, labelMapping); adaptedLabelSets.emplace_back(mappedLabelSet); //adapt image (it is an inplace operation. the image instance stays the same. TransferLabelContent(*imageIterator, *imageIterator, mappedLabelSet, LabelSetImage::UnlabeledLabelValue, LabelSetImage::UnlabeledLabelValue, false, labelMapping, MultiLabelSegmentation::MergeStyle::Replace, MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); } else { adaptedLabelSets.emplace_back(labelset); } const auto setMaxValue = *(std::max_element(setValues.begin(), setValues.end())); maxValue += setMaxValue; imageIterator++; } auto output = ConvertImageVectorToLabelSetImage(groupImages, rawimage->GetTimeGeometry()); LabelSetImage::SpatialGroupIndexType id = 0; for (auto labelset : adaptedLabelSets) { output->AddLabelSetToLayer(id, labelset); id++; } //meta data handling for (auto& [name, prop] : *(props->GetMap())) { output->SetProperty(name, prop->Clone()); //need to clone to avoid that all outputs pointing to the same prop instances. } // Handle UID if (dictionary.HasKey(PROPERTY_KEY_UID)) { itk::MetaDataObject::ConstPointer uidData = dynamic_cast*>(dictionary.Get(PROPERTY_KEY_UID)); if (uidData.IsNotNull()) { mitk::UIDManipulator uidManipulator(output); uidManipulator.SetUID(uidData->GetMetaDataObjectValue()); } } result.push_back(output.GetPointer()); } MITK_INFO << "...finished!"; return result; } LegacyLabelSetImageIO *LegacyLabelSetImageIO::Clone() const { return new LegacyLabelSetImageIO(*this); } void LegacyLabelSetImageIO::InitializeDefaultMetaDataKeys() { this->m_DefaultMetaDataKeys.push_back("NRRD.space"); this->m_DefaultMetaDataKeys.push_back("NRRD.kinds"); this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TYPE); this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS); this->m_DefaultMetaDataKeys.push_back("ITK.InputFilterName"); this->m_DefaultMetaDataKeys.push_back("label."); this->m_DefaultMetaDataKeys.push_back("layer."); this->m_DefaultMetaDataKeys.push_back("layers"); this->m_DefaultMetaDataKeys.push_back("modality"); this->m_DefaultMetaDataKeys.push_back("org.mitk.label."); this->m_DefaultMetaDataKeys.push_back("MITK.IO."); } } // namespace #endif //__mitkLabelSetImageWriter__cpp diff --git a/Modules/Multilabel/autoload/IO/mitkMultiLabelSegmentationIO.cpp b/Modules/Multilabel/autoload/IO/mitkMultiLabelSegmentationIO.cpp index a42723eab3..fe238367c0 100644 --- a/Modules/Multilabel/autoload/IO/mitkMultiLabelSegmentationIO.cpp +++ b/Modules/Multilabel/autoload/IO/mitkMultiLabelSegmentationIO.cpp @@ -1,231 +1,224 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkMultiLabelSegmentationIO.h" #include "mitkBasePropertySerializer.h" #include "mitkIOMimeTypes.h" #include "mitkImageAccessByItk.h" #include "mitkMultiLabelIOHelper.h" #include "mitkLabelSetImageConverter.h" #include #include #include #include #include #include // itk #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkMetaDataDictionary.h" #include "itkMetaDataObject.h" #include "itkNrrdImageIO.h" #include namespace mitk { constexpr char* const MULTILABEL_SEGMENTATION_MODALITY_KEY = "modality"; constexpr char* const MULTILABEL_SEGMENTATION_MODALITY_VALUE = "org.mitk.multilabel.segmentation"; constexpr char* const MULTILABEL_SEGMENTATION_VERSION_KEY = "org.mitk.multilabel.segmentation.version"; constexpr int MULTILABEL_SEGMENTATION_VERSION_VALUE = 1; constexpr char* const MULTILABEL_SEGMENTATION_LABELS_INFO_KEY = "org.mitk.multilabel.segmentation.labelgroups"; constexpr char* const MULTILABEL_SEGMENTATION_UNLABELEDLABEL_LOCK_KEY = "org.mitk.multilabel.segmentation.unlabeledlabellock"; MultiLabelSegmentationIO::MultiLabelSegmentationIO() : AbstractFileIO(LabelSetImage::GetStaticNameOfClass(), IOMimeTypes::NRRD_MIMETYPE(), "MITK Multilabel Segmentation") { this->InitializeDefaultMetaDataKeys(); AbstractFileWriter::SetRanking(10); AbstractFileReader::SetRanking(10); this->RegisterService(); } IFileIO::ConfidenceLevel MultiLabelSegmentationIO::GetWriterConfidenceLevel() const { if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported) return Unsupported; const auto *input = static_cast(this->GetInput()); if (input) return Supported; else return Unsupported; } void MultiLabelSegmentationIO::Write() { ValidateOutputLocation(); auto input = dynamic_cast(this->GetInput()); mitk::LocaleSwitch localeSwitch("C"); mitk::Image::Pointer inputVector = mitk::ConvertLabelSetImageToImage(input); // image write if (inputVector.IsNull()) { mitkThrow() << "Cannot write non-image data"; } itk::NrrdImageIO::Pointer nrrdImageIo = itk::NrrdImageIO::New(); ItkImageIO::PreparImageIOToWriteImage(nrrdImageIo, inputVector); LocalFile localFile(this); const std::string path = localFile.GetFileName(); MITK_INFO << "Writing image: " << path << std::endl; try { itk::EncapsulateMetaData( nrrdImageIo->GetMetaDataDictionary(), std::string(MULTILABEL_SEGMENTATION_MODALITY_KEY), std::string(MULTILABEL_SEGMENTATION_MODALITY_VALUE)); //nrrd does only support string meta information. So we have to convert before. itk::EncapsulateMetaData( nrrdImageIo->GetMetaDataDictionary(), std::string(MULTILABEL_SEGMENTATION_VERSION_KEY), std::to_string(MULTILABEL_SEGMENTATION_VERSION_VALUE)); auto json = MultiLabelIOHelper::SerializeMultLabelGroupsToJSON(input); itk::EncapsulateMetaData( nrrdImageIo->GetMetaDataDictionary(), std::string(MULTILABEL_SEGMENTATION_LABELS_INFO_KEY), json.dump()); // end label set specific meta data //nrrd does only support string meta information. So we have to convert before. itk::EncapsulateMetaData( nrrdImageIo->GetMetaDataDictionary(), std::string(MULTILABEL_SEGMENTATION_UNLABELEDLABEL_LOCK_KEY), std::to_string(input->GetUnlabeledLabelLock())); // Handle properties ItkImageIO::SavePropertyListAsMetaData(nrrdImageIo->GetMetaDataDictionary(), input->GetPropertyList(), this->GetMimeType()->GetName()); // Handle UID itk::EncapsulateMetaData(nrrdImageIo->GetMetaDataDictionary(), PROPERTY_KEY_UID, input->GetUID()); // use compression if available nrrdImageIo->UseCompressionOn(); nrrdImageIo->SetFileName(path); ImageReadAccessor imageAccess(inputVector); nrrdImageIo->Write(imageAccess.GetData()); } catch (const std::exception &e) { mitkThrow() << e.what(); } } IFileIO::ConfidenceLevel MultiLabelSegmentationIO::GetReaderConfidenceLevel() const { if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported) return Unsupported; const std::string fileName = this->GetLocalFileName(); itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); io->SetFileName(fileName); io->ReadImageInformation(); itk::MetaDataDictionary imgMetaDataDictionary = io->GetMetaDataDictionary(); std::string value(""); itk::ExposeMetaData(imgMetaDataDictionary, "modality", value); if (value.compare(MULTILABEL_SEGMENTATION_MODALITY_VALUE) == 0) { return Supported; } else return Unsupported; } std::vector MultiLabelSegmentationIO::DoRead() { itk::NrrdImageIO::Pointer nrrdImageIO = itk::NrrdImageIO::New(); std::vector result; auto rawimage = ItkImageIO::LoadRawMitkImageFromImageIO(nrrdImageIO, this->GetLocalFileName()); const itk::MetaDataDictionary& dictionary = nrrdImageIO->GetMetaDataDictionary(); //check version auto version = MultiLabelIOHelper::GetIntByKey(dictionary, MULTILABEL_SEGMENTATION_VERSION_KEY); if (version > MULTILABEL_SEGMENTATION_VERSION_VALUE) { mitkThrow() << "Data to read has unsupported version. Software is to old to ensure correct reading. Please use a compatible version of MITK or store data in another format. Version of data: " << version << "; Supported versions up to: "< labelsets = MultiLabelIOHelper::DeserializeMultLabelGroupsFromJSON(jlabelsets); - if (labelsets.size() != groupImages.size()) + if (labelsets.size() != output->GetNumberOfLayers()) { - mitkThrow() << "Loaded data is in an invalid state. Number of extracted layer images and labels sets does not match. Found layer images: " << groupImages.size() << "; found labelsets: " << labelsets.size(); + mitkThrow() << "Loaded data is in an invalid state. Number of extracted layer images and labels sets does not match. Found layer images: " << output->GetNumberOfLayers() << "; found labelsets: " << labelsets.size(); } - //construct multi layer segmentation out of layers and labelset info instances - LabelSetImage::LabelValueType maxValue = LabelSetImage::UnlabeledLabelValue; - auto imageIterator = groupImages.begin(); - std::vector adaptedLabelSets; - - auto output = ConvertImageVectorToLabelSetImage(groupImages, rawimage->GetTimeGeometry()); - LabelSetImage::SpatialGroupIndexType id = 0; for (auto labelset : labelsets) { output->AddLabelSetToLayer(id, labelset); id++; } bool unlabeledLock = MultiLabelIOHelper::GetIntByKey(dictionary, MULTILABEL_SEGMENTATION_UNLABELEDLABEL_LOCK_KEY) != 0; output->SetUnlabeledLabelLock(unlabeledLock); //meta data handling auto props = ItkImageIO::ExtractMetaDataAsPropertyList(nrrdImageIO->GetMetaDataDictionary(), this->GetMimeType()->GetName(), this->m_DefaultMetaDataKeys); for (auto& [name, prop] : *(props->GetMap())) { output->SetProperty(name, prop->Clone()); //need to clone to avoid that all outputs pointing to the same prop instances. } // Handle UID if (dictionary.HasKey(PROPERTY_KEY_UID)) { itk::MetaDataObject::ConstPointer uidData = dynamic_cast*>(dictionary.Get(PROPERTY_KEY_UID)); if (uidData.IsNotNull()) { mitk::UIDManipulator uidManipulator(output); uidManipulator.SetUID(uidData->GetMetaDataObjectValue()); } } result.push_back(output.GetPointer()); MITK_INFO << "...finished!"; return result; } MultiLabelSegmentationIO *MultiLabelSegmentationIO::IOClone() const { return new MultiLabelSegmentationIO(*this); } void MultiLabelSegmentationIO::InitializeDefaultMetaDataKeys() { this->m_DefaultMetaDataKeys.push_back("NRRD.space"); this->m_DefaultMetaDataKeys.push_back("NRRD.kinds"); this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TYPE); this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS); this->m_DefaultMetaDataKeys.push_back("ITK.InputFilterName"); this->m_DefaultMetaDataKeys.push_back("org.mitk.multilabel."); this->m_DefaultMetaDataKeys.push_back("MITK.IO."); this->m_DefaultMetaDataKeys.push_back(MULTILABEL_SEGMENTATION_MODALITY_KEY); } } // namespace diff --git a/Modules/Multilabel/mitkLabelSetImageConverter.cpp b/Modules/Multilabel/mitkLabelSetImageConverter.cpp index 26d7d1be57..b994182c38 100644 --- a/Modules/Multilabel/mitkLabelSetImageConverter.cpp +++ b/Modules/Multilabel/mitkLabelSetImageConverter.cpp @@ -1,197 +1,198 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include template static void ConvertLabelSetImageToImage(const itk::Image *, mitk::LabelSetImage::ConstPointer labelSetImage, mitk::Image::Pointer &image) { typedef itk::Image ImageType; typedef itk::ComposeImageFilter ComposeFilterType; typedef itk::ImageDuplicator DuplicatorType; auto numberOfLayers = labelSetImage->GetNumberOfLayers(); if (numberOfLayers > 1) { auto vectorImageComposer = ComposeFilterType::New(); auto activeLayer = labelSetImage->GetActiveLayer(); for (decltype(numberOfLayers) layer = 0; layer < numberOfLayers; ++layer) { auto layerImage = mitk::ImageToItkImage( layer != activeLayer ? labelSetImage->GetLayerImage(layer) : labelSetImage); vectorImageComposer->SetInput(layer, layerImage); } vectorImageComposer->Update(); // mitk::GrabItkImageMemory does not support 4D, this will handle 4D correctly // and create a memory managed copy image = mitk::ImportItkImage(vectorImageComposer->GetOutput())->Clone(); } else { auto layerImage = mitk::ImageToItkImage(labelSetImage); auto duplicator = DuplicatorType::New(); duplicator->SetInputImage(layerImage); duplicator->Update(); // mitk::GrabItkImageMemory does not support 4D, this will handle 4D correctly // and create a memory managed copy image = mitk::ImportItkImage(duplicator->GetOutput())->Clone(); } } mitk::Image::Pointer mitk::ConvertLabelSetImageToImage(LabelSetImage::ConstPointer labelSetImage) { Image::Pointer image; if (labelSetImage->GetNumberOfLayers() > 0) { if (labelSetImage->GetDimension() == 4) { AccessFixedDimensionByItk_n(labelSetImage, ::ConvertLabelSetImageToImage, 4, (labelSetImage, image)); } else { AccessByItk_2(labelSetImage->GetLayerImage(0), ::ConvertLabelSetImageToImage, labelSetImage, image); } image->SetTimeGeometry(labelSetImage->GetTimeGeometry()->Clone()); } return image; } template static void SplitVectorImage(const itk::VectorImage* image, std::vector& result) { typedef itk::VectorImage VectorImageType; typedef itk::Image ImageType; typedef itk::VectorIndexSelectionCastImageFilter VectorIndexSelectorType; auto numberOfLayers = image->GetVectorLength(); for (decltype(numberOfLayers) layer = 0; layer < numberOfLayers; ++layer) { auto layerSelector = VectorIndexSelectorType::New(); layerSelector->SetInput(image); layerSelector->SetIndex(layer); layerSelector->Update(); mitk::Image::Pointer layerImage = mitk::GrabItkImageMemoryChannel(layerSelector->GetOutput(), nullptr, nullptr, false); result.push_back(layerImage); } } std::vector mitk::SplitVectorImage(const Image* vecImage) { if (nullptr == vecImage) { mitkThrow() << "Invalid usage; nullptr passed to SplitVectorImage."; } if (vecImage->GetChannelDescriptor().GetPixelType().GetPixelType() != itk::IOPixelEnum::VECTOR) { mitkThrow() << "Invalid usage of SplitVectorImage; passed image is not a vector image. Present pixel type: "<< vecImage->GetChannelDescriptor().GetPixelType().GetPixelTypeAsString(); } std::vector result; if (4 == vecImage->GetDimension()) { AccessVectorFixedDimensionByItk_n(vecImage, ::SplitVectorImage, 4, (result)); } else { AccessVectorPixelTypeByItk_n(vecImage, ::SplitVectorImage, (result)); } for (auto image : result) { image->SetTimeGeometry(vecImage->GetTimeGeometry()->Clone()); } return result; } mitk::LabelSetImage::Pointer mitk::ConvertImageToLabelSetImage(Image::Pointer image) { std::vector groupImages; if (image.IsNotNull()) { if (image->GetChannelDescriptor().GetPixelType().GetPixelType() == itk::IOPixelEnum::VECTOR) { groupImages = SplitVectorImage(image); } else { groupImages.push_back(image); } } auto labelSetImage = ConvertImageVectorToLabelSetImage(groupImages, image->GetTimeGeometry()); return labelSetImage; } mitk::LabelSetImage::Pointer mitk::ConvertImageVectorToLabelSetImage(const std::vector& images, const mitk::TimeGeometry* timeGeometry) { LabelSetImage::Pointer labelSetImage = mitk::LabelSetImage::New(); for (auto& groupImage : images) { if (groupImage== images.front()) { labelSetImage->InitializeByLabeledImage(groupImage); } else { labelSetImage->AddLayer(groupImage); } } labelSetImage->SetTimeGeometry(timeGeometry->Clone()); return labelSetImage; } mitk::LabelSet::Pointer mitk::GenerateLabelSetWithMappedValues(const LabelSet* sourceLabelset, std::vector > labelMapping) { if (nullptr == sourceLabelset) { mitkThrow() << "Invalid usage; nullptr passed as labelset to GenerateLabelSetWithMappedValues."; } auto result = LabelSet::New(); for (auto [sourceLabelID, destLabelID] : labelMapping) { auto clonedLabel = sourceLabelset->GetLabel(sourceLabelID)->Clone(); clonedLabel->SetValue(destLabelID); result->AddLabel(clonedLabel, false); } + result->SetLayer(sourceLabelset->GetLayer()); return result; } diff --git a/Modules/SegmentationUI/test/QmitkMultiLabelTreeModelTest.cpp b/Modules/SegmentationUI/test/QmitkMultiLabelTreeModelTest.cpp index dfcc145ebc..68e74dcc52 100644 --- a/Modules/SegmentationUI/test/QmitkMultiLabelTreeModelTest.cpp +++ b/Modules/SegmentationUI/test/QmitkMultiLabelTreeModelTest.cpp @@ -1,543 +1,543 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "QmitkMultiLabelTreeModel.h" #include #include class QmitkMultiLabelTreeModelTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(QmitkMultiLabelTreeModelTestSuite); MITK_TEST(NullTest); MITK_TEST(GetterSetterTest); MITK_TEST(AddingLabelTest); MITK_TEST(AddingLayerTest); MITK_TEST(RemovingLabelTest); MITK_TEST(RemovingLayerTest); MITK_TEST(ModifyLabelNameTest); MITK_TEST(ModifyLabelTest); CPPUNIT_TEST_SUITE_END(); mitk::LabelSetImage::Pointer m_Segmentation; QCoreApplication* m_TestApp; public: mitk::LabelSetImage::Pointer GenerateSegmentation() { // Create a new labelset image auto seg = mitk::LabelSetImage::New(); mitk::Image::Pointer regularImage = mitk::Image::New(); unsigned int dimensions[3] = { 5, 5, 5 }; regularImage->Initialize(mitk::MakeScalarPixelType(), 3, dimensions); seg->Initialize(regularImage); return seg; } QColor GetQColor(const mitk::Label* label) { return QColor(label->GetColor().GetRed() * 255, label->GetColor().GetGreen() * 255, label->GetColor().GetBlue() * 255); } mitk::Label::Pointer CreateLabel(const std::string& name, mitk::Label::PixelType value) { auto label = mitk::Label::New(); label->SetName(name); label->SetValue(value); label->SetColor(mitk::Color(value / 255.)); return label; } /** Populate a seg with a following setup (in brackets the order of addition). * - Group 1 (1) * - Label A * - Instance 1 (1) * - Instance 5 (2) * - Instance 10 (8) * - Label B * - Instance 4 (3) * - Label D * - Instance 2 (7) * - Group 2 (4) * - Group 3 (5) * - Label B * - Instance 9 (6) */ void PopulateSegmentation(mitk::LabelSetImage* seg) { seg->SetActiveLayer(0); seg->GetActiveLabelSet()->AddLabel(CreateLabel("A", 1)); seg->GetActiveLabelSet()->AddLabel(CreateLabel("A", 5)); seg->GetActiveLabelSet()->AddLabel(CreateLabel("B", 4)); seg->AddLayer(); seg->AddLayer(); seg->SetActiveLayer(2); seg->GetActiveLabelSet()->AddLabel(CreateLabel("B", 9)); seg->SetActiveLayer(0); seg->GetActiveLabelSet()->AddLabel(CreateLabel("D", 2)); seg->GetActiveLabelSet()->AddLabel(CreateLabel("A", 10)); } void setUp() override { m_Segmentation = GenerateSegmentation(); PopulateSegmentation(m_Segmentation); int argc = 0; char** argv = nullptr; m_TestApp = new QCoreApplication(argc, argv); } void tearDown() override { delete m_TestApp; } QModelIndex GetIndex(const QmitkMultiLabelTreeModel& model, const std::vector& rows, int column = 0) const { QModelIndex testIndex; int i = 0; for (auto row : rows) { if (static_cast::size_type>(i) + 1 < rows.size()) { testIndex = model.index(row, 0, testIndex); } else { testIndex = model.index(row, column, testIndex); } i++; } return testIndex; } bool CheckModelItem(const QmitkMultiLabelTreeModel& model, const std::vector& rows, const QVariant& reference, int column, const mitk::Label* /*label = nullptr*/) const { QModelIndex testIndex = GetIndex(model, rows, column); auto value = model.data(testIndex); bool test = value == reference; if (!test) std::cerr << std::endl <<" Model item error. Expected: '" << reference.toString().toStdString() << "'; actual: '" << value.toString().toStdString() <<"'"; return test; } bool CheckModelRow(const QmitkMultiLabelTreeModel& model, const std::vector& rows, const std::vector references) const { int column = 0; bool test = true; for (const auto& ref : references) { test = test & CheckModelItem(model, rows, ref, column, nullptr); column++; } return test; } void CheckModelGroup0Default(const QmitkMultiLabelTreeModel& model) { CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(), QVariant(), QVariant() })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A (3 instances)"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0,0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("Instance #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("Instance #5"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,2 }, { QString("Instance #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("A #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("A #5"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,2 }, { QString("A #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); } void CheckModelGroup1Default(const QmitkMultiLabelTreeModel& model) { CPPUNIT_ASSERT(CheckModelRow(model, { 1 }, { QString("Group 1"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 1 }))); } void CheckModelGroup2Default(const QmitkMultiLabelTreeModel& model) { CPPUNIT_ASSERT(CheckModelRow(model, { 2 }, { QString("Group 2"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 2,0 }, { QString("B"), QVariant(true), QVariant(QColor(9,9,9)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 2,0 }))); } void CheckModelDefault(const QmitkMultiLabelTreeModel& model) { CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CheckModelGroup1Default(model); CheckModelGroup2Default(model); } void NullTest() { QmitkMultiLabelTreeModel model(nullptr); CPPUNIT_ASSERT(nullptr == model.GetSegmentation()); } void GetterSetterTest() { QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); CheckModelDefault(model); model.SetSegmentation(nullptr); CPPUNIT_ASSERT(nullptr == model.GetSegmentation()); CPPUNIT_ASSERT(false == model.hasChildren(QModelIndex())); } void AddingLabelTest() { QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); //Add label instance (not visible) to labelwith multiple instances (at the end) m_Segmentation->SetActiveLayer(0); auto newLabel = CreateLabel("A", 100); newLabel->SetVisible(false); m_Segmentation->GetActiveLabelSet()->AddLabel(newLabel); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(), QVariant(), QVariant() })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A (4 instances)"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(4, model.rowCount(GetIndex(model, { 0,0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("Instance #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("Instance #5"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,2 }, { QString("Instance #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,3 }, { QString("Instance #100"), QVariant(true), QVariant(QColor(100,100,100)), QVariant(false) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("A #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("A #5"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,2 }, { QString("A #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,3 }, { QString("A #100"), QVariant(true), QVariant(QColor(100,100,100)), QVariant(false) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //Add label instance (not locked) to label with multiple instances (in between) m_Segmentation->SetActiveLayer(0); newLabel = CreateLabel("A", 7); newLabel->SetLocked(false); m_Segmentation->GetActiveLabelSet()->AddLabel(newLabel); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(), QVariant(), QVariant() })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A (5 instances)"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(5, model.rowCount(GetIndex(model, { 0,0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("Instance #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("Instance #5"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,2 }, { QString("Instance #7"), QVariant(false), QVariant(QColor(7,7,7)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,3 }, { QString("Instance #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,4 }, { QString("Instance #100"), QVariant(true), QVariant(QColor(100,100,100)), QVariant(false) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("A #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("A #5"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,2 }, { QString("A #7"), QVariant(false), QVariant(QColor(7,7,7)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,3 }, { QString("A #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,4 }, { QString("A #100"), QVariant(true), QVariant(QColor(100,100,100)), QVariant(false) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //reset everything m_Segmentation = GenerateSegmentation(); PopulateSegmentation(m_Segmentation); model.SetSegmentation(m_Segmentation); //Add label instance to an empty group m_Segmentation->SetActiveLayer(1); newLabel = CreateLabel("A", 3); m_Segmentation->GetActiveLabelSet()->AddLabel(newLabel); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 1 }, { QString("Group 1"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 1,0 }, { QString("A"), QVariant(true), QVariant(QColor(3,3,3)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 1,0 }))); CheckModelGroup2Default(model); } void AddingLayerTest() { QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); m_Segmentation->AddLayer(); CPPUNIT_ASSERT_EQUAL(4, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CheckModelGroup1Default(model); CheckModelGroup2Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 3 }, { QString("Group 3"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 3 }))); } void RemovingLabelTest() { QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); //remove label instance from label with multiple instances (middel) m_Segmentation->RemoveLabel(5); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(), QVariant(), QVariant() })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A (2 instances)"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(GetIndex(model, { 0,0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("Instance #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("Instance #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("A #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("A #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //remove label instance from label with multiple instances (first) m_Segmentation->RemoveLabel(1); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //reset everything m_Segmentation = GenerateSegmentation(); PopulateSegmentation(m_Segmentation); model.SetSegmentation(m_Segmentation); //remove label instance from label with multiple instances (at the end) m_Segmentation->RemoveLabel(10); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(), QVariant(), QVariant() })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A (2 instances)"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(GetIndex(model, { 0,0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("Instance #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("Instance #5"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("A #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("A #5"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //reset everything m_Segmentation = GenerateSegmentation(); PopulateSegmentation(m_Segmentation); model.SetSegmentation(m_Segmentation); //remove label instance from label with only one instance m_Segmentation->RemoveLabel(9); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CheckModelGroup1Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 2 }, { QString("Group 2"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 2 }))); } void RemovingLayerTest() { QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); //remove group in the middle m_Segmentation->SetActiveLayer(1); m_Segmentation->RemoveLayer(); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 1 }, { QString("Group 1"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 1,0 }, { QString("B"), QVariant(true), QVariant(QColor(9,9,9)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 1,0 }))); //remove groups in the end m_Segmentation->SetActiveLayer(1); m_Segmentation->RemoveLayer(); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); //remove all groups m_Segmentation->SetActiveLayer(0); m_Segmentation->RemoveLayer(); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(QModelIndex())); //reset everything m_Segmentation = GenerateSegmentation(); PopulateSegmentation(m_Segmentation); model.SetSegmentation(m_Segmentation); //remove first group m_Segmentation->SetActiveLayer(0); m_Segmentation->RemoveLayer(); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 1 }, { QString("Group 1"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 1,0 }, { QString("B"), QVariant(true), QVariant(QColor(9,9,9)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 1,0 }))); } void ModifyLabelNameTest() { QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); //move from multiple instance to new label in the middle auto label = m_Segmentation->GetLabel(5,0); label->SetName("C"); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(4, model.rowCount(GetIndex(model, { 0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(), QVariant(), QVariant() })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A (2 instances)"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(GetIndex(model, { 0,0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("Instance #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("Instance #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("A #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("A #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("C"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,3 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,3 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //move from multiple instance to new label at the end label = m_Segmentation->GetLabel(10, 0); label->SetName("E"); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(5, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("C"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,3 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,3 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,4 }, { QString("E"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,4 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //move last instance to new label label = m_Segmentation->GetLabel(10, 0); label->SetName("F"); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(5, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("C"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,3 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,3 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,4 }, { QString("F"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,4 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //move last instance to an existing label label->SetName("B"); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(4, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(), QVariant(), QVariant() })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B (2 instances)"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(GetIndex(model, { 0,1 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,1,0 }, { QString("Instance #4"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 0,1,1 }, { QString("Instance #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,1,0 }, { QString("B #4"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 0,1,1 }, { QString("B #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("C"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,3 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,3 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); } void ModifyLabelTest() { QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); auto label = m_Segmentation->GetLabel(9, 2); //check single instance modifications label->SetVisible(false); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CheckModelGroup1Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 2 }, { QString("Group 2"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 2,0 }, { QString("B"), QVariant(true), QVariant(QColor(9,9,9)), QVariant(false) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 2,0 }))); label->SetLocked(false); label->SetColor(mitk::Color(22 / 255.)); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CheckModelGroup1Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 2 }, { QString("Group 2"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 2,0 }, { QString("B"), QVariant(false), QVariant(QColor(22,22,22)), QVariant(false) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 2,0 }))); //check instance modifications with multi instance label m_Segmentation->SetActiveLayer(2); m_Segmentation->GetActiveLabelSet()->AddLabel(CreateLabel("B", 33)); label->SetVisible(true); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CheckModelGroup1Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 2 }, { QString("Group 2"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 2 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 2,0 }, { QString("B"), QVariant(), QVariant(), QVariant() })); + CPPUNIT_ASSERT(CheckModelRow(model, { 2,0 }, { QString("B (2 instances)"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(GetIndex(model, { 2,0 }))); - CPPUNIT_ASSERT(CheckModelRow(model, { 2,0,0 }, { QString("Instance #9"), QVariant(false), QVariant(QColor(22,22,22)), QVariant(true) })); - CPPUNIT_ASSERT(CheckModelRow(model, { 2,0,1 }, { QString("Instance #33"), QVariant(true), QVariant(QColor(33,33,33)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 2,0,0 }, { QString("B #9"), QVariant(false), QVariant(QColor(22,22,22)), QVariant(true) })); + CPPUNIT_ASSERT(CheckModelRow(model, { 2,0,1 }, { QString("B #33"), QVariant(true), QVariant(QColor(33,33,33)), QVariant(true) })); } }; MITK_TEST_SUITE_REGISTRATION(QmitkMultiLabelTreeModel)