1 // This is mul/vil3d/tests/test_algo_find_blobs.cxx
2
3 #include <iostream>
4 #include <map>
5 #ifdef _MSC_VER
6 # include "vcl_msvc_warnings.h"
7 #endif
8 #include "testlib/testlib_test.h"
9 #include <vil3d/algo/vil3d_find_blobs.h>
10 #include <vil3d/vil3d_crop.h>
11 #include <vil3d/vil3d_print.h>
12 #include "vgl/vgl_point_3d.h"
13
14
15 //========================================================================
16 // Find the first voxel (in raster scan order) of each blob in a blob image
17 //========================================================================
first_voxel_of_blobs(const vil3d_image_view<unsigned> & img,std::map<unsigned,vgl_point_3d<unsigned>> & blob_vox)18 static void first_voxel_of_blobs(const vil3d_image_view<unsigned>& img,
19 std::map<unsigned, vgl_point_3d<unsigned> >& blob_vox)
20 {
21 blob_vox.clear();
22
23 for (unsigned k=0; k<img.nk(); ++k)
24 {
25 for (unsigned j=0; j<img.nj(); ++j)
26 {
27 for (unsigned i=0; i<img.ni(); ++i)
28 {
29 unsigned label = img(i,j,k);
30 if (blob_vox.find(label)==blob_vox.end())
31 {
32 blob_vox[label] = vgl_point_3d<unsigned>(i,j,k);
33 }
34 }
35 }
36 }
37 }
38
39
40 //========================================================================
41 // Find blobs and check against true answer
42 //========================================================================
test_blob_image(const vil3d_image_view<bool> & src,const vil3d_find_blob_connectivity conn,const vil3d_image_view<unsigned> & tru,const std::string & testname)43 static void test_blob_image(const vil3d_image_view<bool>& src,
44 const vil3d_find_blob_connectivity conn,
45 const vil3d_image_view<unsigned>& tru,
46 const std::string& testname)
47 {
48 vil3d_image_view<unsigned> dst;
49 vil3d_find_blobs(src, conn, dst);
50
51 // Check first voxels
52 std::map<unsigned, vgl_point_3d<unsigned> > blob_vox;
53 first_voxel_of_blobs(src, blob_vox);
54
55
56 // NB FIX THIS: labels need not match but must have 1:1 relationship...
57 TEST(testname.c_str(), vil3d_image_view_deep_equality(dst,tru), true);
58
59 #if 0
60 //#ifndef NDEBUG
61 std::cout << "--------------------------------------------------\n"
62 << testname << "\n\n";
63
64 std::cout << "src image:\n";
65 vil3d_print_all(std::cout, src);
66 std::cout << '\n';
67
68 std::cout << "dst image:\n";
69 vil3d_print_all(std::cout, dst);
70 std::cout << '\n';
71
72 std::cout << "tru image:\n";
73 vil3d_print_all(std::cout, tru);
74 std::cout << '\n';
75
76 std::cout << "first voxels:\n";
77 for (std::map<unsigned, vgl_point_3d<unsigned> >::const_iterator it=blob_vox.begin();
78 it!=blob_vox.end(); ++it)
79 {
80 std::cout << it->first << ": "
81 << it->second.x() << ' '
82 << it->second.y() << ' '
83 << it->second.z() << '\n';
84 }
85 std::cout << '\n';
86
87 std::cout << "--------------------------------------------------\n";
88 //#endif // NDEBUG
89 #endif
90 }
91
92
93 //========================================================================
94 // All-background image
95 //========================================================================
test_all_background()96 static void test_all_background()
97 {
98 const unsigned ni=9, nj=10, nk=11, np=1;
99
100 vil3d_image_view<bool> src(ni, nj, nk, np);
101 src.fill(false);
102
103 vil3d_image_view<unsigned> tru(ni, nj, nk, np);
104 tru.fill(0);
105
106 test_blob_image(src, vil3d_find_blob_connectivity_6_conn, tru,
107 "Test all-background image");
108 test_blob_image(src, vil3d_find_blob_connectivity_26_conn, tru,
109 "Test all-background image");
110 }
111
112
113 //========================================================================
114 // All-foreground image
115 //========================================================================
test_all_foreground()116 static void test_all_foreground()
117 {
118 const unsigned ni=3, nj=4, nk=5, np=1;
119
120 vil3d_image_view<bool> src(ni, nj, nk, np);
121 src.fill(true);
122
123 vil3d_image_view<unsigned> tru(ni, nj, nk, np);
124 tru.fill(1);
125
126 test_blob_image(src, vil3d_find_blob_connectivity_6_conn, tru,
127 "Test all-foreground image");
128 test_blob_image(src, vil3d_find_blob_connectivity_26_conn, tru,
129 "Test all-foreground image");
130 }
131
132
133 //========================================================================
134 // Single central blob
135 //========================================================================
test_single_central()136 static void test_single_central()
137 {
138 const unsigned ni=9, nj=10, nk=11, np=1;
139
140 vil3d_image_view<bool> src(ni, nj, nk, np);
141 src.fill(false);
142 vil3d_crop(src, 3,3, 3,4, 3,5).fill(true);
143 src(6,5,4)=true; src(4,7,5)=true; src(5,6,8)=true;
144
145 vil3d_image_view<unsigned> tru(ni, nj, nk, np);
146 tru.fill(0);
147 vil3d_crop(tru, 3,3, 3,4, 3,5).fill(1);
148 tru(6,5,4)=1; tru(4,7,5)=1; tru(5,6,8)=1;
149
150 test_blob_image(src, vil3d_find_blob_connectivity_6_conn, tru, "Test single central blob");
151 test_blob_image(src, vil3d_find_blob_connectivity_26_conn, tru, "Test single central blob");
152 }
153
154
155 //========================================================================
156 // Single blob at image edge
157 //========================================================================
test_single_edge()158 static void test_single_edge()
159 {
160 const unsigned ni=9, nj=10, nk=11, np=1;
161
162 vil3d_image_view<bool> src(ni, nj, nk, np);
163 src.fill(false);
164 vil3d_crop(src, 0,3, 3,4, 3,5).fill(true);
165
166 vil3d_image_view<unsigned> tru(ni, nj, nk, np);
167 tru.fill(0);
168 vil3d_crop(tru, 0,3, 3,4, 3,5).fill(1);
169
170 test_blob_image(src, vil3d_find_blob_connectivity_6_conn, tru, "Test single edge blob");
171 test_blob_image(src, vil3d_find_blob_connectivity_26_conn, tru, "Test single edge blob");
172 }
173
174
175 //========================================================================
176 // Multiple separate blobs
177 // Design note: these blobs are all separate (even with 26-conn) in 3D;
178 // however, they appear to overlap in 2 of the 3 axes.
179 //========================================================================
test_multiple_separate()180 static void test_multiple_separate()
181 {
182 const unsigned ni=9, nj=10, nk=11, np=1;
183
184 vil3d_image_view<bool> src(ni, nj, nk, np);
185 src.fill(false);
186 vil3d_crop(src, 1,3, 1,4, 1,5).fill(true);
187 vil3d_crop(src, 6,3, 2,4, 2,4).fill(true);
188 vil3d_crop(src, 2,4, 7,3, 3,3).fill(true);
189 vil3d_crop(src, 2,5, 2,5, 7,3).fill(true);
190
191 vil3d_image_view<unsigned> tru(ni, nj, nk, np);
192 tru.fill(0);
193 vil3d_crop(tru, 1,3, 1,4, 1,5).fill(1);
194 vil3d_crop(tru, 6,3, 2,4, 2,4).fill(2);
195 vil3d_crop(tru, 2,4, 7,3, 3,3).fill(3);
196 vil3d_crop(tru, 2,5, 2,5, 7,3).fill(4);
197
198 test_blob_image(src, vil3d_find_blob_connectivity_6_conn, tru, "Test multiple separate blobs");
199 test_blob_image(src, vil3d_find_blob_connectivity_26_conn, tru, "Test multiple separate blobs");
200 }
201
202 //========================================================================
203 // two blobs, with one that will invoke the connected merging code.
204 //========================================================================
test_merging_blocks()205 static void test_merging_blocks()
206 {
207 const unsigned ni=9, nj=10, nk=11, np=1;
208
209 vil3d_image_view<bool> src(ni, nj, nk, np);
210 src.fill(false);
211 vil3d_crop(src, 1,7, 1,7, 1,7).fill(true);
212 vil3d_crop(src, 1,6, 1,6, 1,6).fill(false);
213 vil3d_crop(src, 1,3, 1,3, 1,3).fill(true);
214
215 vil3d_image_view<unsigned> tru(ni, nj, nk, np);
216 tru.fill(0);
217 vil3d_crop(tru, 1,7, 1,7, 1,7).fill(2);
218 vil3d_crop(tru, 1,6, 1,6, 1,6).fill(0);
219 vil3d_crop(tru, 1,3, 1,3, 1,3).fill(1);
220
221 test_blob_image(src, vil3d_find_blob_connectivity_6_conn, tru, "Test simple merging case");
222 test_blob_image(src, vil3d_find_blob_connectivity_26_conn, tru, "Test simple merging case");
223 }
224
225
226 //========================================================================
227 // One diagonal line that exercises the merging code.
228 //========================================================================
test_merging_diagonal_line()229 static void test_merging_diagonal_line()
230 {
231 const unsigned ni=9, nj=10, nk=11, np=1;
232
233 vil3d_image_view<bool> src(ni, nj, nk, np);
234 src.fill(false);
235 vil3d_image_view<unsigned> tru(ni, nj, nk, np);
236 tru.fill(0);
237 for (unsigned i=0; i<ni; ++i)
238 {
239 src(ni-i-1, i, i) = true;
240 tru(ni-i-1, i, i) = 1;
241 }
242
243 test_blob_image(src, vil3d_find_blob_connectivity_26_conn, tru,
244 "Test merging diagonal line");
245 }
246
247 //=============================================================================
248 // lots of limbs in a single blob that exercises the merging code.
249 // Check that renumber also makes label set compact.
250 //=============================================================================
test_multilimb_merging()251 static void test_multilimb_merging()
252 {
253 const unsigned ni=9, nj=9, nk=9, np=1;
254
255 vil3d_image_view<bool> src(ni, nj, nk, np);
256 src.fill(false);
257 vil3d_image_view<unsigned> tru(ni, nj, nk, np);
258 tru.fill(0);
259 for (unsigned i=0; i<ni-1; i+=2)
260 {
261 for (unsigned k=0; k<nk-1; k+=2)
262 {
263 src(i, 1, k )=true;
264 src(i, 2, k )=true;
265 src(i+1,2, k )=true;
266 src(i, 2, k+1)=true;
267 src(i+1,2, k+1)=true;
268 tru(i, 1, k )=1;
269 tru(i, 2, k )=1;
270 tru(i+1,2, k )=1;
271 tru(i, 2, k+1)=1;
272 tru(i+1,2, k+1)=1;
273 }
274 }
275
276 src(5, 5, 5)=true;
277 tru(5, 5, 5)=2;
278
279 test_blob_image(src, vil3d_find_blob_connectivity_6_conn, tru,
280 "Test multilimb blob merging");
281 }
282
283 //=============================================================================
284 // lots of long awkward limbs in a single blob that exercises the merging code.
285 // Check that renumber also makes label set compact.
286 //=============================================================================
test_multilimb_merging2()287 static void test_multilimb_merging2()
288 {
289 const unsigned ni=9, nj=9, nk=9, np=1;
290
291 vil3d_image_view<bool> src(ni, nj, nk, np);
292 src.fill(false);
293 vil3d_image_view<unsigned> tru(ni, nj, nk, np);
294 tru.fill(0);
295 for (unsigned i=1; i<ni-2; i+=2)
296 {
297 vil3d_crop(src, 1,ni-i-1, 2,1, i,1).fill(true);
298 vil3d_crop(tru, 1,ni-i-1, 2,1, i,1).fill(1);
299 src(ni-i-1, 2, i+1)=true;
300 src(ni-i-1, 2, i+2)=true;
301 src(ni-i-2, 2, i+2)=true;
302 tru(ni-i-1, 2, i+1)=1;
303 tru(ni-i-1, 2, i+2)=1;
304 tru(ni-i-2, 2, i+2)=1;
305 }
306
307 src(5, 4, 5)=true;
308 tru(5, 4, 5)=2;
309
310 test_blob_image(src, vil3d_find_blob_connectivity_6_conn, tru,
311 "Test multilimb blob merging2");
312 test_blob_image(src, vil3d_find_blob_connectivity_26_conn, tru,
313 "Test multilimb blob merging2");
314 }
315
316
317 //=============================================================================
318 // lots of long awkward limbs in a single blob that exercises the merging code.
319 // Check that renumber also makes label set compact.
320 //=============================================================================
test_multilimb_merging3()321 static void test_multilimb_merging3()
322 {
323 const unsigned ni=9, nj=9, nk=9, np=1;
324
325 vil3d_image_view<bool> src(ni, nj, nk, np);
326 src.fill(false);
327 vil3d_image_view<unsigned> tru(ni, nj, nk, np);
328 tru.fill(0);
329 for (unsigned i=1; i<ni-2; i+=2)
330 {
331 vil3d_crop(src, 1,ni-i-1, 2,1, i,1).fill(true);
332 vil3d_crop(tru, 1,ni-i-1, 2,1, i,1).fill(1);
333 src(ni-i, 2, i+1)=true;
334 src(ni-i-1, 2, i+2)=true;
335 src(ni-i-2, 2, i+2)=true;
336 tru(ni-i, 2, i+1)=1;
337 tru(ni-i-1, 2, i+2)=1;
338 tru(ni-i-2, 2, i+2)=1;
339 }
340
341 src(5, 4, 5)=true;
342 tru(5, 4, 5)=2;
343
344 test_blob_image(src, vil3d_find_blob_connectivity_26_conn, tru,
345 "Test multilimb blob merging3");
346 }
347
348 //========================================================================
349 // Main function
350 //========================================================================
test_algo_find_blobs()351 static void test_algo_find_blobs()
352 {
353 std::cout << "**************************\n"
354 << " Testing vil3d_find_blobs\n"
355 << "**************************\n";
356
357 test_all_background();
358 test_all_foreground();
359 test_single_central();
360 test_single_edge();
361 test_multiple_separate();
362 test_merging_blocks();
363 test_merging_diagonal_line();
364 test_multilimb_merging();
365 test_multilimb_merging2();
366 test_multilimb_merging3();
367
368
369 // Multiple blobs with diagonal connectivity
370
371 // Multiple nested blobs
372
373 // Test multi-plane image - no need for this, blob-finder only claims to handle first plane
374 }
375
376
377 //========================================================================
378 // test macro
379 //========================================================================
380 TESTMAIN(test_algo_find_blobs);
381