1 // This is gel/vifa/vifa_parallel.cxx
2 #include <iostream>
3 #include <fstream>
4 #include "vifa_parallel.h"
5 //:
6 // \file
7 #include "vnl/vnl_math.h"
8 #include <vdgl/vdgl_digital_curve.h>
9 #include <vsol/vsol_curve_2d.h>
10 #include <vtol/vtol_edge_2d.h>
11 #include <vtol/vtol_vertex_2d.h>
12 #include <vtol/vtol_intensity_face.h>
13 #include "vifa_gaussian.h"
14
15 #ifdef DUMP
16 #include "vul/vul_sprintf.h"
17 #ifdef _MSC_VER
18 # include "vcl_msvc_warnings.h"
19 #endif
20
21 static int pass = 0;
22 #endif
23
24 constexpr float n_sigma = 2.0; // on either side of center
25
26
27 vifa_parallel::
vifa_parallel(iface_list & faces,bool,vifa_parallel_params * params)28 vifa_parallel(iface_list& faces,
29 bool /*contrast_weighted*/,
30 vifa_parallel_params* params) :
31 vifa_parallel_params(params)
32 {
33 raw_h_ = new vifa_histogram(nbuckets, min_angle, max_angle);
34 float range = max_angle - min_angle;
35
36 for (auto & face : faces)
37 {
38 edge_list edges; face->edges(edges);
39
40 for (auto & edge : edges)
41 {
42 vtol_edge_2d* e = edge->cast_to_edge_2d();
43
44 if (e)
45 {
46 #ifdef OLD_LINE_APPROX
47 const vtol_vertex_2d* v1 = e->v1()->cast_to_vertex_2d();
48 const vtol_vertex_2d* v2 = e->v2()->cast_to_vertex_2d();
49 double dy = v1->y() - v2->y();
50 double dx = v1->x() - v2->x();
51 double length = 0.0;
52
53 if (contrast_weighted)
54 {
55 vtol_intensity_face_sptr other_f = get_adjacent_iface(*ifi, e);
56
57 if (other_f)
58 length = std::sqrt((dx * dx) + (dy * dy))
59 * std::fabs((*ifi)->Io() - other_f->Io());
60 }
61
62 double orientation = std::atan2(dy, dx) * vnl_math::deg_per_rad;
63 if (orientation < 0)
64 orientation += 180.0;
65
66 float theta = map_x(float(orientation));
67 raw_h_->SetCount(theta, raw_h_->GetCount(theta) + float(length));
68 #else
69 vsol_curve_2d_sptr c = e->curve();
70
71 if (c)
72 {
73 vdgl_digital_curve* dc = c->cast_to_vdgl_digital_curve();
74
75 if (dc)
76 {
77 double l = dc->length();
78
79 for (int i = 0; i < l; i++)
80 {
81 // Use parametric index representation (0 -- 1)
82 double theta = dc->get_theta(i / l);
83 #ifdef DEBUG
84 std::cout << "raw theta: " << theta;
85 #endif
86 while (theta < min_angle)
87 theta += range;
88
89 while (theta > max_angle)
90 theta -= range;
91 #ifdef DEBUG
92 std::cout << " to " << theta << std::endl;
93 #endif
94 raw_h_->UpCount(float(theta));
95 }
96 }
97 }
98 #endif // OLD_LINE_APPROX
99 }
100 }
101 }
102
103 norm_h_ = vifa_parallel::normalize_histogram(raw_h_);
104 }
105
106
107 vifa_parallel::
vifa_parallel(std::vector<float> & pixel_orientations,vifa_parallel_params * params)108 vifa_parallel(std::vector<float>& pixel_orientations,
109 vifa_parallel_params* params) :
110 vifa_parallel_params(params)
111 {
112 raw_h_ = new vifa_histogram(nbuckets, min_angle, max_angle);
113 float range = max_angle - min_angle;
114
115 for (float theta : pixel_orientations)
116 {
117 while (theta < min_angle)
118 {
119 theta += range;
120 }
121 while (theta > max_angle)
122 {
123 theta -= range;
124 }
125
126 raw_h_->UpCount(theta);
127 }
128
129 norm_h_ = vifa_parallel::normalize_histogram(raw_h_);
130 }
131
132 vifa_parallel::
vifa_parallel(float center_angle,float std_dev)133 vifa_parallel(float center_angle,
134 float std_dev)
135 {
136 raw_h_ = new vifa_histogram(nbuckets, min_angle, max_angle);
137
138 #ifdef DEBUG
139 std::cout << "vifa_parallel(): 0.5 is "<< raw_h_->GetValIndex(0.5) << std::endl;
140 #endif
141
142 vifa_gaussian g(center_angle, std_dev);
143 for (float i = min_angle; i < 2 * max_angle; i++)
144 {
145 float v = g.pdf(i);
146 float vx = map_x(i);
147
148 raw_h_->SetCount(vx, raw_h_->GetCount(vx) + v);
149 }
150
151 norm_h_ = vifa_parallel::normalize_histogram(raw_h_);
152 }
153
~vifa_parallel()154 vifa_parallel::~vifa_parallel()
155 {
156 delete raw_h_;
157 delete norm_h_;
158 }
159
reset()160 void vifa_parallel::reset() {
161 delete norm_h_;
162 norm_h_ = normalize_histogram(raw_h_);
163 }
164
get_raw_hist()165 vifa_histogram *vifa_parallel::get_raw_hist() { return raw_h_; }
166
get_norm_hist()167 vifa_histogram *vifa_parallel::get_norm_hist() { return norm_h_; }
168
169 void vifa_parallel::
map_gaussian(float & max_angle,float & std_dev,float & scale)170 map_gaussian(float& max_angle,
171 float& std_dev,
172 float& scale)
173 {
174 bool set_min_res_flag = true;
175
176 constexpr float incr = 3.0; // put me in the params!
177 float max_value;
178 float local_max_angle = find_peak(max_value);
179 max_angle = 0.0;
180 std_dev = 0.0;
181 scale = 0.0;
182
183 // Skip histograms that are empty
184 if (local_max_angle != -1.0)
185 {
186 float min_residual = 0.f; // dummy initialisation
187
188 for (float j=-(n_sigma+1); j<=(n_sigma+1); j++)
189 {
190 float new_center = map_x(local_max_angle + (j * incr));
191 float local_std_dev = 0.0; // degrees
192
193 for (int i = 0; i < 5; i++)
194 {
195 local_std_dev += incr;
196 vifa_gaussian g(new_center, local_std_dev);
197 float g_max = g.pdf(new_center);
198 float local_scale = norm_h_->GetCount(new_center) /
199 g_max;
200 // NOTE: local_scale could be zero if the histogram is 0 here...
201
202 #ifdef DUMP
203 char buf[25];
204 vul_sprintf(buf, "gauss-%d-%d-%d.dat", pass, (int)j, i);
205 std::ofstream gdump(buf);
206 #endif
207 // int sample_count = 0;
208 float sample_sum = 0.0;
209
210 for (float dx = (-n_sigma * local_std_dev);
211 dx <= (n_sigma * local_std_dev);
212 dx += norm_h_->GetBucketSize())
213 {
214 float vx = new_center + dx;
215 float e = g.pdf(vx) * local_scale;
216 // e could be zero because of local_scale, see above
217 float x = map_x(vx);
218 float f = norm_h_->GetCount(x);
219 if (f < 0)
220 {
221 f = 0;
222 }
223
224 float diff = std::fabs(f - e);
225
226 #ifdef DUMP
227 gdump << x << ' ' << e << ' ' << diff << ' ' << vx << ' ' << f << std::endl;
228 #endif
229 if (e != 0.0)
230 {
231 sample_sum += ((diff * diff) / e);
232 // sample_count++;
233 }
234 }
235
236 // Set min_residual the first time thru
237 if ((set_min_res_flag || sample_sum < min_residual) && sample_sum != 0)
238 {
239 set_min_res_flag = false;
240 min_residual = sample_sum;
241 std_dev = local_std_dev;
242 max_angle = new_center;
243 scale = local_scale;
244
245 #ifdef DEBUG
246 std::cout << "*** ";
247 #endif
248 }
249
250 #ifdef DEBUG
251 std::cout << j << " gaussian " << i << " residual "
252 << sample_sum << " sample count " << sample_count << std::endl;
253 #endif
254 }
255 }
256
257 #ifdef DEBUG
258 std::cout << "best is at " << max_angle << " sd of " << std_dev
259 << " scale " << scale << std::endl;
260 #endif
261
262 #ifdef DUMP
263 pass++;
264 #endif
265 }
266 }
267
268 void vifa_parallel::
remove_gaussian(float max_angle,float std_dev,float scale)269 remove_gaussian(float max_angle,
270 float std_dev,
271 float scale)
272 {
273 // Skip if histogram is empty
274 if (norm_h_->GetMaxCount() != 0.0)
275 {
276 vifa_gaussian g(max_angle, std_dev);
277 for (float dx = (-n_sigma * std_dev);
278 dx <= (n_sigma * std_dev);
279 dx += norm_h_->GetBucketSize())
280 {
281 float vx = max_angle + dx;
282 float e = g.pdf(vx) * scale;
283 float x = map_x(vx);
284 float f = norm_h_->GetCount(x);
285
286 if (f >= 0)
287 {
288 float new_val = ((f - e) < 0) ? 0 : (f - e);
289
290 #ifdef DEBUG
291 std::cout << " --- " << x << ": " << f <<" to " << new_val << std::endl;
292 #endif
293
294 norm_h_->SetCount(x, new_val);
295 }
296 else
297 {
298 std::cerr << " --- " << x << ": bad " <<
299 norm_h_->GetValIndex(x) << std::endl;
300 }
301 }
302 }
303 }
304
305 void vifa_parallel::
snapshot(char * fname)306 snapshot(char* fname)
307 {
308 norm_h_->WritePlot(fname);
309 }
310
area()311 float vifa_parallel::area() {
312 if (norm_h_->GetMaxCount() == 0.0)
313 {
314 // Return 0 area for empty histograms
315 return 0.0;
316 }
317 else
318 {
319 return norm_h_->ComputeArea();
320 }
321 }
322
bin_variance()323 float vifa_parallel::bin_variance() {
324 float* counts = norm_h_->GetCounts();
325 int res = norm_h_->GetRes();
326 float sum = 0;
327 float sum2 = 0;
328
329 for (int i = 0; i < res; i++)
330 {
331 sum += counts[i];
332 sum2 += (counts[i] * counts[i]);
333 }
334
335 float mean = sum / res;
336 float var = (sum2 / res) - (mean * mean);
337
338 return var;
339 }
340
341 float vifa_parallel::
map_x(float raw_x)342 map_x(float raw_x)
343 {
344 float range = max_angle - min_angle + 1;
345
346 while (raw_x < min_angle)
347 {
348 raw_x += range;
349 }
350 while (raw_x > max_angle)
351 {
352 raw_x -= range;
353 }
354
355 return raw_x;
356 }
357
358 vifa_histogram* vifa_parallel::
normalize_histogram(vifa_histogram * h)359 normalize_histogram(vifa_histogram* h)
360 {
361 auto* norm = new vifa_histogram(nbuckets, min_angle, max_angle);
362 int nbuckets = h->GetRes();
363 float area = h->ComputeArea();
364 float* x_vals = h->GetVals();
365 float* y_vals = h->GetCounts();
366
367 for (int i = 0; i < nbuckets; i++)
368 {
369 float new_area = y_vals[i] / area;
370 norm->SetCount(x_vals[i], new_area);
371 }
372
373 return norm;
374 }
375
376 float vifa_parallel::
find_peak(float & max_value)377 find_peak(float& max_value)
378 {
379 int nbuckets = norm_h_->GetRes();
380 float* x_vals = norm_h_->GetVals();
381 float* y_vals = norm_h_->GetCounts();
382 int max_index = -1;
383 max_value = -1;
384
385 for (int i = 0; i < nbuckets; i++)
386 {
387 if (y_vals[i] > max_value)
388 {
389 max_index = i;
390 max_value = y_vals[i];
391 }
392 }
393
394 if (max_index == -1)
395 {
396 return -1;
397 }
398
399 max_value = y_vals[max_index];
400 return x_vals[max_index];
401 }
402
403 vtol_intensity_face_sptr vifa_parallel::
get_adjacent_iface(const vtol_intensity_face_sptr & known_face,vtol_edge_2d * e)404 get_adjacent_iface(const vtol_intensity_face_sptr& known_face,
405 vtol_edge_2d* e)
406 {
407 vtol_intensity_face_sptr adj_face = nullptr;
408 face_list faces; e->faces(faces);
409
410 // Expect only two intensity faces for 2-D case
411 if (faces.size() == 2)
412 {
413 vtol_intensity_face* f1 = faces[0]->cast_to_intensity_face();
414 vtol_intensity_face* f2 = faces[1]->cast_to_intensity_face();
415
416 if (f1 && f2)
417 {
418 if (*known_face == *f1)
419 {
420 adj_face = f2;
421 }
422 else if (*known_face == *f2)
423 {
424 adj_face = f1;
425 }
426 else
427 {
428 // Known face does not contain the
429 // given edge -- leave result NULL
430 }
431 }
432 }
433 return adj_face;
434 }
435