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 "itkShowDistanceMap.h"
20 #include "itkDanielssonDistanceMapImageFilter.h"
21 #include "itkStdStreamStateSave.h"
22
itkDanielssonDistanceMapImageFilterTest(int,char * [])23 int itkDanielssonDistanceMapImageFilterTest(int, char* [] )
24 {
25 // Save the format stream variables for std::cout
26 // They will be restored when coutState goes out of scope
27 itk::StdStreamStateSave coutState(std::cout);
28
29 std::cout << "Test ITK Danielsson Distance Map" << std::endl << std::endl;
30 std::cout << "Compute the distance map of a 9x9 image" << std::endl;
31 std::cout << "with a point at (4,4) (value=1)" << std::endl << std::endl;
32 std::cout << "with a point at (1,6) (value=2)" << std::endl << std::endl;
33
34
35 using myImageType2D1 = itk::Image<unsigned char, 2>;
36 using myImageType2D2 = itk::Image<float, 2>;
37
38 /* Allocate the 2D image */
39 myImageType2D1::SizeType size2D = {{9,9}};
40 myImageType2D1::IndexType index2D = {{0,0}};
41 myImageType2D1::RegionType region2D;
42 region2D.SetSize( size2D );
43 region2D.SetIndex( index2D );
44
45 myImageType2D1::Pointer inputImage2D = myImageType2D1::New();
46 inputImage2D->SetLargestPossibleRegion( region2D );
47 inputImage2D->SetBufferedRegion( region2D );
48 inputImage2D->SetRequestedRegion( region2D );
49 inputImage2D->Allocate( true );
50
51 /* Set pixel (4,4) with the value 1
52 * and pixel (1,6) with the value 2
53 * The Danielsson Distance is performed for each pixel with a value > 0
54 * The ClosestPoints computation is based on the value of the pixel.
55 */
56
57 index2D[0] = 4;
58 index2D[1] = 4;
59 inputImage2D->SetPixel( index2D, 1);
60 index2D[0] = 1;
61 index2D[1] = 6;
62 inputImage2D->SetPixel( index2D, 2);
63
64 /* Create Danielsson Distance Map filter */
65 using myFilterType2D = itk::DanielssonDistanceMapImageFilter<
66 myImageType2D1,
67 myImageType2D2 >;
68
69 myFilterType2D::Pointer filter2D = myFilterType2D::New();
70
71 filter2D->SetInput( inputImage2D );
72
73 myImageType2D2::Pointer outputDistance2D = filter2D->GetOutput();
74
75 using VoronoiImageType = myFilterType2D::VoronoiImageType;
76
77 VoronoiImageType::Pointer outputVoronoi2D = filter2D->GetVoronoiMap();
78
79 myFilterType2D::VectorImagePointer
80 outputComponents = filter2D->GetVectorDistanceMap();
81
82 filter2D->Update();
83
84 ShowDistanceMap(outputDistance2D);
85 std::cout << "Voronoi Map Image 2D" << std::endl << std::endl;
86 ShowDistanceMap(outputVoronoi2D);
87
88 /* Show VectorsComponents Points map */
89 std::cout << std::endl << std::endl;
90 std::cout << "Components Map Image 2D" << std::endl << std::endl;
91
92 itk::ImageSliceConstIteratorWithIndex< myFilterType2D::VectorImageType > it2D4(
93 outputComponents,
94 outputComponents->GetRequestedRegion() );
95
96 it2D4.SetFirstDirection( 0 );
97 it2D4.SetSecondDirection( 1 );
98
99 while( !it2D4.IsAtEnd() )
100 {
101 while( !it2D4.IsAtEndOfSlice() )
102 {
103 while( !it2D4.IsAtEndOfLine() )
104 {
105 std::cout << "[";
106 for (unsigned int i=0;i<2;i++)
107 {
108 std::cout << it2D4.Get()[i];
109 if(i==0)
110 {
111 std::cout << ",";
112 }
113 }
114 std::cout << "]";
115 std::cout << "\t";
116 ++it2D4;
117
118 }
119 std::cout << std::endl;
120 it2D4.NextLine();
121 }
122 it2D4.NextSlice();
123 }
124
125
126 /* Test Squared Distance functionality */
127 myImageType2D2::IndexType index;
128 index[0] = 0;
129 index[1] = 0;
130 const double distance1 = outputDistance2D->GetPixel( index );
131
132 filter2D->SquaredDistanceOn();
133
134 if( filter2D->GetSquaredDistance() != true )
135 {
136 std::cerr << "filter2D->GetSquaredDistance() != true" <<std::endl;
137 return EXIT_FAILURE;
138 }
139
140 filter2D->SetSquaredDistance( true );
141 filter2D->Update();
142
143 const double distance2 = outputDistance2D->GetPixel( index );
144 const myImageType2D2::PixelType epsilon = 1e-5;
145 if( std::fabs( distance2 - distance1 * distance1 ) > epsilon )
146 {
147 std::cerr << "Error in use of the SetSquaredDistance() method" << std::endl;
148 return EXIT_FAILURE;
149 }
150
151 std::cout << "Squared Distance Map " << std::endl;
152 ShowDistanceMap(outputDistance2D);
153
154
155 /* Test for images with anisotropic spacing */
156 myImageType2D1::SpacingType anisotropicSpacing;
157
158 anisotropicSpacing[0] = 1.0;
159 anisotropicSpacing[1] = 5.0;
160
161 inputImage2D->SetSpacing( anisotropicSpacing );
162
163 inputImage2D->FillBuffer( 0 );
164
165 index2D[0] = 4;
166 index2D[1] = 4;
167 inputImage2D->SetPixel( index2D, 1);
168
169 filter2D->SetInput( inputImage2D );
170 filter2D->SetInputIsBinary(true);
171
172 if( filter2D->GetInputIsBinary() != true )
173 {
174 std::cerr << "filter2D->GetInputIsBinary() != true" <<std::endl;
175 return EXIT_FAILURE;
176 }
177
178
179 filter2D->UseImageSpacingOn();
180
181 if( filter2D->GetUseImageSpacing() != true )
182 {
183 std::cerr << "filter2D->GetUseImageSpacing() != true" << std::endl;
184 return EXIT_FAILURE;
185 }
186
187 filter2D->SetUseImageSpacing(true);
188 filter2D->Update();
189
190 index2D[1] = 5;
191 auto expectedValue = static_cast<myImageType2D2::PixelType>(anisotropicSpacing[1]);
192 expectedValue *= expectedValue;
193 myImageType2D2::PixelType pixelValue =
194 filter2D->GetOutput()->GetPixel( index2D );
195 if ( std::fabs( expectedValue - pixelValue ) > epsilon )
196 {
197 std::cerr << "Error when image spacing is anisotropic." << std::endl;
198 std::cerr << "Pixel value was " << pixelValue << ", expected " << expectedValue << std::endl;
199 return EXIT_FAILURE;
200 }
201
202 ShowDistanceMap(outputDistance2D);
203
204 // Create a large 3D image with a small foreground object. The foreground is denoted by a pixel value of 0,
205 // and the background by a non-zero pixel value. This will test speedups to the code that ignore all background
206 // pixels in the computation since those pixels do not influence the result.
207
208 // Allocate the 3D image
209 using ImageType3D = itk::Image< float, 3>;
210 ImageType3D::SizeType size3D = {{200,200,200}};
211 ImageType3D::IndexType index3D = {{0,0}};
212 ImageType3D::RegionType region3D;
213 region3D.SetSize( size3D );
214 region3D.SetIndex( index3D );
215 ImageType3D::Pointer inputImage3D = ImageType3D::New();
216 inputImage3D->SetRegions( region3D );
217 inputImage3D->Allocate();
218 inputImage3D->FillBuffer(1);
219
220 // Set a few pixels in the middle of the image to 0. These are the foreground pixels for which the distance will be solved.
221 ImageType3D::IndexType foregroundIndex;
222 ImageType3D::SizeType foregroundSize;
223 for( unsigned int i = 0; i < 3; i++ )
224 {
225 foregroundSize[i] = 5;
226 foregroundIndex[i] = (size3D[i]/2) - foregroundSize[i]/2;
227 }
228 ImageType3D::RegionType foregroundRegion;
229 foregroundRegion.SetSize( foregroundSize );
230 foregroundRegion.SetIndex( foregroundIndex );
231
232 itk::ImageRegionIteratorWithIndex<ImageType3D> it3D(inputImage3D,foregroundRegion);
233 for( it3D.GoToBegin(); !it3D.IsAtEnd(); ++it3D )
234 {
235 it3D.Set( 0 );
236 }
237
238 // Create Danielsson Distance Map filter
239 using myFilterType3D = itk::DanielssonDistanceMapImageFilter< ImageType3D, ImageType3D >;
240
241 myFilterType3D::Pointer filter3D = myFilterType3D::New();
242
243 filter3D->SetInput( inputImage3D );
244 filter3D->Update();
245
246 return EXIT_SUCCESS;
247 }
248