1 // This is gel/vifa/vifa_int_faces_adj_attr.cxx
2 #include "vifa_int_faces_adj_attr.h"
3
vifa_int_faces_adj_attr()4 vifa_int_faces_adj_attr::vifa_int_faces_adj_attr()
5 : vifa_int_faces_attr(), seed_(nullptr), seed_attr_(nullptr) {
6 init();
7 ComputeAttributes();
8 }
9
10 vifa_int_faces_adj_attr::
vifa_int_faces_adj_attr(const vtol_intensity_face_sptr & seed,int depth,int size_filter,vdgl_fit_lines_params * fitter_params,vifa_group_pgram_params * gpp_s,vifa_group_pgram_params * gpp_w,vifa_coll_lines_params * cpp,vifa_norm_params * np,vifa_int_face_attr_factory * factory,float junk_area_percentage)11 vifa_int_faces_adj_attr(const vtol_intensity_face_sptr& seed,
12 int depth,
13 int size_filter,
14 vdgl_fit_lines_params* fitter_params,
15 vifa_group_pgram_params* gpp_s,
16 vifa_group_pgram_params* gpp_w,
17 vifa_coll_lines_params* cpp,
18 vifa_norm_params* np,
19 vifa_int_face_attr_factory* factory,
20 float junk_area_percentage)
21 : vifa_int_faces_attr(fitter_params, gpp_s, gpp_w, cpp, np, factory),
22 closure_valid_(false),
23 seed_(seed),
24 seed_attr_(nullptr),
25 depth_(depth),
26 size_filter_(size_filter),
27 junk_area_percentage_(junk_area_percentage),
28 junk_count_(0)
29 {
30 init();
31 ComputeAttributes();
32 }
33
34 vifa_int_faces_adj_attr::
vifa_int_faces_adj_attr(const vtol_intensity_face_sptr & seed,int depth,iface_list & neighborhood,int size_filter,vdgl_fit_lines_params * fitter_params,vifa_group_pgram_params * gpp_s,vifa_group_pgram_params * gpp_w,vifa_coll_lines_params * cpp,vifa_norm_params * np,vifa_int_face_attr_factory * factory,float junk_area_percentage)35 vifa_int_faces_adj_attr(const vtol_intensity_face_sptr& seed,
36 int depth,
37 iface_list& neighborhood,
38 int size_filter,
39 vdgl_fit_lines_params* fitter_params,
40 vifa_group_pgram_params* gpp_s,
41 vifa_group_pgram_params* gpp_w,
42 vifa_coll_lines_params* cpp,
43 vifa_norm_params* np,
44 vifa_int_face_attr_factory* factory,
45 float junk_area_percentage)
46 : vifa_int_faces_attr(neighborhood, fitter_params, gpp_s, gpp_w, cpp, np, factory),
47 closure_valid_(false), // still need to filter on size!
48 seed_(seed),
49 seed_attr_(nullptr),
50 depth_(depth),
51 size_filter_(size_filter),
52 junk_area_percentage_(junk_area_percentage),
53 junk_count_(0)
54 {
55 init();
56 ComputeAttributes();
57 }
58
59 void vifa_int_faces_adj_attr::
SetSeed(const vtol_intensity_face_sptr & seed)60 SetSeed(const vtol_intensity_face_sptr& seed)
61 {
62 seed_ = seed;
63 closure_valid_ = false;
64 seed_attr_ = factory_new_attr(seed_);
65 }
66
67 iface_list& vifa_int_faces_adj_attr::
GetFaces()68 GetFaces()
69 {
70 if (!closure_valid_)
71 {
72 faces_.clear();
73 this->compute_closure();
74 }
75
76 return faces_;
77 }
78
79 // Caller must delete returned list when finished
80 iface_list* vifa_int_faces_adj_attr::
GetFaceList()81 GetFaceList()
82 {
83 if (!closure_valid_)
84 {
85 faces_.clear();
86 this->compute_closure();
87 }
88
89 auto* v = new iface_list;
90 for (auto & face : faces_)
91 {
92 v->push_back(face);
93 }
94
95 return v;
96 }
97
98 bool vifa_int_faces_adj_attr::
ComputeAttributes()99 ComputeAttributes()
100 {
101 if (!closure_valid_)
102 this->compute_closure();
103
104 if (vifa_int_faces_attr::ComputeAttributes())
105 {
106 // Seed is not included in faces_ or attribute histograms
107 seed_attr_ = factory_new_attr(seed_);
108 vifa_int_face_attr* seed_attr_ptr = seed_attr_.ptr();
109
110 // Compute ratio of seed to neighbors for each hist attribute
111 for (int i = 0; i < this->NumHistAttributes(); i++)
112 {
113 float seed_val = (seed_attr_ptr->*(attr_get_funcs[i]))();
114
115 // Instead of x/y, compute (x+1)/(y+1) since y may be near zero
116
117 float hist_mean = GetMeanAttr(i);
118 if (hist_mean < attr_min_vals[i])
119 hist_mean = attr_min_vals[i];
120 mean_ratios_[i] = (seed_val + 1) / (hist_mean + 1);
121
122 float hist_min = GetMinAttr(i);
123 if (hist_min < attr_min_vals[i])
124 hist_min = attr_min_vals[i];
125 min_ratios_[i] = (seed_val + 1) / (hist_min + 1);
126 }
127
128 attributes_valid_ = true;
129 }
130
131 return valid_p();
132 }
133
134 int vifa_int_faces_adj_attr::
NeighborhoodSize()135 NeighborhoodSize()
136 {
137 compute_closure();
138 return faces_.size();
139 }
140
141 // Populate a vector containing all attributes, including inherited ones.
142 bool vifa_int_faces_adj_attr::
GetAttributes(std::vector<float> & attrs)143 GetAttributes(std::vector<float>& attrs)
144 {
145 if (vifa_int_faces_attr::GetAttributes(attrs))
146 return this->vifa_int_faces_adj_attr::GetNativeAttributes(attrs);
147 else
148 return false;
149 }
150
151 // Append the attribute names to a vector in the same order as
152 // GetAttributes. KEEP IN SYNC WITH GetAttributes!!!
153 void vifa_int_faces_adj_attr::
GetAttributeNames(std::vector<std::string> & names)154 GetAttributeNames(std::vector<std::string>& names)
155 {
156 vifa_int_faces_attr::GetAttributeNames(names);
157
158 for (int i = 0; i < NUM_HIST_ATTRIBUTES; i++)
159 {
160 std::string name(attr_names[i]);
161 names.push_back("ratio" + name);
162 }
163
164 for (int i = 0; i < NUM_HIST_ATTRIBUTES; i++)
165 {
166 std::string name(attr_names[i]);
167 names.push_back("minRatio" + name);
168 }
169 }
170
171 // Populate a vector containing attributes native to this class (not
172 // inherited). KEEP IN SYNC WITH GETNAMES ABOVE!
173 // Assumes that
174 bool vifa_int_faces_adj_attr::
GetNativeAttributes(std::vector<float> & attrs)175 GetNativeAttributes(std::vector<float>& attrs)
176 {
177 if (!this->ComputeAttributes())
178 {
179 std::cerr << "Couldn't compute group adj attributes?\n";
180 return false;
181 }
182
183 for (int i = 0; i < this->NumHistAttributes(); i++)
184 {
185 attrs.push_back(this->GetRatioAttr(i));
186 }
187
188 for (int i = 0; i < this->NumHistAttributes(); i++)
189 {
190 attrs.push_back(this->GetMinRatioAttr(i));
191 }
192
193 // what about Collinearity()???
194
195 return true;
196 }
197
198 bool vifa_int_faces_adj_attr::
compute_closure()199 compute_closure()
200 {
201 // std::cout << " In ifsaa::compute_closure()...\n";
202
203 if (!closure_valid_)
204 {
205 if (faces_.empty())
206 {
207 // std::cout << "faces_ is empty -- rebuilding\n";
208
209 if ((seed_) && (depth_ != BAD_DEPTH))
210 {
211 // Temporarily add the seed to the list (front), preventing the
212 // neighborhood construction from adding it back accidentally.
213 faces_.push_back(seed_);
214
215 // Build the neighborhood (recursively)
216 this->compute_closure_step(0, seed_);
217
218 // Remove the seed, leaving the true neighborhood
219 faces_.erase(faces_.begin());
220 }
221 }
222
223 // std::cout << faces_.size() << " face(s)" << endl;
224
225 float original_area = 0;
226 float junk_area = 0;
227 int original_nbrhood_size = faces_.size();
228 float area_threshold = (seed_->Npix() * junk_area_percentage_);
229 iface_list keep_faces;
230 for (auto & face : faces_)
231 {
232 original_area += face->Npix();
233
234 if (face->Npix() >= area_threshold)
235 keep_faces.push_back(face);
236 else
237 {
238 junk_count_++;
239 junk_area += face->Npix();
240 }
241 }
242
243 // std::cout << keep_faces.size() << " keep_face(s)" << endl;
244
245 faces_ = keep_faces;
246 junk_percent_ = (float)junk_count_ / original_nbrhood_size;
247 junk_area_ratio_ = junk_area / original_area;
248 closure_valid_ = true;
249 }
250
251 #if 0
252 std::cout << "Final faces_: " << faces_.size() << std::endl;
253
254 for (iface_iterator f = faces_.begin(); f != faces_.end(); ++f)
255 std::cout << " (" << (*f)->Xo() << ", " << (*f)->Yo() << "), "
256 << (*f)->Npix() << " pixels\n";
257 #endif
258
259 // std::cout << "Leaving ifsaa::compute_closure()\n";
260
261 return closure_valid_;
262 }
263
264 float vifa_int_faces_adj_attr::
Collinearity()265 Collinearity()
266 {
267 compute_closure();
268 get_collinear_lines();
269
270 float u_len = 0.0f;
271 float w_len = 0.0f;
272 float coll = 0.0f;
273 edge_list edges; seed_->edges(edges);
274
275 for (auto & edge : edges)
276 {
277 vtol_edge_2d* e = edge->cast_to_edge_2d();
278
279 if (e)
280 {
281 vifa_coll_lines_sptr clr = get_line_along_edge(e);
282
283 if (clr)
284 {
285 u_len += float(e->curve()->length());
286 w_len += float(clr->spanning_length());
287 }
288 }
289 }
290
291 if (u_len > 0.0f)
292 coll = w_len / u_len;
293
294 return coll;
295 }
296
297 // Get the ratio of a vifa_int_face_attr attribute to the seed.
298 float vifa_int_faces_adj_attr::
GetRatioAttr(int attr_index)299 GetRatioAttr(int attr_index)
300 {
301 return mean_ratios_[attr_index];
302 }
303
304 // Get the ratio of the seed's vifa_int_face_attr to the minimum neighbor
305 float vifa_int_faces_adj_attr::
GetMinRatioAttr(int attr_index)306 GetMinRatioAttr(int attr_index)
307 {
308 return min_ratios_[attr_index];
309 }
310
311 void vifa_int_faces_adj_attr::
init()312 init()
313 {
314 junk_percent_ = 0.0f;
315 junk_area_ratio_ = 0.0f;
316
317 int n = NumHistAttributes();
318 mean_ratios_.reserve(n);
319 min_ratios_.reserve(n);
320
321 // initialize to -1.
322 for (int i = 0; i < n; i++)
323 mean_ratios_[i] = min_ratios_[i] = -1;
324 }
325
326 bool vifa_int_faces_adj_attr::
add_unique_face(iface_list & facelist,const vtol_intensity_face_sptr & face,int size_filter)327 add_unique_face(iface_list& facelist,
328 const vtol_intensity_face_sptr& face,
329 int size_filter)
330 {
331 for (auto & check : facelist)
332 {
333 if ((check.ptr()->Xo() == face->Xo()) &&
334 (check.ptr()->Yo() == face->Yo()))
335 return false;
336 }
337
338 if (face->Npix() >= size_filter)
339 {
340 facelist.push_back(face);
341 return true;
342 }
343
344 return false;
345 }
346
347 void vifa_int_faces_adj_attr::
compute_closure_step(int current_depth,vtol_intensity_face_sptr seed)348 compute_closure_step(int current_depth,
349 vtol_intensity_face_sptr seed)
350 {
351 #ifdef CCS_DEBUG
352 std::cout << "ccs: depth " << current_depth << " of " << depth_;
353
354 if (seed)
355 std::cout << " at seed " << seed->Xo() << ", " << seed->Yo();
356 else
357 std::cout << " with null seed";
358 #endif
359
360 if ((current_depth >= depth_) || (!seed))
361 {
362 #ifdef CCS_DEBUG
363 std::cout << "...bailing\n";
364 #endif
365 return;
366 }
367 #ifdef CCS_DEBUG
368 else
369 std::cout << std::endl;
370 #endif
371
372 // Get all the faces adjacent to the seed face
373 iface_list* adj_faces = get_adjacent_faces(seed);
374 if (adj_faces)
375 {
376 // For each adjacent face...
377 auto fi = adj_faces->begin();
378 for (; fi != adj_faces->end(); fi++)
379 {
380 vtol_intensity_face_sptr adj_face_sptr = (*fi);
381
382 // Try to add the adjacent face to the master face list
383 if (this->add_unique_face(faces_, adj_face_sptr, size_filter_))
384 {
385 // It's a new face, so recursively find its neighbors
386 this->compute_closure_step(current_depth + 1, adj_face_sptr);
387 }
388 }
389
390 delete adj_faces;
391 }
392 else
393 std::cerr << "vifsaa::compute_closure_step(): No adj. faces found!\n";
394 }
395
396 vtol_intensity_face_sptr vifa_int_faces_adj_attr::
get_adjacent_face_at_edge(vtol_intensity_face_sptr & known_face,vtol_edge_2d * e)397 get_adjacent_face_at_edge(vtol_intensity_face_sptr& known_face,
398 vtol_edge_2d* e)
399 {
400 vtol_intensity_face_sptr adj_face = nullptr;
401 face_list faces; e->faces(faces);
402
403 // Expect only one or two intensity faces for 2-D case
404 if (faces.size() == 2)
405 {
406 vtol_intensity_face* f1 = faces[0]->cast_to_intensity_face();
407 vtol_intensity_face* f2 = faces[1]->cast_to_intensity_face();
408
409 if (f1 && f2 && *known_face == *f1)
410 adj_face = f2;
411 else if (f1 && f2 && *known_face == *f2)
412 adj_face = f1;
413 else
414 {
415 // Known face does not contain the
416 // given edge -- leave result NULL
417 }
418 }
419
420 return adj_face;
421 }
422
423 iface_list* vifa_int_faces_adj_attr::
get_adjacent_faces(vtol_intensity_face_sptr & known_face)424 get_adjacent_faces(vtol_intensity_face_sptr& known_face)
425 {
426 iface_list* faces = nullptr;
427
428 if (known_face.ptr())
429 {
430 edge_list edges; known_face->edges(edges);
431 faces = new iface_list;
432
433 for (auto & edge : edges)
434 {
435 vtol_edge_2d* e = edge->cast_to_edge_2d();
436 if (e)
437 {
438 vtol_intensity_face_sptr other_f =
439 this->get_adjacent_face_at_edge(known_face, e);
440
441 if (other_f.ptr())
442 this->add_unique_face(*faces, other_f, 0);
443 }
444 }
445 }
446
447 return faces;
448 }
449