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