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