1 // This is gel/vifa/vifa_group_pgram.cxx
2 #include <iostream>
3 #include <cmath>
4 #include "vifa_group_pgram.h"
5 //:
6 // \file
7
8 #ifdef _MSC_VER
9 # include "vcl_msvc_warnings.h"
10 #endif
11 #include "vnl/vnl_math.h"
12 #include "vgl/vgl_point_2d.h"
13 #include "vgl/vgl_vector_2d.h"
14 #include "vgl/vgl_clip.h"
15
16 #ifndef DEGTORAD
17 #define DEGTORAD (vnl_math::pi_over_180)
18 #endif
19
20
21 vifa_group_pgram::
vifa_group_pgram(imp_line_list & lg,const vifa_group_pgram_params & old_params,double angle_range)22 vifa_group_pgram(imp_line_list& lg,
23 const vifa_group_pgram_params& old_params,
24 double angle_range)
25 : vifa_group_pgram_params(old_params)
26 {
27 angle_range_ = angle_range;
28 th_dim_ = (int)std::ceil(angle_range_/angle_increment());
29 th_dim_++; //Include both 0 and angle_range_
30 bb_ = new vifa_bbox;
31
32 for (int i = 0; i < th_dim_; i++)
33 {
34 auto* illp = new imp_line_list;
35 curves_.push_back(illp);
36 }
37 this->Index(lg);
38 }
39
40 //------------------------------------------------------------
41 //: Destructor
42 vifa_group_pgram::
~vifa_group_pgram()43 ~vifa_group_pgram()
44 {
45 for (auto illp : curves_)
46 {
47 for (auto & ili : *illp)
48 {
49 ili = nullptr;
50 }
51
52 delete illp;
53 }
54 }
55
56 //-----------------------------------------------------
57 //: Add an ImplicitLine to the index
58 void vifa_group_pgram::
Index(const imp_line_sptr & il)59 Index(const imp_line_sptr& il)
60 {
61 int ang_bin = this->AngleLoc(il);
62 curves_[ang_bin]->push_back(il);
63
64 this->touch();
65 }
66
67 //------------------------------------------------------------
68 //: Add a set of ImplicitLines to the angular index
69 void vifa_group_pgram::
Index(imp_line_list & lg)70 Index(imp_line_list& lg)
71 {
72 for (auto & ili : lg)
73 Index(ili);
74 }
75
76 //------------------------------------------------------------
77 //: Clear all lines from the index
78 void vifa_group_pgram::
Clear()79 Clear()
80 {
81 for (auto & curve : curves_)
82 {
83 imp_line_list* illp = curve;
84 for (auto & ili : *illp)
85 ili = nullptr;
86
87 delete illp;
88 curve = new imp_line_list;
89 }
90
91 this->touch();
92 }
93
94 //-----------------------------------------------------------------
95 //: Compute a histogram of parallel line coverage
96 //
GetCoverageHist()97 vifa_histogram_sptr vifa_group_pgram::GetCoverageHist() {
98 vifa_histogram_sptr h = new vifa_histogram(th_dim_, 0.0f, float(angle_range_));
99
100 float* cnts = h->GetCounts();
101 for (int i = 0; i < th_dim_; i++)
102 cnts[i] = float(this->LineCoverage(i));
103 return h;
104 }
105
106 //--------------------------------------------------------------
107 //: Get a populated line coverage corresponding to a given angle bin
108 //
109 vifa_line_cover_sptr vifa_group_pgram::
GetLineCover(int angle_bin)110 GetLineCover(int angle_bin)
111 {
112 imp_line_sptr il = this->LineAtAngle(angle_bin);
113
114 // Get all the lines which are within +- angular resolution of angle_bin.
115 imp_line_list lg;
116 this->CollectAdjacentLines(angle_bin, lg);
117
118 if (lg.empty()) {
119 return nullptr;
120 }
121
122 // Construct a bounding box from the ROI and clip
123 // the line defined by angle_bin
124 double bx;
125 double by;
126 double ex;
127 double ey;
128 this->CheckUpdateBoundingBox();
129 if (!vgl_clip_line_to_box(il->a(), il->b(), il->c(),
130 bb_->min_x(), bb_->min_y(),
131 bb_->max_x(), bb_->max_y(),
132 bx, by, ex, ey))
133 {
134 std::cerr << "In vifa_group_pgram::GetLineCover(): No intersection found\n";
135 return nullptr;
136 }
137
138 // Here we set the clipping bounds.
139 vgl_point_2d<double> b(bx, by);
140 vgl_point_2d<double> e(ex, ey);
141 il->set_points(b, e);
142
143 // The line is cut into 1 pixel bins
144 int len = int(il->length());
145 if (!len)
146 {
147 return nullptr;
148 }
149
150 vifa_line_cover_sptr cov = new vifa_line_cover(il, len);
151 for (auto & ili : lg)
152 {
153 cov->InsertLine(ili);
154 }
155
156 return cov;
157 }
158
159 //--------------------------------------------------------------
160 //: Compute parallel line overlap on a line at the same orientation with midpoint at the center of the region of the line group.
161 //
162 double vifa_group_pgram::
LineCoverage(int angle_bin)163 LineCoverage(int angle_bin)
164 {
165 vifa_line_cover_sptr lc = this->GetLineCover(angle_bin);
166 return lc ? lc->GetCoverage() : 0.0;
167 }
168
169 //--------------------------------------------------------------
170 //: Collect implicit line(s) from the angle array at orientations +- the given bin orientation.
171 // Wrap around the end of the array so that 0 degrees and 180 degrees are considered parallel.
172 void vifa_group_pgram::
CollectAdjacentLines(int angle_bin,imp_line_list & lg)173 CollectAdjacentLines(int angle_bin,
174 imp_line_list& lg)
175 {
176 if (angle_bin >= 0 && angle_bin < th_dim_)
177 {
178 if (angle_bin == 0)
179 {
180 // Case I - At the beginning of the array
181 lg.insert(lg.end(), curves_[th_dim_ - 1]->begin(),
182 curves_[th_dim_ - 1]->end());
183 lg.insert(lg.end(), curves_[0]->begin(),
184 curves_[0]->end());
185 lg.insert(lg.end(), curves_[1]->begin(),
186 curves_[1]->end());
187 }
188 else if (angle_bin == th_dim_ - 1)
189 {
190 // Case II - At the end of the array
191 lg.insert(lg.end(), curves_[th_dim_ - 2]->begin(),
192 curves_[th_dim_ - 2]->end());
193 lg.insert(lg.end(), curves_[th_dim_ - 1]->begin(),
194 curves_[th_dim_ - 1]->end());
195 lg.insert(lg.end(), curves_[0]->begin(),
196 curves_[0]->end());
197 }
198 else
199 {
200 // Case III - not near ends of the array
201 lg.insert(lg.end(), curves_[angle_bin - 1]->begin(),
202 curves_[angle_bin - 1]->end());
203 lg.insert(lg.end(), curves_[angle_bin]->begin(),
204 curves_[angle_bin]->end());
205 lg.insert(lg.end(), curves_[angle_bin + 1]->begin(),
206 curves_[angle_bin + 1]->end());
207 }
208 }
209 else
210 std::cerr << "vifa_group_pgram::CollectAdjacentLines(): bad angle_bin\n";
211 }
212
213 //------------------------------------------------------------------
214 //: Get Total length of parallel lines adjacent and including a bin
215 //
216 double vifa_group_pgram::
GetAdjacentPerimeter(int bin)217 GetAdjacentPerimeter(int bin)
218 {
219 imp_line_list lg;
220 this->CollectAdjacentLines(bin, lg);
221
222 double sum = 0;
223 for (auto & ili : lg)
224 {
225 vgl_vector_2d<double> v = ili->point2() - ili->point1();
226 sum += v.length();
227 }
228
229 return sum;
230 }
231
232 //------------------------------------------------------
233 //: Compute the total length of parallel lines normalized by the total edge perimeter
norm_parallel_line_length()234 double vifa_group_pgram::norm_parallel_line_length() {
235 this->ComputeDominantDirs();
236 if (dominant_dirs_.empty()) {
237 // No basis
238 return 0.0;
239 }
240
241 double max_cover = 0.0;
242 int max_dir = 0;
243 auto iit = dominant_dirs_.begin();
244 for (; iit != dominant_dirs_.end(); iit++)
245 {
246 int dir = (*iit);
247 vifa_line_cover_sptr lc = this->GetLineCover(dir);
248 if (!(lc.ptr()))
249 {
250 // std::cout << "vgg::norm_parallel_line_length(): "
251 // << "No line cover found for dir " << dir << std::endl;
252
253 // Is this right? What about other dominant directions?
254 // return 0.0;
255 continue;
256 }
257
258 double cov = lc->GetCoverage();
259
260 if (cov > max_cover)
261 {
262 max_cover = cov;
263 max_dir = dir;
264 }
265 }
266
267 double per = this->GetAdjacentPerimeter(max_dir);
268
269 // std::cout << "vgg::norm_parallel_line_length(): per = " << per
270 // << ", tmp1_ = " << tmp1_ << std::endl;
271
272 return 1.5 * per / tmp1_;
273 }
274
275 //---------------------------------------------------------
276 //: Find the angle bin corresponding to an implicit_line
277 int vifa_group_pgram::
AngleLoc(const imp_line_sptr & il)278 AngleLoc(const imp_line_sptr& il)
279 {
280 // Compute angle index
281 double angle = std::fmod(il->slope_degrees(), 180.0);
282 if (angle < 0.0)
283 angle += 180.0;
284
285 if (angle > angle_range_)
286 {
287 std::cerr << "In vifa_group_pgram::AngleLoc(): angle " << angle
288 << " was outside the angle range " << angle_range_ << std::endl;
289 return 0;
290 }
291
292 return (int)(std::floor(angle / angle_increment()));
293 }
294
295 //--------------------------------------------------------------
296 //: Define a line passing through the center of the Hough ROI and at an angle corresponding to the angle bin
297 imp_line_sptr vifa_group_pgram::
LineAtAngle(int angle_bin)298 LineAtAngle(int angle_bin)
299 {
300 // Get the new line's direction unit vector
301 double ang_rad = DEGTORAD * angle_bin * angle_increment();
302 vgl_vector_2d<double> d(std::cos(ang_rad), std::sin(ang_rad));
303
304 // Get the new line's midpoint (bounding box centroid)
305 this->CheckUpdateBoundingBox();
306 vgl_point_2d<double> m = bb_->centroid();
307
308 // Return a new line
309 imp_line_sptr il = new imp_line(d, m);
310 return il;
311 }
312
313 //------------------------------------------------------
314 //: Compute the bounding box of the current index
315 //
ComputeBoundingBox()316 void vifa_group_pgram::ComputeBoundingBox() {
317 // Reset the bounding box
318 bb_->empty();
319
320 for (auto illp : curves_)
321 {
322 for (auto & ili : *illp)
323 {
324 const imp_line_sptr& il = ili;
325
326 bb_->add(il->point1());
327 bb_->add(il->point2());
328 }
329 }
330
331 // Update the bounding box timestamp
332 bb_->touch();
333 }
334
335 //---------------------------------------------------------
336 //: Compute the dominant directions using the coverage histogram.
337 // A dominant direction is a local maximum in the coverage distribution.
338 //
ComputeDominantDirs()339 void vifa_group_pgram::ComputeDominantDirs() {
340 dominant_dirs_.clear();
341
342 // Get the coverage histogram and do find local maxima.
343 vifa_histogram_sptr h = this->GetCoverageHist();
344 vifa_histogram_sptr h_sup = h->NonMaximumSupress(max_suppress_radius(), true);
345 float* cnts = h_sup->GetCounts();
346 int max_idx = h_sup->GetRes();
347
348 // Rebuild the dominant direction array
349 for (int i = 0; i < max_idx; i++)
350 if (cnts[i] > 0)
351 dominant_dirs_.push_back(i);
352
353 // std::cout << "vgg::ComputeDominantDirs(): max_idx = " << max_idx << ", "
354 // << dominant_dirs_.size() << " dominant directions found\n";
355 }
356