1 // This is brl/bpro/core/brip_pro/processes/brip_blob_intersection_process.cxx
2 #include <iostream>
3 #include <algorithm>
4 #include <sstream>
5 #include <bprb/bprb_func_process.h>
6 //:
7 // \file
8 
9 #include <boxm2/util/boxm2_detect_change_blobs.h>
10 #include <bil/algo/bil_blob_finder.h>
11 #include <bprb/bprb_parameters.h>
12 #include "vil/vil_image_view.h"
13 #include "vil/vil_chord.h"
14 #include <bbas_pro/bbas_1d_array_float.h>
15 #ifdef _MSC_VER
16 #  include "vcl_msvc_warnings.h"
17 #endif
18 
19 namespace brip_blob_intersection_process_globals
20 {
21   constexpr unsigned n_inputs_ = 2;
22   constexpr unsigned n_outputs_ = 3;
23 }
24 
25 //: Constructor
brip_blob_intersection_process_cons(bprb_func_process & pro)26 bool brip_blob_intersection_process_cons(bprb_func_process& pro)
27 {
28   using namespace brip_blob_intersection_process_globals;
29 
30   // this process takes 2 inputs:
31   std::vector<std::string> input_types;
32   input_types.emplace_back("vil_image_view_base_sptr");  // modeled blob map
33   input_types.emplace_back("vil_image_view_base_sptr");  // ground truth map
34   // this process takes 3 outputs:
35   std::vector<std::string> output_types;
36   output_types.emplace_back("int");  // num true positives
37   output_types.emplace_back("int");  // num false positives
38   output_types.emplace_back("int");  // num blobs in GT
39 
40   return pro.set_input_types(input_types)
41       && pro.set_output_types(output_types);
42 }
43 
44 //: Execute the process
brip_blob_intersection_process(bprb_func_process & pro)45 bool brip_blob_intersection_process(bprb_func_process& pro)
46 {
47   using namespace brip_blob_intersection_process_globals;
48 
49   // Sanity check
50   if (pro.n_inputs() < n_inputs_) {
51     std::cerr << "brip_blob_intersection_process: The number of inputs should be 2\n";
52     return false;
53   }
54 
55   // get the inputs
56   vil_image_view_base_sptr blob_sptr = pro.get_input<vil_image_view_base_sptr>(0);
57   vil_image_view_base_sptr gt_sptr = pro.get_input<vil_image_view_base_sptr>(1);
58 
59   // check bounds to make sure they match
60   if (blob_sptr->ni() != gt_sptr->ni() || blob_sptr->nj() != gt_sptr->nj()) {
61     std::cout<<"brip_blob_intersection_process:: detection map doesn't match ground truth map"<<std::endl;
62     return false;
63   }
64 
65   // cast to usable image views
66   auto * gt_uchar = dynamic_cast<vil_image_view<vxl_byte> *>(gt_sptr.ptr());
67   if ( !gt_uchar ) {
68     std::cout<<"brip_blob_intersection_process:: gt map is not an unsigned char map"<<std::endl;
69     return false;
70   }
71   auto * blob_uchar =dynamic_cast<vil_image_view<unsigned char> *>(blob_sptr.ptr());
72   if (!blob_uchar) {
73     std::cout<<"brip_blob_intersection_process:: blob map is not an unsigned char map"<<std::endl;
74     return false;
75   }
76 
77   // create boolean gtmap
78   vil_image_view<bool>  gt_map(gt_uchar->ni(), gt_uchar->nj()),
79                         blob_map(gt_uchar->ni(), gt_uchar->nj());
80   for (unsigned int i=0; i<gt_uchar->ni(); ++i)
81     for (unsigned int j=0; j<gt_uchar->nj(); ++j) {
82       gt_map(i,j) = (*gt_uchar)(i,j) == 0 ? false : true;
83       blob_map(i,j) = (*blob_uchar)(i,j) == 0 ? false : true;
84     }
85 
86   // blob detect each image
87   bil_blob_finder gt_finder(gt_map);
88   bil_blob_finder mp_finder(blob_map);
89   typedef std::vector<vil_chord> blob_t;
90   std::vector<blob_t> gt_blobs, mp_blobs;
91 
92   // blob region is just a vector of vil_chords (rows in image)
93   std::vector<vil_chord> region;
94   while (gt_finder.next_4con_region(region))
95     gt_blobs.push_back(region);
96   while (mp_finder.next_4con_region(region))
97     mp_blobs.push_back(region);
98 
99   // ---- cross check blobs ---------
100   int numTP=0;
101   bool* trueBlobs = new bool[mp_blobs.size()];
102   std::fill(trueBlobs, trueBlobs+mp_blobs.size(), false);
103   for (auto gt_blob : gt_blobs) {
104     bool gt_blob_found = false;
105     for (unsigned int j=0; j<mp_blobs.size(); ++j) {
106       blob_t mp_blob = mp_blobs[j];
107 
108       // determine if gt_blob[i] intersects with mp_blob[j]
109       bool intersects = false;
110       blob_t::iterator gt_iter;
111       for (gt_iter=gt_blob.begin(); gt_iter!=gt_blob.end(); ++gt_iter) {
112         for (unsigned gt_i=gt_iter->ilo; gt_i<gt_iter->ihi; ++gt_i) {
113 
114           // gt pixel = (gt_i, gt_iter->j)
115           blob_t::iterator mp_iter;
116           for (mp_iter=mp_blob.begin(); mp_iter!=mp_blob.end(); ++mp_iter) {
117             for (unsigned mp_i=mp_iter->ilo; mp_i<mp_iter->ihi; ++mp_i) {
118               // mp pixel = (mp_i, mp_iter->j)
119               // if pixels match, they intersect
120               if (mp_i==gt_i && mp_iter->j==gt_iter->j) {
121                 intersects = true;
122                 break;
123               }
124             }
125           }
126           if (intersects)
127             break;
128         }
129         if (intersects)
130           break;
131       }
132 
133       // count total number of model blobs that intersect
134       if (intersects)
135         trueBlobs[j] = true;
136 
137       // determine true positive, false positive
138       if (intersects && !gt_blob_found) {
139         numTP++;
140         break;
141       }
142     }
143   }
144 
145   // count non intersecting blobs
146   int falseBlobs = 0;
147   for (unsigned int i=0; i<mp_blobs.size(); ++i)
148     if (!trueBlobs[i]) falseBlobs++;
149 
150   // set outputs
151   if (pro.n_outputs() < n_outputs_) {
152     std::cerr << "brip_blob_intersection_process: The number of outputs should be "<<n_outputs_<<'\n';
153     return false;
154   }
155   pro.set_output_val<int>(0, numTP);
156   pro.set_output_val<int>(1, falseBlobs);
157   pro.set_output_val<int>(2, gt_blobs.size());
158   return true;
159 }
160