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