1 // Copyright (C) 2011  Davis E. King (davis@dlib.net)
2 // License: Boost Software License   See LICENSE.txt for the full license.
3 
4 
5 #include <sstream>
6 #include <string>
7 #include <cstdlib>
8 #include <ctime>
9 #include "dlib/image_processing.h"
10 
11 #include "dlib/test/tester.h"
12 
13 #include "dlib/image_transforms.h"
14 #include "dlib/pixel.h"
15 #include "dlib/array2d.h"
16 #include "dlib/array.h"
17 
18 // ----------------------------------------------------------------------------------------
19 
20 namespace
21 {
22 
23     using namespace test;
24     using namespace dlib;
25     using namespace std;
26 
27     using dlib::array;
28 
29     // Declare the logger we will use in this test.  The name of the tester
30     // should start with "test."
31     logger dlog("test.scan_image");
32 
33 // ----------------------------------------------------------------------------------------
34 
35     template <typename image_type1, typename image_type2>
sum_filter_i(const image_type1 & img,image_type2 & out,const rectangle & rect)36     void sum_filter_i (
37         const image_type1& img,
38         image_type2& out,
39         const rectangle& rect
40     )
41     {
42         typedef typename image_type1::type pixel_type;
43         typedef typename promote<pixel_type>::type ptype;
44         integral_image_generic<ptype> iimg;
45         iimg.load(img);
46         for (long r = 0; r < img.nr(); ++r)
47         {
48             for (long c = 0; c < img.nc(); ++c)
49             {
50                 const rectangle temp = translate_rect(rect, point(c,r)).intersect(get_rect(iimg));
51                 if (temp.is_empty() == false)
52                     out[r][c] += iimg.get_sum_of_area(temp);
53             }
54         }
55 
56     }
57 
58 // ----------------------------------------------------------------------------------------
59 
60     template <
61         typename image_array_type
62         >
scan_image_i(std::vector<std::pair<double,point>> & dets,const image_array_type & images,const std::vector<std::pair<unsigned int,rectangle>> & rects,const double thresh,const unsigned long max_dets)63     void scan_image_i (
64         std::vector<std::pair<double, point> >& dets,
65         const image_array_type& images,
66         const std::vector<std::pair<unsigned int, rectangle> >& rects,
67         const double thresh,
68         const unsigned long max_dets
69     )
70     {
71         typedef typename image_array_type::type::type pixel_type;
72         typedef typename promote<pixel_type>::type ptype;
73         array<integral_image_generic<ptype> > iimg;
74         iimg.set_max_size(images.size());
75         iimg.set_size(images.size());
76 
77         for (unsigned long i = 0; i < iimg.size(); ++i)
78             iimg[i].load(images[i]);
79 
80 
81         dets.clear();
82 
83 
84         for (long r = 0; r < images[0].nr(); ++r)
85         {
86             for (long c = 0; c < images[0].nc(); ++c)
87             {
88                 ptype temp = 0;
89                 for (unsigned long i = 0; i < rects.size(); ++i)
90                 {
91                     rectangle rtemp = translate_rect(rects[i].second,point(c,r)).intersect(get_rect(images[0]));
92                     if (rtemp.is_empty() == false)
93                         temp += iimg[rects[i].first].get_sum_of_area(rtemp);
94                 }
95                 if (temp > thresh)
96                 {
97                     dets.push_back(std::make_pair(temp, point(c,r)));
98 
99                     if (dets.size() >= max_dets)
100                         return;
101 
102                 }
103             }
104         }
105     }
106 
107 // ----------------------------------------------------------------------------------------
108 
109     template <
110         typename image_array_type
111         >
scan_image_old(std::vector<std::pair<double,point>> & dets,const image_array_type & images,const std::vector<std::pair<unsigned int,rectangle>> & rects,const double thresh,const unsigned long max_dets)112     void scan_image_old (
113         std::vector<std::pair<double, point> >& dets,
114         const image_array_type& images,
115         const std::vector<std::pair<unsigned int, rectangle> >& rects,
116         const double thresh,
117         const unsigned long max_dets
118     )
119     {
120         dets.clear();
121         if (max_dets == 0)
122             return;
123 
124         typedef typename image_array_type::type::type pixel_type;
125         typedef typename promote<pixel_type>::type ptype;
126 
127         std::vector<std::vector<ptype> > column_sums(rects.size());
128         for (unsigned long i = 0; i < column_sums.size(); ++i)
129         {
130             const typename image_array_type::type& img = images[rects[i].first];
131             column_sums[i].resize(img.nc() + rects[i].second.width(),0);
132 
133             const long top    = -1 + rects[i].second.top();
134             const long bottom = -1 + rects[i].second.bottom();
135             long left = rects[i].second.left()-1;
136 
137             // initialize column_sums[i] at row -1
138             for (unsigned long j = 0; j < column_sums[i].size(); ++j)
139             {
140                 rectangle strip(left,top,left,bottom);
141                 strip = strip.intersect(get_rect(img));
142                 if (!strip.is_empty())
143                 {
144                     column_sums[i][j] = sum(matrix_cast<ptype>(subm(mat(img),strip)));
145                 }
146 
147                 ++left;
148             }
149         }
150 
151 
152         const rectangle area = get_rect(images[0]);
153 
154         for (long r = 0; r < images[0].nr(); ++r)
155         {
156             // set to sum at point(-1,r). i.e. should be equal to sum_of_rects_in_images(images, rects, point(-1,r))
157             // We compute it's value in the next loop.
158             ptype cur_sum = 0;
159 
160             // Update the first part of column_sums since we only work on the c+width part of column_sums
161             // in the main loop.
162             for (unsigned long i = 0; i < rects.size(); ++i)
163             {
164                 const typename image_array_type::type& img = images[rects[i].first];
165                 const long top    = r + rects[i].second.top() - 1;
166                 const long bottom = r + rects[i].second.bottom();
167                 const long width  = rects[i].second.width();
168                 for (long k = 0; k < width; ++k)
169                 {
170                     const long right  = k-width + rects[i].second.right();
171 
172                     const ptype br_corner = area.contains(right,bottom) ? img[bottom][right] : 0;
173                     const ptype tr_corner = area.contains(right,top)    ? img[top][right]    : 0;
174                     // update the sum in this column now that we are on the next row
175                     column_sums[i][k] = column_sums[i][k] + br_corner - tr_corner;
176                     cur_sum += column_sums[i][k];
177                 }
178             }
179 
180             for (long c = 0; c < images[0].nc(); ++c)
181             {
182                 for (unsigned long i = 0; i < rects.size(); ++i)
183                 {
184                     const typename image_array_type::type& img = images[rects[i].first];
185                     const long top    = r + rects[i].second.top() - 1;
186                     const long bottom = r + rects[i].second.bottom();
187                     const long right  = c + rects[i].second.right();
188                     const long width  =     rects[i].second.width();
189 
190                     const ptype br_corner = area.contains(right,bottom) ? img[bottom][right] : 0;
191                     const ptype tr_corner = area.contains(right,top)    ? img[top][right]    : 0;
192                     // update the sum in this column now that we are on the next row
193                     column_sums[i][c+width] = column_sums[i][c+width] + br_corner - tr_corner;
194 
195 
196                     // add in the new right side of the rect and subtract the old right side.
197                     cur_sum = cur_sum + column_sums[i][c+width] - column_sums[i][c];
198 
199                 }
200 
201                 if (cur_sum > thresh)
202                 {
203                     dets.push_back(std::make_pair(cur_sum, point(c,r)));
204 
205                     if (dets.size() >= max_dets)
206                         return;
207                 }
208             }
209         }
210     }
211 
212 // ----------------------------------------------------------------------------------------
213 
run_test1()214     void run_test1()
215     {
216         dlog << LINFO << "run_test1()";
217 
218         print_spinner();
219         array2d<unsigned char> img, temp_img;
220         img.set_size(600,600);
221         assign_all_pixels(img,0);
222         rectangle rect = centered_rect(10,10,5,5);
223         dlog << LTRACE << "expected: 10,10";
224         fill_rect(img, rect, 255);
225 
226 
227         array<array2d<unsigned char> > images;
228         std::vector<std::pair<unsigned int, rectangle> > rects;
229         for (int i = 0; i < 10; ++i)
230         {
231             assign_image(temp_img, img);
232             images.push_back(temp_img);
233             rects.push_back(make_pair(i,centered_rect(0,0,5,5)));
234         }
235 
236         std::vector<std::pair<double, point> > dets, dets2, dets3;
237 
238 
239         dlog << LTRACE << "best score: "<< sum_of_rects_in_images(images,rects,point(10,10));
240         scan_image(dets,images,rects,30000, 100);
241         scan_image_i(dets2,images,rects,30000, 100);
242         scan_image_old(dets3,images,rects,30000, 100);
243 
244 
245 
246         dlog << LTRACE << "dets.size(): "<< dets.size();
247         dlog << LTRACE << "dets2.size(): "<< dets2.size();
248         dlog << LTRACE << "dets3.size(): "<< dets3.size();
249 
250         DLIB_TEST(dets.size() == dets2.size());
251         DLIB_TEST(dets.size() == dets3.size());
252 
253         for (unsigned long i = 0; i < dets.size(); ++i)
254         {
255             //dlog << LTRACE << "dets["<<i<<"]: " << dets[i].second << "  -> " << dets[i].first;
256             //dlog << LTRACE << "dets2["<<i<<"]: " << dets2[i].second << "  -> " << dets2[i].first;
257             //dlog << LTRACE << "dets3["<<i<<"]: " << dets3[i].second << "  -> " << dets3[i].first;
258 
259             DLIB_TEST(sum_of_rects_in_images(images, rects, dets[i].second) == dets[i].first);
260             DLIB_TEST(sum_of_rects_in_images(images, rects, dets2[i].second) == dets2[i].first);
261             DLIB_TEST(sum_of_rects_in_images(images, rects, dets3[i].second) == dets3[i].first);
262         }
263 
264 
265     }
266 
267 // ----------------------------------------------------------------------------------------
268 
run_test2()269     void run_test2()
270     {
271         print_spinner();
272         dlog << LINFO << "run_test2()";
273         array2d<unsigned char> img, temp_img;
274         img.set_size(600,600);
275         assign_all_pixels(img,0);
276         rectangle rect = centered_rect(10,11,5,6);
277         dlog << LTRACE << "expected: 10,11";
278         fill_rect(img, rect, 255);
279 
280 
281         array<array2d<unsigned char> > images;
282         std::vector<std::pair<unsigned int, rectangle> > rects;
283         for (int i = 0; i < 10; ++i)
284         {
285             assign_image(temp_img, img);
286             images.push_back(temp_img);
287             rects.push_back(make_pair(i,centered_rect(0,0,5,5)));
288             rects.push_back(make_pair(i,centered_rect(3,2,5,6)));
289         }
290 
291         std::vector<std::pair<double, point> > dets, dets2, dets3;
292 
293 
294         scan_image(dets,images,rects,30000, 100);
295         scan_image_i(dets2,images,rects,30000, 100);
296         scan_image_old(dets3,images,rects,30000, 100);
297 
298 
299 
300         dlog << LTRACE << "dets.size(): "<< dets.size();
301         dlog << LTRACE << "dets2.size(): "<< dets2.size();
302         dlog << LTRACE << "dets3.size(): "<< dets3.size();
303 
304         DLIB_TEST(dets.size() == dets2.size());
305         DLIB_TEST(dets.size() == dets3.size());
306 
307         for (unsigned long i = 0; i < dets.size(); ++i)
308         {
309             //dlog << LTRACE << "dets["<<i<<"]: " << dets[i].second << "  -> " << dets[i].first;
310             //dlog << LTRACE << "dets2["<<i<<"]: " << dets2[i].second << "  -> " << dets2[i].first;
311             //dlog << LTRACE << "dets3["<<i<<"]: " << dets3[i].second << "  -> " << dets3[i].first;
312 
313             DLIB_TEST(sum_of_rects_in_images(images, rects, dets[i].second) == dets[i].first);
314             DLIB_TEST(sum_of_rects_in_images(images, rects, dets2[i].second) == dets2[i].first);
315             DLIB_TEST(sum_of_rects_in_images(images, rects, dets3[i].second) == dets3[i].first);
316         }
317 
318 
319     }
320 
321 // ----------------------------------------------------------------------------------------
322 
323     template <typename pixel_type>
run_test3(const double thresh)324     void run_test3(const double thresh)
325     {
326         dlog << LINFO << "running run_test3("<<thresh<<")";
327         dlib::rand rnd;
328 
329         rnd.set_seed("235");
330 
331         array<array2d<pixel_type> > images;
332         images.resize(1);
333         images[0].set_size(200,180);
334 
335         for (int iter = 0; iter < 50; ++iter)
336         {
337             print_spinner();
338             assign_all_pixels(images[0], thresh - 0.0001);
339 
340             for (int i = 0; i < 20; ++i)
341             {
342                 point p1(rnd.get_random_32bit_number()%images[0].nc(),
343                          rnd.get_random_32bit_number()%images[0].nr());
344                 point p2(rnd.get_random_32bit_number()%images[0].nc(),
345                          rnd.get_random_32bit_number()%images[0].nr());
346 
347                 rectangle rect(p1,p2);
348                 fill_rect(images[0], rect, static_cast<pixel_type>(rnd.get_random_double()*10 - 5));
349             }
350 
351             std::vector<std::pair<unsigned int, rectangle> > rects;
352             rects.push_back(make_pair(0,centered_rect(0,0,1+rnd.get_random_32bit_number()%40,1+rnd.get_random_32bit_number()%40)));
353             rects.push_back(make_pair(0,centered_rect(0,0,1+rnd.get_random_32bit_number()%40,1+rnd.get_random_32bit_number()%40)));
354 
355 
356 
357 
358             std::vector<std::pair<double, point> > dets, dets2, dets3;
359             scan_image(dets,images,rects,thresh, 100);
360             scan_image_i(dets2,images,rects,thresh, 100);
361             scan_image_old(dets3,images,rects,thresh, 100);
362 
363             dlog << LTRACE << "dets.size(): "<< dets.size();
364             dlog << LTRACE << "dets2.size(): "<< dets2.size();
365             dlog << LTRACE << "dets3.size(): "<< dets3.size();
366 
367             DLIB_TEST(dets.size() == dets2.size());
368             DLIB_TEST(dets.size() == dets3.size());
369 
370             for (unsigned long i = 0; i < dets.size(); ++i)
371             {
372                 //dlog << LTRACE << "dets["<<i<<"]: " << dets[i].second << "  -> " << dets[i].first;
373                 //dlog << LTRACE << "dets2["<<i<<"]: " << dets2[i].second << "  -> " << dets2[i].first;
374                 //dlog << LTRACE << "dets3["<<i<<"]: " << dets3[i].second << "  -> " << dets3[i].first;
375 
376                 DLIB_TEST_MSG(std::abs(sum_of_rects_in_images(images, rects, dets[i].second) - dets[i].first) < 1e-6,
377                               "error: "<< sum_of_rects_in_images(images, rects, dets[i].second) - dets[i].first
378                               << "   dets["<<i<<"].second: " << dets[i].second
379                               );
380                 DLIB_TEST_MSG(std::abs(sum_of_rects_in_images(images, rects, dets2[i].second) - dets2[i].first) < 1e-6,
381                               sum_of_rects_in_images(images, rects, dets2[i].second) - dets2[i].first
382                               );
383                 DLIB_TEST_MSG(std::abs(sum_of_rects_in_images(images, rects, dets3[i].second) - dets3[i].first) < 1e-6,
384                               "error: "<< sum_of_rects_in_images(images, rects, dets3[i].second) - dets3[i].first
385                               << "   dets3["<<i<<"].first: " << dets3[i].first
386                               << "   dets3["<<i<<"].second: " << dets3[i].second
387                               );
388             }
389 
390         }
391     }
392 
393 // ----------------------------------------------------------------------------------------
394 
395     template <typename pixel_type>
test_sum_filter()396     void test_sum_filter (
397     )
398     {
399         dlib::rand rnd;
400 
401         for (int k = 0; k < 20; ++k)
402         {
403             print_spinner();
404 
405             array2d<pixel_type> img(1 + rnd.get_random_32bit_number()%100,
406                                     1 + rnd.get_random_32bit_number()%100);
407 
408             for (long r = 0; r < img.nr(); ++r)
409             {
410                 for (long c = 0; c < img.nc(); ++c)
411                 {
412                     img[r][c] = static_cast<pixel_type>(100*(rnd.get_random_double()-0.5));
413                 }
414             }
415 
416             array2d<long> test1(img.nr(), img.nc());
417             array2d<double> test2(img.nr(), img.nc());
418             array2d<long> test1_i(img.nr(), img.nc());
419             array2d<double> test2_i(img.nr(), img.nc());
420 
421             assign_all_pixels(test1, 0);
422             assign_all_pixels(test2, 0);
423             assign_all_pixels(test1_i, 0);
424             assign_all_pixels(test2_i, 0);
425 
426             for (int i = 0; i < 10; ++i)
427             {
428                 const long width  = rnd.get_random_32bit_number()%10 + 1;
429                 const long height = rnd.get_random_32bit_number()%10 + 1;
430                 const point p(rnd.get_random_32bit_number()%img.nc(),
431                               rnd.get_random_32bit_number()%img.nr());
432 
433                 const rectangle rect = centered_rect(p, width, height);
434                 sum_filter(img, test1, rect);
435                 sum_filter(img, test2, rect);
436                 sum_filter(img, test1_i, rect);
437                 sum_filter(img, test2_i, rect);
438 
439                 DLIB_TEST(mat(test1) == mat(test1_i));
440                 DLIB_TEST(mat(test2) == mat(test2_i));
441             }
442         }
443     }
444 
445 // ----------------------------------------------------------------------------------------
446 
447     template <
448         typename image_type1,
449         typename image_type2
450         >
naive_max_filter(const image_type1 & img,image_type2 & out,const long width,const long height,typename image_type1::type thresh)451     void naive_max_filter (
452         const image_type1& img,
453         image_type2& out,
454         const long width,
455         const long height,
456         typename image_type1::type thresh
457         )
458     {
459         const rectangle area = get_rect(img);
460         for (long r = 0; r < img.nr(); ++r)
461         {
462             for (long c = 0; c < img.nc(); ++c)
463             {
464                 const rectangle win = centered_rect(point(c,r),width,height).intersect(area);
465                 out[r][c] += std::max(dlib::max(subm(mat(img),win)), thresh);
466             }
467         }
468     }
469 
470 // ----------------------------------------------------------------------------------------
471 
test_max_filter(long rows,long cols,long width,long height,dlib::rand & rnd)472     void test_max_filter(long rows, long cols, long width, long height, dlib::rand& rnd)
473     {
474         array2d<int> img(rows, cols);
475         rectangle rect = centered_rect(0,0, width, height);
476 
477         array2d<int> out(img.nr(),img.nc());
478         assign_all_pixels(out, 0);
479         array2d<int> out2(img.nr(),img.nc());
480         assign_all_pixels(out2, 0);
481 
482         for (long r = 0; r < img.nr(); ++r)
483         {
484             for (long c = 0; c < img.nc(); ++c)
485             {
486                 img[r][c] = rnd.get_random_32bit_number();
487             }
488         }
489 
490         const int thresh = rnd.get_random_32bit_number();
491 
492         naive_max_filter(img, out2, rect.width(), rect.height(), thresh);
493         max_filter(img, out, rect.width(), rect.height(), thresh);
494 
495         DLIB_TEST_MSG(mat(out) == mat(out2),
496                                 "rows: "<< rows
497                                 << "\ncols: "<< rows
498                                 << "\nwidth: "<< width
499                                 << "\nheight: "<< height );
500     }
501 
502 // ----------------------------------------------------------------------------------------
503 
test_max_filter()504     void test_max_filter()
505     {
506         dlib::rand rnd;
507         for (int iter = 0; iter < 300; ++iter)
508         {
509             print_spinner();
510             test_max_filter(0,0,1,1,rnd);
511             test_max_filter(0,0,3,1,rnd);
512             test_max_filter(0,0,3,3,rnd);
513             test_max_filter(0,0,1,3,rnd);
514             test_max_filter(1,1,1,1,rnd);
515             test_max_filter(2,2,1,1,rnd);
516             test_max_filter(3,3,1,1,rnd);
517             test_max_filter(3,3,3,3,rnd);
518             test_max_filter(3,3,2,2,rnd);
519             test_max_filter(3,3,3,5,rnd);
520             test_max_filter(3,3,6,8,rnd);
521             test_max_filter(20,20,901,901,rnd);
522             test_max_filter(5,5,1,5,rnd);
523             test_max_filter(50,50,9,9,rnd);
524             test_max_filter(50,50,9,9,rnd);
525             test_max_filter(50,50,10,10,rnd);
526             test_max_filter(50,50,11,10,rnd);
527             test_max_filter(50,50,10,11,rnd);
528             test_max_filter(50,50,10,21,rnd);
529             test_max_filter(50,50,20,10,rnd);
530             test_max_filter(50,50,20,10,rnd);
531             test_max_filter(50,50,9,9,rnd);
532             test_max_filter(20,20,1,901,rnd);
533             test_max_filter(20,20,3,901,rnd);
534             test_max_filter(20,20,901,1,rnd);
535         }
536 
537         for (int iter = 0; iter < 200; ++iter)
538         {
539             print_spinner();
540             test_max_filter((int)rnd.get_random_8bit_number()%100+1,
541                             (int)rnd.get_random_8bit_number()%100+1,
542                             (int)rnd.get_random_8bit_number()%150+1,
543                             (int)rnd.get_random_8bit_number()%150+1,
544                             rnd);
545         }
546     }
547 
548 // ----------------------------------------------------------------------------------------
549 
make_images(dlib::rand & rnd,array<array2d<unsigned char>> & images,long num,long nr,long nc)550     void make_images (
551         dlib::rand& rnd,
552         array<array2d<unsigned char> >& images,
553         long num,
554         long nr,
555         long nc
556     )
557     {
558         images.resize(num);
559         for (unsigned long i = 0; i < images.size(); ++i)
560         {
561             images[i].set_size(nr,nc);
562         }
563 
564         for (unsigned long i = 0; i < images.size(); ++i)
565         {
566             for (long r = 0; r < nr; ++r)
567             {
568                 for (long c = 0; c < nc; ++c)
569                 {
570                     images[i][r][c] = rnd.get_random_8bit_number();
571                 }
572             }
573         }
574     }
575 
576 
577     template <
578         typename image_array_type
579         >
brute_force_scan_image_movable_parts(std::vector<std::pair<double,point>> & dets,const image_array_type & images,const rectangle & window,const std::vector<std::pair<unsigned int,rectangle>> & fixed_rects,const std::vector<std::pair<unsigned int,rectangle>> & movable_rects,const double thresh,const unsigned long)580     void brute_force_scan_image_movable_parts (
581         std::vector<std::pair<double, point> >& dets,
582         const image_array_type& images,
583         const rectangle& window,
584         const std::vector<std::pair<unsigned int, rectangle> >& fixed_rects,
585         const std::vector<std::pair<unsigned int, rectangle> >& movable_rects,
586         const double thresh,
587         const unsigned long
588     )
589     {
590         dets.clear();
591         if (movable_rects.size() == 0 && fixed_rects.size() == 0)
592             return;
593 
594         for (long r = 0; r < images[0].nr(); ++r)
595         {
596             for (long c = 0; c < images[0].nc(); ++c)
597             {
598                 const point p(c,r);
599                 double score = sum_of_rects_in_images_movable_parts(images,
600                                                                     window,
601                                                                     fixed_rects,
602                                                                     movable_rects,
603                                                                     p);
604 
605                 if (score >= thresh)
606                 {
607                     dets.push_back(make_pair(score,p));
608                 }
609             }
610         }
611     }
612 
test_scan_images_movable_parts()613     void test_scan_images_movable_parts()
614     {
615         array<array2d<unsigned char> > images;
616         dlib::rand rnd;
617         for (int iter = 0; iter < 40; ++iter)
618         {
619             print_spinner();
620             const int num_images = rnd.get_random_32bit_number()%4+1;
621 
622             make_images(rnd,images, num_images,
623                         rnd.get_random_32bit_number()%50+1,
624                         rnd.get_random_32bit_number()%50+1
625                         );
626 
627             std::vector<std::pair<double,point> > dets1, dets2;
628             std::vector<std::pair<unsigned int, rectangle> > fixed_rects, movable_rects;
629 
630             double total_area = 0;
631             for (unsigned long i = 0; i < images.size(); ++i)
632             {
633                 fixed_rects.push_back(make_pair(i, centered_rect(
634                             rnd.get_random_32bit_number()%10-5,
635                             rnd.get_random_32bit_number()%10-5,
636                             rnd.get_random_32bit_number()%10,
637                             rnd.get_random_32bit_number()%10
638                             )));
639 
640                 total_area += fixed_rects.back().second.area();
641 
642                 movable_rects.push_back(make_pair(i, centered_rect(
643                             0,
644                             0,
645                             rnd.get_random_32bit_number()%10+1,
646                             rnd.get_random_32bit_number()%10+1
647                             )));
648                 total_area += movable_rects.back().second.area();
649             }
650 
651             const rectangle window = centered_rect(0,0,
652                                                 rnd.get_random_32bit_number()%15+1,
653                                                 rnd.get_random_32bit_number()%15+1);
654             dlog << LINFO << "window size: "<< window.width() << ", " << window.height();
655             const double thresh = total_area*130;
656             const unsigned long max_dets = get_rect(images[0]).area();
657 
658             scan_image_movable_parts(dets1,images,window,fixed_rects,movable_rects,thresh, max_dets);
659             brute_force_scan_image_movable_parts(dets2,images,window,fixed_rects,movable_rects,thresh, max_dets);
660 
661             dlog << LINFO << "max_possible dets: " << max_dets;
662             dlog << LINFO << "regular dets: " << dets1.size();
663             dlog << LINFO << "brute force:  " << dets2.size();
664             DLIB_TEST(dets1.size() == dets2.size());
665 
666             array2d<double> check(images[0].nr(), images[0].nc());
667             assign_all_pixels(check, 1e-300);
668             for (unsigned long i = 0; i < dets1.size(); ++i)
669             {
670                 const point p = dets1[i].second;
671                 check[p.y()][p.x()] = dets1[i].first;
672             }
673             for (unsigned long i = 0; i < dets2.size(); ++i)
674             {
675                 const point p = dets2[i].second;
676                 DLIB_TEST(std::abs(check[p.y()][p.x()] - dets2[i].first) < 1e-10);
677             }
678             dlog << LINFO << "=======================\n";
679         }
680     }
681 
682 // ----------------------------------------------------------------------------------------
683 
684     class scan_image_tester : public tester
685     {
686     public:
scan_image_tester()687         scan_image_tester (
688         ) :
689             tester ("test_scan_image",
690                     "Runs tests on the scan_image routine.")
691         {}
692 
perform_test()693         void perform_test (
694         )
695         {
696             test_scan_images_movable_parts();
697             test_max_filter();
698 
699             run_test1();
700             run_test2();
701             run_test3<unsigned char>(1);
702             run_test3<unsigned char>(-1);
703             run_test3<double>(1);
704             run_test3<double>(-1);
705 
706             test_sum_filter<unsigned char>();
707             test_sum_filter<double>();
708         }
709     } a;
710 
711 }
712 
713 
714