1 // This is brl/bpro/core/sdet_pro/processes/sdet_filter_bank_processes.cxx
2 #include <bprb/bprb_func_process.h>
3 //:
4 // \file
5
6 #include <bprb/bprb_parameters.h>
7 #include <brdb/brdb_value.h>
8 #include <sdet/sdet_texture_classifier_params.h>
9 #include <sdet/sdet_texture_classifier.h>
10 #include "vil/vil_image_view.h"
11 #include "vnl/vnl_random.h"
12 #include "vil/vil_math.h"
13 #include "vil/vil_load.h"
14 #include "vil/vil_save.h"
15 #include "vil/vil_plane.h"
16 #include "vil/vil_resample_bilin.h"
17 #include "vil/vil_convert.h"
18
19 //: this process extracts the filter bank of an image (assumes a float image in the range [0, 1])
20 // and saves it in the filter_bank object of the passed texture_classifier instance
21 // the params of the classifier instance are used
sdet_extract_filter_bank_process_cons(bprb_func_process & pro)22 bool sdet_extract_filter_bank_process_cons(bprb_func_process& pro)
23 {
24 std::vector<std::string> input_types;
25 input_types.emplace_back("sdet_texture_classifier_sptr"); // classifier instance
26 input_types.emplace_back("vcl_string"); // input image name
27 input_types.emplace_back("vcl_string"); // filter bank folder
28 if (!pro.set_input_types(input_types))
29 return false;
30
31 std::vector<std::string> output_types;
32 return pro.set_output_types(output_types);
33 }
34
sdet_extract_filter_bank_process(bprb_func_process & pro)35 bool sdet_extract_filter_bank_process(bprb_func_process& pro)
36 {
37 if (!pro.verify_inputs())
38 {
39 std::cout << pro.name() << "sdet_extract_filter_bank_process inputs are not valid"<< std::endl;
40 return false;
41 }
42 // get inputs
43 sdet_texture_classifier_sptr tc_ptr = pro.get_input<sdet_texture_classifier_sptr>(0);
44 std::string name = pro.get_input<std::string>(1);
45 std::string folder = pro.get_input<std::string>(2);
46
47 // assumes to load a float image in [0,1] using the name, name should be full path to the image
48 if (!tc_ptr->compute_filter_bank_float_img(folder, name))
49 {
50 std::cout << "problems computing filter bank on the image!\n";
51 return false;
52 }
53
54 return true;
55 }
56
57 //: this process extracts the filter bank of an image (assumes a float image in the range [0, 1])
58 // and saves it in the filter_bank object of the passed texture_classifier instance
59 // the params of the classifier instance are used
sdet_extract_filter_bank_img_process_cons(bprb_func_process & pro)60 bool sdet_extract_filter_bank_img_process_cons(bprb_func_process& pro)
61 {
62 std::vector<std::string> input_types;
63 input_types.emplace_back("sdet_texture_classifier_sptr"); // classifier instance
64 input_types.emplace_back("vil_image_view_base_sptr"); // input image
65 if (!pro.set_input_types(input_types))
66 return false;
67
68 std::vector<std::string> output_types;
69 return pro.set_output_types(output_types);
70 }
71
sdet_extract_filter_bank_img_process(bprb_func_process & pro)72 bool sdet_extract_filter_bank_img_process(bprb_func_process& pro)
73 {
74 if (!pro.verify_inputs())
75 {
76 std::cout << pro.name() << "sdet_extract_filter_bank_process inputs are not valid"<< std::endl;
77 return false;
78 }
79 // get inputs
80 sdet_texture_classifier_sptr tc_ptr = pro.get_input<sdet_texture_classifier_sptr>(0);
81 vil_image_view_base_sptr img_ptr = pro.get_input<vil_image_view_base_sptr>(1);
82 vil_image_view<float> img(img_ptr);
83
84 // assumes to load a float image in [0,1] using the name, name should be full path to the image
85 if (!tc_ptr->compute_filter_bank(img))
86 {
87 std::cout << "problems computing filter bank on the image!\n";
88 return false;
89 }
90
91 return true;
92 }
93
94
95 //: this process extracts a "gauss" band from the input image and adds that as another layer to the filter_bank of the passed classifier
96 // practically increases the dimension of the textons
97 // the params of the classifier instance are used
sdet_add_to_filter_bank_process_cons(bprb_func_process & pro)98 bool sdet_add_to_filter_bank_process_cons(bprb_func_process& pro)
99 {
100 std::vector<std::string> input_types;
101 input_types.emplace_back("sdet_texture_classifier_sptr"); // classifier instance
102 input_types.emplace_back("vcl_string"); // input image name
103 input_types.emplace_back("unsigned"); // the plane to extract the filters from
104 input_types.emplace_back("vcl_string"); // filter bank folder
105 input_types.emplace_back("vcl_string"); // filter name : unique name to be used to write the response to filter folder
106 input_types.emplace_back("bool"); // option to turn on gauss smoothing on image
107 if (!pro.set_input_types(input_types))
108 return false;
109
110 std::vector<std::string> output_types;
111 return pro.set_output_types(output_types);
112 }
113
sdet_add_to_filter_bank_process(bprb_func_process & pro)114 bool sdet_add_to_filter_bank_process(bprb_func_process& pro)
115 {
116 if (!pro.verify_inputs())
117 {
118 std::cout << pro.name() << "sdet_extract_filter_bank_process inputs are not valid"<< std::endl;
119 return false;
120 }
121 // get inputs
122 sdet_texture_classifier_sptr tc_ptr = pro.get_input<sdet_texture_classifier_sptr>(0);
123 std::string name = pro.get_input<std::string>(1);
124 auto n = pro.get_input<unsigned>(2);
125 std::string folder = pro.get_input<std::string>(3);
126 std::string res_name = pro.get_input<std::string>(4);
127 bool is_smooth = pro.get_input<bool>(5);
128
129 vil_image_view_base_sptr img_sptr = vil_load(name.c_str());
130
131 vil_image_view<float> img_f;
132 if (auto* img_ptr = dynamic_cast<vil_image_view<vxl_byte>*>(img_sptr.ptr())) {
133 std::cout << " loaded image, ni: " << img_ptr->ni() << " " << img_ptr->nj() << " nplanes: " << img_ptr->nplanes()
134 << " with pixel format: " << img_ptr->pixel_format() << std::endl;
135 vil_image_view<vxl_byte> img_band = vil_plane(*img_ptr, n);
136 vil_convert_stretch_range_limited(img_band, img_f, (vxl_byte)0, (vxl_byte)255, 0.0f, 1.0f);
137 }else if (auto* img_ptr = dynamic_cast<vil_image_view<float>*>(img_sptr.ptr())) {
138 std::cout << " loaded image, ni: " << img_ptr->ni() << " " << img_ptr->nj() << " nplanes: " << img_ptr->nplanes()
139 << " with pixel format: " << img_ptr->pixel_format() << std::endl;
140 img_f = vil_plane(*img_ptr, n);
141 }else {
142 std::cout << "Error: " << pro.name() << " -- The image pixel format: " << img_sptr->pixel_format() << " is not supported!\n";
143 return false;
144 }
145
146 if (is_smooth)
147 std::cout << " gauss smooth is applied on the input image" << std::endl;
148
149 unsigned tni = tc_ptr->filter_responses().ni();
150 unsigned tnj = tc_ptr->filter_responses().nj();
151 if (tni != img_f.ni() || tnj != img_f.nj()) {
152 std::cout << "filter responses have ni: " << tni << " nj: " << tnj << "..";
153 std::cout << " input image has ni: " << img_f.ni() << " nj: " << img_f.nj() << "! resampling..\n";
154
155 vil_image_view<float> out_img(tni, tnj);
156 vil_resample_bilin(img_f, out_img, tni, tnj);
157 tc_ptr->add_gauss_response(out_img, folder, name, res_name, is_smooth);
158 } else
159 tc_ptr->add_gauss_response(img_f, folder, name, res_name, is_smooth);
160
161 return true;
162 }
163
164 //: this process extracts various bands from an input 4-band image and adds them as other layers to the filter_bank of the passed classifier
165 // practically increases the dimension of the textons
166 // the params of the classifier instance are used
sdet_add_to_filter_bank_process2_cons(bprb_func_process & pro)167 bool sdet_add_to_filter_bank_process2_cons(bprb_func_process& pro)
168 {
169 std::vector<std::string> input_types;
170 input_types.emplace_back("sdet_texture_classifier_sptr"); // classifier instance
171 input_types.emplace_back("vcl_string"); // input image name
172 input_types.emplace_back("vcl_string"); // filter bank folder
173 if (!pro.set_input_types(input_types))
174 return false;
175
176 std::vector<std::string> output_types;
177 return pro.set_output_types(output_types);
178 }
179
band_ops(vil_image_view<float> & band1,vil_image_view<float> & band2,vil_image_view<float> & ratio)180 void band_ops(vil_image_view<float>& band1, vil_image_view<float>& band2, vil_image_view<float>&ratio)
181 {
182 vil_image_view<float> dif(band1.ni(), band1.nj());
183 vil_image_view<float> sum(band1.ni(), band1.nj());
184
185 vil_math_image_difference(band1, band2, dif);
186 vil_math_image_sum(band1, band2, sum);
187 vil_math_image_ratio(dif, sum, ratio); // image values range in [-1,1]
188 // scale to -0.03,0.03 -- heuristic scale
189 vil_math_scale_and_offset_values(ratio, 0.03, 0.0); // map to [-0.03,0.03]
190 // scale to 0,0.03 -- heuristic scale
191 //vil_math_scale_and_offset_values(ratio, 1.0, 1.0); // map to [0,2]
192 //vil_math_scale_and_offset_values(ratio, 0.03/2.0, 0.0); // map to [0,0.03]
193 }
194
sdet_add_to_filter_bank_process2(bprb_func_process & pro)195 bool sdet_add_to_filter_bank_process2(bprb_func_process& pro)
196 {
197 if (!pro.verify_inputs())
198 {
199 std::cout << pro.name() << "sdet_extract_filter_bank_process inputs are not valid"<< std::endl;
200 return false;
201 }
202 // get inputs
203 sdet_texture_classifier_sptr tc_ptr = pro.get_input<sdet_texture_classifier_sptr>(0);
204 std::string name = pro.get_input<std::string>(1);
205 std::string folder = pro.get_input<std::string>(2);
206
207 vil_image_view_base_sptr img_sptr = vil_load(name.c_str());
208 if (img_sptr->nplanes() < 4) {
209 std::cerr << pro.name() << " input image does not have at least 4 bands!\n";
210 return false;
211 }
212
213 // assumes an input image in [0,1] range
214 vil_image_view<float> img_f(img_sptr);
215 std::cout << " loaded image, ni: " << img_sptr->ni() << " " << img_sptr->nj() << " nplanes: " << img_f.nplanes()
216 << " with pixel format: " << img_sptr->pixel_format() << std::endl;
217
218 unsigned tni = tc_ptr->filter_responses().ni();
219 unsigned tnj = tc_ptr->filter_responses().nj();
220 if (tni != img_f.ni() || tnj != img_f.nj()) {
221 std::cout << "filter responses have ni: " << tni << " nj: " << tnj << "..";
222 std::cout << " input image has ni: " << img_f.ni() << " nj: " << img_f.nj() << "! resampling..\n";
223
224 vil_image_view<float> out_img(tni, tnj, img_f.nplanes());
225 vil_resample_bilin(img_f, out_img, tni, tnj);
226
227 // now compute various channels
228 vil_image_view<float> band_b = vil_plane(out_img, 0);
229 vil_image_view<float> band_g = vil_plane(out_img, 1);
230 vil_image_view<float> band_r = vil_plane(out_img, 2);
231 vil_image_view<float> band_nir = vil_plane(out_img, 3);
232
233 vil_image_view<float> ratio(out_img.ni(), out_img.nj());
234
235 band_ops(band_nir, band_r, ratio);
236 tc_ptr->add_gauss_response(ratio, folder, name, "nir_r", false); // last argument = false --> do not gaussian smooth this image
237
238 band_ops(band_r, band_g, ratio);
239 tc_ptr->add_gauss_response(ratio, folder, name, "r_g", false); // last argument = false --> do not gaussian smooth this image
240
241 band_ops(band_r, band_b, ratio);
242 tc_ptr->add_gauss_response(ratio, folder, name, "r_b", false); // last argument = false --> do not gaussian smooth this image
243
244 band_ops(band_g, band_b, ratio);
245 tc_ptr->add_gauss_response(ratio, folder, name, "g_b", false); // last argument = false --> do not gaussian smooth this image
246
247 } else {
248
249 vil_image_view<float> band_b = vil_plane(img_f, 0);
250 vil_image_view<float> band_g = vil_plane(img_f, 1);
251 vil_image_view<float> band_r = vil_plane(img_f, 2);
252 vil_image_view<float> band_nir = vil_plane(img_f, 3);
253
254 vil_image_view<float> ratio(img_f.ni(), img_f.nj());
255
256 band_ops(band_nir, band_r, ratio);
257 tc_ptr->add_gauss_response(ratio, folder, name, "nir_r", false); // last argument = false --> do not gaussian smooth this image
258
259 band_ops(band_r, band_g, ratio);
260 tc_ptr->add_gauss_response(ratio, folder, name, "r_g", false); // last argument = false --> do not gaussian smooth this image
261
262 band_ops(band_r, band_b, ratio);
263 tc_ptr->add_gauss_response(ratio, folder, name, "r_b", false); // last argument = false --> do not gaussian smooth this image
264
265 band_ops(band_g, band_b, ratio);
266 tc_ptr->add_gauss_response(ratio, folder, name, "g_b", false); // last argument = false --> do not gaussian smooth this image
267
268 }
269
270 return true;
271 }
272
273 //: this process extracts a series of filter responses from the input image (assumed to be properly scaled to [0,1])
274 // and adds each response as another layer to the other_responses_ of the passed classifier
275 // practically increases the dimension of the textons
276 // the params of the classifier instance are used
sdet_add_responses_to_filter_bank_process_cons(bprb_func_process & pro)277 bool sdet_add_responses_to_filter_bank_process_cons(bprb_func_process& pro)
278 {
279 std::vector<std::string> input_types;
280 input_types.emplace_back("sdet_texture_classifier_sptr"); // classifier instance
281 input_types.emplace_back("vcl_string"); // input image name
282 input_types.emplace_back("vil_image_view_base_sptr"); // input image
283 input_types.emplace_back("vcl_string"); // filter bank folder
284 input_types.emplace_back("vcl_string"); // filter name : unique name to be used to write the response to filter folder (the id of the filter bank will be appended to this name)
285 if (!pro.set_input_types(input_types))
286 return false;
287
288 std::vector<std::string> output_types;
289 return pro.set_output_types(output_types);
290 }
291
sdet_add_responses_to_filter_bank_process(bprb_func_process & pro)292 bool sdet_add_responses_to_filter_bank_process(bprb_func_process& pro)
293 {
294 if (!pro.verify_inputs())
295 {
296 std::cout << pro.name() << "sdet_extract_filter_bank_process inputs are not valid"<< std::endl;
297 return false;
298 }
299 // get inputs
300 sdet_texture_classifier_sptr tc_ptr = pro.get_input<sdet_texture_classifier_sptr>(0);
301 std::string name = pro.get_input<std::string>(1);
302 vil_image_view_base_sptr img_sptr = pro.get_input<vil_image_view_base_sptr>(2);
303 std::string folder = pro.get_input<std::string>(3);
304 std::string res_name = pro.get_input<std::string>(4);
305
306 if (img_sptr->pixel_format() != VIL_PIXEL_FORMAT_FLOAT) {
307 std::cerr << " In sdet_add_responses_to_filter_bank_process(): the input image format is not FLOAT!.. it is assumed the input image is properly scaled to [0,1]!\n";
308 return false;
309 }
310
311 vil_image_view<float> img_f(img_sptr);
312 float min_value, max_value;
313 vil_math_value_range(img_f, min_value, max_value);
314 if (max_value > 1.0 || min_value < 0) {
315 std::cerr << " In sdet_add_responses_to_filter_bank_process(): the input image is NOT scaled to [0,1]!\n";
316 return false;
317 }
318
319 unsigned tni = tc_ptr->filter_responses().ni();
320 unsigned tnj = tc_ptr->filter_responses().nj();
321 if (tni != img_f.ni() || tnj != img_f.nj()) {
322 std::cout << "filter responses have ni: " << tni << " nj: " << tnj << "..";
323 std::cout << " input image has ni: " << img_f.ni() << " nj: " << img_f.nj() << "! resampling..\n";
324
325 vil_image_view<float> out_img(tni, tnj);
326 vil_resample_bilin(img_f, out_img, tni, tnj);
327 tc_ptr->add_filter_responses(out_img, folder, name, res_name);
328 } else
329 tc_ptr->add_filter_responses(img_f, folder, name, res_name);
330
331 return true;
332 }
333