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