1 /*========================================================================= 2 * 3 * Copyright Insight Software Consortium 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0.txt 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 *=========================================================================*/ 18 19 #include "itkGTest.h" 20 21 #include "itkImage.h" 22 #include "itkLabelImageToShapeLabelMapFilter.h" 23 24 25 namespace Math = itk::Math; 26 27 namespace 28 { 29 30 class ShapeLabelMapFixture 31 : public ::testing::Test 32 { 33 public: 34 ShapeLabelMapFixture() = default; 35 ~ShapeLabelMapFixture() override = default; 36 37 protected: SetUp()38 void SetUp() override {} TearDown()39 void TearDown() override {} 40 41 template<unsigned int D, typename TPixelType = unsigned short> 42 struct FixtureUtilities 43 { 44 static const unsigned int Dimension = D; 45 46 using PixelType = TPixelType; 47 using ImageType = itk::Image<PixelType, Dimension>; 48 49 using LabelObjectType = itk::ShapeLabelObject<PixelType, Dimension>; 50 using ShapeLabelMapType = itk::LabelMap<LabelObjectType>; 51 52 CreateImage__anon16ce00700111::ShapeLabelMapFixture::FixtureUtilities53 static typename ImageType::Pointer CreateImage() 54 { 55 typename ImageType::Pointer image = ImageType::New(); 56 57 typename ImageType::SizeType imageSize; 58 imageSize.Fill(25); 59 image->SetRegions(typename ImageType::RegionType(imageSize)); 60 image->Allocate(); 61 image->FillBuffer(0); 62 63 return image; 64 } 65 66 ComputeLabelObject__anon16ce00700111::ShapeLabelMapFixture::FixtureUtilities67 static typename LabelObjectType::ConstPointer ComputeLabelObject(const ImageType* image, 68 PixelType label = 1) 69 { 70 71 using L2SType = itk::LabelImageToShapeLabelMapFilter<ImageType>; 72 typename L2SType::Pointer l2s = L2SType::New(); 73 l2s->SetInput( image ); 74 l2s->ComputeFeretDiameterOn(); 75 l2s->ComputePerimeterOn(); 76 l2s->ComputeOrientedBoundingBoxOn(); 77 l2s->Update(); 78 return l2s->GetOutput()->GetLabelObject(label); 79 } 80 }; 81 82 83 }; 84 } 85 86 // The expected results were verified for these tests cases, unless 87 // the test is marked with the "resulting value" comment. In which 88 // case the baseline value was just what was computed by the method. 89 90 91 TEST_F(ShapeLabelMapFixture,3D_T1x1x1) 92 { 93 using namespace itk::GTest::TypedefsAndConstructors::Dimension3; 94 95 using Utils = FixtureUtilities<3>; 96 97 Utils::ImageType::Pointer image( Utils::CreateImage() ); 98 99 image->SetPixel(MakeIndex(5,7,9), 1); 100 101 Utils::LabelObjectType::ConstPointer labelObject = Utils::ComputeLabelObject(image); 102 103 104 ITK_EXPECT_VECTOR_NEAR(MakeIndex(5,7,9), labelObject->GetBoundingBox().GetIndex(), 1e-99); 105 ITK_EXPECT_VECTOR_NEAR(MakeSize(1,1,1), labelObject->GetBoundingBox().GetSize(), 1e-99); 106 ITK_EXPECT_VECTOR_NEAR(MakePoint(5.0,7.0,9.0), labelObject->GetCentroid(), 1e-10); 107 EXPECT_EQ(0.0, labelObject->GetElongation()); 108 ITK_EXPECT_VECTOR_NEAR(MakePoint(0.0,0.0,0.0), labelObject->GetEquivalentEllipsoidDiameter(), 1e-10); 109 EXPECT_NEAR(4.83598, labelObject->GetEquivalentSphericalPerimeter(), 1e-4); // resulting value 110 EXPECT_NEAR(0.62035, labelObject->GetEquivalentSphericalRadius(), 1e-4); // resulting value 111 EXPECT_EQ(0.0, labelObject->GetFeretDiameter()); 112 EXPECT_EQ(0.0, labelObject->GetFlatness()); 113 EXPECT_EQ(1u, labelObject->GetNumberOfPixels()); 114 EXPECT_EQ(0u, labelObject->GetNumberOfPixelsOnBorder()); 115 ITK_EXPECT_VECTOR_NEAR(MakeVector(1u,1u,1u), labelObject->GetOrientedBoundingBoxSize(), 1e-10); 116 ITK_EXPECT_VECTOR_NEAR(MakePoint(4.5,6.5,8.5), labelObject->GetOrientedBoundingBoxOrigin(), 1e-10); 117 EXPECT_NEAR(3.004, labelObject->GetPerimeter(), 1e-4); // resulting value 118 EXPECT_EQ(0.0, labelObject->GetPerimeterOnBorder()); 119 EXPECT_EQ(0.0, labelObject->GetPerimeterOnBorderRatio()); 120 EXPECT_EQ(1.0, labelObject->GetPhysicalSize()); 121 // labelObject->GetPrincipalAxes(); degenerate case 122 EXPECT_EQ(MakeVector(0.0,0.0,0.0), labelObject->GetPrincipalMoments()); 123 EXPECT_NEAR(1.6098, labelObject->GetRoundness(), 0.0001); // resulting value 124 125 EXPECT_EQ(labelObject->GetBoundingBox(), labelObject->GetRegion()); 126 127 if (::testing::Test::HasFailure()) 128 { 129 labelObject->Print(std::cout); 130 } 131 } 132 133 TEST_F(ShapeLabelMapFixture,3D_T3x2x1) 134 { 135 using namespace itk::GTest::TypedefsAndConstructors::Dimension3; 136 137 using Utils = FixtureUtilities<3>; 138 139 Utils::ImageType::Pointer image( Utils::CreateImage() ); 140 141 for (unsigned int i = 5; i < 8; ++i) 142 { 143 image->SetPixel(MakeIndex(i,9,11), 1); 144 image->SetPixel(MakeIndex(i,10,11), 1); 145 } 146 147 Utils::LabelObjectType::ConstPointer labelObject = Utils::ComputeLabelObject(image); 148 149 150 ITK_EXPECT_VECTOR_NEAR(MakeIndex(5,9,11), labelObject->GetBoundingBox().GetIndex(), 1e-99); 151 ITK_EXPECT_VECTOR_NEAR(MakeSize(3,2,1), labelObject->GetBoundingBox().GetSize(), 1e-99); 152 EXPECT_EQ(MakePoint(6,9.5,11.0), labelObject->GetCentroid()); 153 EXPECT_NEAR(1.63299, labelObject->GetElongation(), 1e-4); 154 ITK_EXPECT_VECTOR_NEAR(MakePoint(0.0,0.0,0.0), labelObject->GetEquivalentEllipsoidDiameter(), 1e-10); 155 EXPECT_NEAR(15.96804, labelObject->GetEquivalentSphericalPerimeter(), 1e-4); // resulting value 156 EXPECT_NEAR(1.12725, labelObject->GetEquivalentSphericalRadius(), 1e-4); // resulting value 157 EXPECT_NEAR(2.23606, labelObject->GetFeretDiameter(), 1e-4); 158 EXPECT_EQ(0.0, labelObject->GetFlatness()); 159 EXPECT_EQ(6u, labelObject->GetNumberOfPixels()); 160 EXPECT_EQ(0u, labelObject->GetNumberOfPixelsOnBorder()); 161 ITK_EXPECT_VECTOR_NEAR(MakeVector(1u,2u,3u), labelObject->GetOrientedBoundingBoxSize(),1e-10); 162 ITK_EXPECT_VECTOR_NEAR(MakePoint(7.5, 8.5, 10.5), labelObject->GetOrientedBoundingBoxOrigin(), 1e-10); 163 EXPECT_NEAR(14.62414, labelObject->GetPerimeter(), 1e-4); // resulting value 164 EXPECT_EQ(0.0, labelObject->GetPerimeterOnBorder()); 165 EXPECT_EQ(0.0, labelObject->GetPerimeterOnBorderRatio()); 166 EXPECT_EQ(6.0, labelObject->GetPhysicalSize()); 167 // labelObject->GetPrincipalAxes(); omitted 168 ITK_EXPECT_VECTOR_NEAR(MakeVector(0, 0.25, 0.666667), labelObject->GetPrincipalMoments(),1e-4); 169 EXPECT_NEAR(1.09189, labelObject->GetRoundness(), 1e-4); // resulting value 170 171 EXPECT_EQ(labelObject->GetBoundingBox(), labelObject->GetRegion()); 172 173 if (::testing::Test::HasFailure()) 174 { 175 labelObject->Print(std::cout); 176 } 177 } 178 179 180 TEST_F(ShapeLabelMapFixture,3D_T3x2x1_Direction) 181 { 182 using namespace itk::GTest::TypedefsAndConstructors::Dimension3; 183 184 using Utils = FixtureUtilities<3>; 185 186 Utils::ImageType::Pointer image( Utils::CreateImage() ); 187 188 for (unsigned int i = 5; i < 8; ++i) 189 { 190 image->SetPixel(MakeIndex(i,9,11), 1); 191 image->SetPixel(MakeIndex(i,10,11), 1); 192 } 193 194 DirectionType direction; 195 196 const double d[9] = {0.7950707161543119, -0.44533237368675166, 0.41175433605536305, 197 -0.6065167008084678, -0.5840224148057925, 0.5394954222649374, 198 0.00021898465942798317, -0.6786728931900383, -0.7344406416415056}; 199 200 direction = DirectionType::InternalMatrixType(d); 201 202 image->SetDirection(direction); 203 204 Utils::LabelObjectType::ConstPointer labelObject = Utils::ComputeLabelObject(image); 205 206 207 ITK_EXPECT_VECTOR_NEAR(MakeIndex(5,9,11), labelObject->GetBoundingBox().GetIndex(), 1e-99); 208 ITK_EXPECT_VECTOR_NEAR(MakeSize(3,2,1), labelObject->GetBoundingBox().GetSize(), 1e-99); 209 ITK_EXPECT_VECTOR_NEAR(MakePoint(5.06906, -3.25286, -14.5249), labelObject->GetCentroid(), 1e-4); 210 EXPECT_NEAR(1.63299, labelObject->GetElongation(), 1e-4); 211 //ITK_EXPECT_VECTOR_NEAR(MakePoint(0.0,0.0,0.0), labelObject->GetEquivalentEllipsoidDiameter(), 1e-10); 212 EXPECT_NEAR(15.96804, labelObject->GetEquivalentSphericalPerimeter(), 1e-4); // resulting value 213 EXPECT_NEAR(1.12725, labelObject->GetEquivalentSphericalRadius(), 1e-4); // resulting value 214 EXPECT_NEAR(2.23606, labelObject->GetFeretDiameter(), 1e-4); 215 //EXPECT_EQ(0.0, labelObject->GetFlatness()); unstable due to division near zero 216 EXPECT_EQ(6u, labelObject->GetNumberOfPixels()); 217 EXPECT_EQ(0u, labelObject->GetNumberOfPixelsOnBorder()); 218 ITK_EXPECT_VECTOR_NEAR(MakeVector(1u,2u,3u), labelObject->GetOrientedBoundingBoxSize(),1e-10); 219 ITK_EXPECT_VECTOR_NEAR(MakePoint(3.22524, -3.19685, -14.83670), labelObject->GetOrientedBoundingBoxOrigin(), 1e-4); 220 EXPECT_NEAR(14.62414, labelObject->GetPerimeter(), 1e-4); // resulting value 221 EXPECT_EQ(0.0, labelObject->GetPerimeterOnBorder()); 222 EXPECT_EQ(0.0, labelObject->GetPerimeterOnBorderRatio()); 223 EXPECT_EQ(6.0, labelObject->GetPhysicalSize()); 224 //labelObject->GetPrincipalAxes(); omitted 225 ITK_EXPECT_VECTOR_NEAR(MakeVector(0, 0.25, 0.666667), labelObject->GetPrincipalMoments(),1e-4); 226 EXPECT_NEAR(1.09189, labelObject->GetRoundness(), 1e-4); // resulting value 227 228 if (::testing::Test::HasFailure()) 229 { 230 labelObject->Print(std::cout); 231 } 232 } 233 234 235 TEST_F(ShapeLabelMapFixture,3D_T2x2x2_Spacing) 236 { 237 using namespace itk::GTest::TypedefsAndConstructors::Dimension3; 238 239 using Utils = FixtureUtilities<3>; 240 241 Utils::ImageType::Pointer image( Utils::CreateImage() ); 242 243 for (unsigned int i = 0; i < 2; ++i) 244 { 245 for (unsigned int j = 0; j < 2; ++j) 246 { 247 image->SetPixel(MakeIndex(5+j,9+i,11), 1); 248 image->SetPixel(MakeIndex(5+j,9+i,12), 1); 249 } 250 } 251 252 image->SetSpacing(MakeVector(1.0,1.1,2.2)); 253 254 Utils::LabelObjectType::ConstPointer labelObject = Utils::ComputeLabelObject(image); 255 256 257 ITK_EXPECT_VECTOR_NEAR(MakeIndex(5,9,11), labelObject->GetBoundingBox().GetIndex(), 1e-99); 258 ITK_EXPECT_VECTOR_NEAR(MakeSize(2,2,2), labelObject->GetBoundingBox().GetSize(), 1e-99); 259 ITK_EXPECT_VECTOR_NEAR(MakePoint(5.5, 10.45, 25.3), labelObject->GetCentroid(), 1e-4); 260 EXPECT_NEAR(2.0, labelObject->GetElongation(), 1e-4); 261 ITK_EXPECT_VECTOR_NEAR(MakePoint(2.4814, 2.72954, 5.45908), labelObject->GetEquivalentEllipsoidDiameter(), 1e-4); // resulting value 262 EXPECT_NEAR(34.86751, labelObject->GetEquivalentSphericalPerimeter(), 1e-4); // resulting value 263 EXPECT_NEAR(1.66573, labelObject->GetEquivalentSphericalRadius(), 1e-4); // resulting value 264 EXPECT_NEAR(2.65518, labelObject->GetFeretDiameter(), 1e-4); 265 EXPECT_NEAR(1.1, labelObject->GetFlatness(), 1e-4); 266 EXPECT_EQ(8u, labelObject->GetNumberOfPixels()); 267 EXPECT_EQ(0u, labelObject->GetNumberOfPixelsOnBorder()); 268 ITK_EXPECT_VECTOR_NEAR(MakeVector(2, 2.2, 4.4), labelObject->GetOrientedBoundingBoxSize(),1e-10); 269 EXPECT_NEAR(28.3919, labelObject->GetPerimeter(), 1e-4); // resulting value 270 EXPECT_EQ(0.0, labelObject->GetPerimeterOnBorder()); 271 EXPECT_EQ(0.0, labelObject->GetPerimeterOnBorderRatio()); 272 EXPECT_NEAR(19.36, labelObject->GetPhysicalSize(), 1e-10); 273 // We are omitted these because the sign of the eigen vectors is not 274 //unique, therefore the axes may not always point in the same 275 //direction and the origin may not be the same corner 276 //ITK_EXPECT_VECTOR_NEAR(MakePoint(4.5, 9.35, 23.1), labelObject->GetOrientedBoundingBoxOrigin(), 1e-4); 277 //labelObject->GetPrincipalAxes(); omitted 278 ITK_EXPECT_VECTOR_NEAR(MakeVector(0.25, 0.3025, 1.21), labelObject->GetPrincipalMoments(),1e-4); 279 EXPECT_NEAR( 1.22808, labelObject->GetRoundness(), 1e-4); // resulting value 280 281 if (::testing::Test::HasFailure()) 282 { 283 labelObject->Print(std::cout); 284 } 285 } 286 287 288 TEST_F(ShapeLabelMapFixture,3D_T2x2x2_Spacing_Direction) 289 { 290 using namespace itk::GTest::TypedefsAndConstructors::Dimension3; 291 292 using Utils = FixtureUtilities<3>; 293 294 Utils::ImageType::Pointer image( Utils::CreateImage() ); 295 296 DirectionType direction; 297 298 const double d[9] = {0.7950707161543119, -0.44533237368675166, 0.41175433605536305, 299 -0.6065167008084678, -0.5840224148057925, 0.5394954222649374, 300 0.00021898465942798317, -0.6786728931900383, -0.7344406416415056}; 301 302 direction = DirectionType::InternalMatrixType(d); 303 304 image->SetDirection(direction); 305 306 for (unsigned int i = 0; i < 2; ++i) 307 { 308 for (unsigned int j = 0; j < 2; ++j) 309 { 310 image->SetPixel(MakeIndex(5+j,9+i,11), 1); 311 image->SetPixel(MakeIndex(5+j,9+i,12), 1); 312 } 313 } 314 315 image->SetSpacing(MakeVector(1.0,1.1,2.2)); 316 317 Utils::LabelObjectType::ConstPointer labelObject = Utils::ComputeLabelObject(image); 318 319 320 ITK_EXPECT_VECTOR_NEAR(MakeIndex(5,9,11), labelObject->GetBoundingBox().GetIndex(), 1e-99); 321 ITK_EXPECT_VECTOR_NEAR(MakeSize(2,2,2), labelObject->GetBoundingBox().GetSize(), 1e-99); 322 ITK_EXPECT_VECTOR_NEAR(MakePoint(10.13655, 4.21035, -25.67227), labelObject->GetCentroid(), 1e-4); // resulting value 323 EXPECT_NEAR(2.0, labelObject->GetElongation(), 1e-4); 324 ITK_EXPECT_VECTOR_NEAR(MakePoint(2.4814, 2.72954, 5.45908), labelObject->GetEquivalentEllipsoidDiameter(), 1e-4); // resulting value 325 EXPECT_NEAR(34.86751, labelObject->GetEquivalentSphericalPerimeter(), 1e-4); // resulting value 326 EXPECT_NEAR(1.66573, labelObject->GetEquivalentSphericalRadius(), 1e-4); // resulting value 327 EXPECT_NEAR(2.65518, labelObject->GetFeretDiameter(), 1e-4); 328 EXPECT_NEAR(1.1, labelObject->GetFlatness(), 1e-4); 329 EXPECT_EQ(8u, labelObject->GetNumberOfPixels()); 330 EXPECT_EQ(0u, labelObject->GetNumberOfPixelsOnBorder()); 331 ITK_EXPECT_VECTOR_NEAR(MakeVector(2, 2.2, 4.4), labelObject->GetOrientedBoundingBoxSize(),1e-10); 332 ITK_EXPECT_VECTOR_NEAR(MakePoint(8.92548, 4.27240, -23.31018), labelObject->GetOrientedBoundingBoxOrigin(), 1e-4); // resulting value 333 EXPECT_NEAR(28.3919, labelObject->GetPerimeter(), 1e-4); // resulting value 334 EXPECT_EQ(0.0, labelObject->GetPerimeterOnBorder()); 335 EXPECT_EQ(0.0, labelObject->GetPerimeterOnBorderRatio()); 336 EXPECT_NEAR(19.36, labelObject->GetPhysicalSize(), 1e-10); 337 //labelObject->GetPrincipalAxes(); omitted 338 ITK_EXPECT_VECTOR_NEAR(MakeVector(0.25, 0.3025, 1.21), labelObject->GetPrincipalMoments(),1e-4); 339 EXPECT_NEAR( 1.22808, labelObject->GetRoundness(), 1e-4); // resulting value 340 341 if (::testing::Test::HasFailure()) 342 { 343 labelObject->Print(std::cout); 344 } 345 } 346 347 348 TEST_F(ShapeLabelMapFixture,2D_T1x1) 349 { 350 using namespace itk::GTest::TypedefsAndConstructors::Dimension2; 351 352 using Utils = FixtureUtilities<2>; 353 354 Utils::ImageType::Pointer image( Utils::CreateImage() ); 355 356 image->SetPixel(MakeIndex(5,7), 1); 357 358 Utils::LabelObjectType::ConstPointer labelObject = Utils::ComputeLabelObject(image); 359 360 ITK_EXPECT_VECTOR_NEAR(MakeVector(1.0,1.0), labelObject->GetOrientedBoundingBoxSize(),1e-10); 361 ITK_EXPECT_VECTOR_NEAR(MakePoint(4.5, 6.5), labelObject->GetOrientedBoundingBoxOrigin(), 1e-4); 362 363 if (::testing::Test::HasFailure()) 364 { 365 labelObject->Print(std::cout); 366 } 367 } 368 369 370 TEST_F(ShapeLabelMapFixture,2D_T1_1) 371 { 372 using namespace itk::GTest::TypedefsAndConstructors::Dimension2; 373 374 using Utils = FixtureUtilities<2>; 375 376 Utils::ImageType::Pointer image( Utils::CreateImage() ); 377 378 image->SetPixel(MakeIndex(5,7), 1); 379 image->SetPixel(MakeIndex(6,8), 1); 380 381 Utils::LabelObjectType::ConstPointer labelObject = Utils::ComputeLabelObject(image); 382 383 ITK_EXPECT_VECTOR_NEAR(MakeSize(2,2), labelObject->GetBoundingBox().GetSize(), 1e-99); 384 ITK_EXPECT_VECTOR_NEAR(MakeVector(Math::sqrt2, 2.0*Math::sqrt2), labelObject->GetOrientedBoundingBoxSize(),1e-4); 385 ITK_EXPECT_VECTOR_NEAR(MakePoint(4.0, 7.0), labelObject->GetOrientedBoundingBoxOrigin(), 1e-4); 386 387 if (::testing::Test::HasFailure()) 388 { 389 labelObject->Print(std::cout); 390 } 391 } 392 393 394 TEST_F(ShapeLabelMapFixture,2D_T1_1_FlipDirection) 395 { 396 using namespace itk::GTest::TypedefsAndConstructors::Dimension2; 397 398 using Utils = FixtureUtilities<2>; 399 400 Utils::ImageType::Pointer image( Utils::CreateImage() ); 401 402 image->SetPixel(MakeIndex(5,7), 1); 403 image->SetPixel(MakeIndex(6,8), 1); 404 405 DirectionType direction; 406 407 const double d[4] = {0,1.0, 408 1.0, 0}; 409 410 direction = DirectionType::InternalMatrixType(d); 411 412 image->SetDirection(direction); 413 414 415 Utils::LabelObjectType::ConstPointer labelObject = Utils::ComputeLabelObject(image); 416 417 ITK_EXPECT_VECTOR_NEAR(MakeVector(Math::sqrt2, 2.0*Math::sqrt2), labelObject->GetOrientedBoundingBoxSize(),1e-4); 418 ITK_EXPECT_VECTOR_NEAR(MakePoint(6.0, 5.0), labelObject->GetOrientedBoundingBoxOrigin(), 1e-4); 419 420 421 if (::testing::Test::HasFailure()) 422 { 423 labelObject->Print(std::cout); 424 } 425 } 426 427 428 TEST_F(ShapeLabelMapFixture,2D_T2x4) 429 { 430 using namespace itk::GTest::TypedefsAndConstructors::Dimension2; 431 432 using Utils = FixtureUtilities<2>; 433 434 Utils::ImageType::Pointer image( Utils::CreateImage() ); 435 436 for (unsigned int i = 4; i < 6; ++i) 437 { 438 for (unsigned int j = 3; j < 7; ++j) 439 { 440 image->SetPixel(MakeIndex(i,j), 1); 441 } 442 } 443 444 Utils::LabelObjectType::ConstPointer labelObject = Utils::ComputeLabelObject(image); 445 446 ITK_EXPECT_VECTOR_NEAR(MakeVector(2.0,4.0), labelObject->GetOrientedBoundingBoxSize(),1e-10); 447 ITK_EXPECT_VECTOR_NEAR(MakePoint(3.5, 2.5), labelObject->GetOrientedBoundingBoxOrigin(), 1e-4); 448 449 if (::testing::Test::HasFailure()) 450 { 451 labelObject->Print(std::cout); 452 } 453 } 454