00001 #include "bsol_hough_line_index.h"
00002
00003
00004
00005
00006
00007
00008
00009 #include <vcl_cmath.h>
00010
00011 #ifdef VCL_VC_6
00012
00013 # pragma warning(disable:4715 )
00014 #endif
00015
00016 #include <vcl_algorithm.h>
00017 #include <vnl/vnl_math.h>
00018 #include <vsol/vsol_line_2d.h>
00019 #include <vsol/vsol_point_2d.h>
00020 #include <vsol/vsol_point_2d_sptr.h>
00021 #undef DEGTORAD
00022 #define DEGTORAD 0.017453293f // = float(vnl_math::pi_over_180)
00023
00024 class nlines
00025 {
00026 public:
00027 bool operator()(const vcl_vector<vsol_line_2d_sptr> & v1,
00028 const vcl_vector<vsol_line_2d_sptr> & v2)
00029 {
00030 return v1.size() > v2.size();
00031 }
00032 };
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 bsol_hough_line_index::bsol_hough_line_index(const int r_dimension,
00044 const int theta_dimension)
00045 {
00046 xo_ = 0; yo_ = 0;
00047 ysize_ = xsize_ = (float)vcl_ceil(r_dimension/vnl_math::sqrt2);
00048 angle_range_ = (float)theta_dimension;
00049 angle_increment_ = 1.0f;
00050
00051 this->init(r_dimension, theta_dimension);
00052 }
00053
00054
00055
00056
00057 bsol_hough_line_index::bsol_hough_line_index(const float x0,
00058 const float y0,
00059 const float xsize,
00060 const float ysize,
00061 const float angle_range,
00062 const float angle_increment)
00063 {
00064 xo_ = x0; yo_ = y0;
00065 xsize_ = xsize;
00066 ysize_ = ysize;
00067 angle_range_ = angle_range;
00068 angle_increment_ = angle_increment;
00069
00070 int theta_dimension = (int)vcl_ceil(angle_range_/angle_increment_);
00071 theta_dimension++;
00072 float diag = vcl_sqrt(xsize*xsize + ysize*ysize);
00073 int rmax = int(diag);
00074 rmax++;
00075 this->init(rmax, theta_dimension);
00076 }
00077
00078 bsol_hough_line_index::
00079 bsol_hough_line_index(vbl_bounding_box<double, 2> const& box,
00080 const float angle_range,
00081 const float angle_increment)
00082 {
00083 xo_ = float(box.xmin()); yo_ = float(box.ymin());
00084 xsize_ = float(box.xmax()-xo_);
00085 ysize_ = float(box.ymax()-yo_);
00086 angle_range_ = angle_range;
00087 angle_increment_ = angle_increment;
00088
00089 int theta_dimension = (int)vcl_ceil(angle_range_/angle_increment_);
00090 theta_dimension++;
00091 float diag = vcl_sqrt(xsize_*xsize_ + ysize_*ysize_);
00092 int rmax = int(diag);
00093 rmax++;
00094 this->init(rmax, theta_dimension);
00095 }
00096
00097
00098 bsol_hough_line_index::~bsol_hough_line_index()
00099 {
00100 for (int r=0;r<r_dim_;r++)
00101 for (int th=0;th<th_dim_;th++)
00102 delete index_[r][th];
00103 }
00104
00105
00106
00107
00108
00109 void bsol_hough_line_index::array_loc(vsol_line_2d_sptr const& line,
00110 float& r, float& theta)
00111 {
00112
00113 float angle = (float)line->tangent_angle();
00114 if (angle >= 180.0f)
00115 angle -= 180.0f;
00116
00117 if (angle > angle_range_)
00118 {
00119 vcl_cout << "Warning - bsol_hough_line_index angle outside of range!\n";
00120 return;
00121 }
00122
00123 theta = angle;
00124
00125 float angrad = DEGTORAD*angle;
00126
00127
00128 vsol_point_2d_sptr mid = line->middle();
00129 float midx = float(mid->x()-xo_);
00130 float midy = float(mid->y()-yo_);
00131 float xs2 = xsize_/2.0f;
00132 float ys2 = ysize_/2.0f;
00133
00134 double cx = -(midx-xs2)*vcl_sin(angrad);
00135 double cy = (midy-ys2)*vcl_cos(angrad);
00136
00137
00138
00139 r = float(cx + cy + vcl_sqrt(xs2*xs2 + ys2*ys2));
00140 }
00141
00142
00143
00144
00145
00146 void bsol_hough_line_index::array_loc(vsol_line_2d_sptr const& line,
00147 int& r, int& theta)
00148 {
00149 float angle = 0, radius = 0;
00150 this->array_loc(line, radius, angle);
00151 theta = (int)vcl_floor(angle/angle_increment_);
00152 r = int(radius);
00153 }
00154
00155
00156
00157
00158
00159 int bsol_hough_line_index::trans_loc(const int transx, const int transy,
00160 const int r, const int theta)
00161 {
00162 float angle = angle_increment_*theta;
00163 float angrad = DEGTORAD*angle;
00164 int new_cx = -int(transx*vcl_sin(angrad));
00165 int new_cy = int(transy*vcl_cos(angrad));
00166 int newr = new_cx + new_cy;
00167 newr += r;
00168 if (newr < 0)
00169 return 0;
00170 else if (newr > r_dim_)
00171 return r_dim_;
00172 else
00173 return newr;
00174 }
00175
00176
00177
00178
00179
00180
00181 int bsol_hough_line_index::count(const int r, const int theta)
00182 {
00183 if (r<0||theta<0||r>=r_dim_||theta>=th_dim_)
00184 {
00185 vcl_cout << "Warning - bsol_hough_line_index index outside of range!\n";
00186 return 0;
00187 }
00188
00189 return index_[r][theta]->size();
00190 }
00191
00192
00193
00194
00195
00196
00197 bool bsol_hough_line_index::index(vsol_line_2d_sptr const& line)
00198 {
00199 if (!line)
00200 {
00201 vcl_cout << "In bsol_hough_line_index::index(..) NULL line\n";
00202 return false;
00203 }
00204 int r, theta;
00205 this->array_loc(line, r, theta);
00206 if (!(r < r_dim_)||!(theta < th_dim_))
00207 return false;
00208
00209 index_[r][theta]->push_back(line);
00210 return true;
00211 }
00212
00213
00214
00215
00216
00217 bool bsol_hough_line_index::index_new(vsol_line_2d_sptr const& line)
00218 {
00219 if (!line)
00220 {
00221 vcl_cout << "In bsol_hough_line_index::index_new(..) NULL line\n";
00222 return false;
00223 }
00224
00225 int r, theta;
00226
00227 this->array_loc(line, r, theta);
00228 if (!(r < r_dim_)||!(theta < th_dim_))
00229 return false;
00230
00231 vcl_vector<vsol_line_2d_sptr>* lines = index_[r][theta];
00232 if (!(vcl_find(lines->begin(), lines->end(), line) == lines->end()))
00233 return false;
00234
00235 index_[r][theta]->push_back(line);
00236 return true;
00237 }
00238
00239
00240
00241
00242 bool bsol_hough_line_index::find(vsol_line_2d_sptr const& line)
00243 {
00244 int r, theta;
00245 this->array_loc(line, r, theta);
00246 vcl_vector<vsol_line_2d_sptr>* lines = index_[r][theta];
00247 return !(vcl_find(lines->begin(), lines->end(), line) == lines->end());
00248 }
00249
00250
00251
00252
00253
00254
00255 bool bsol_hough_line_index::remove(vsol_line_2d_sptr const& line)
00256 {
00257 int r, theta;
00258 this->array_loc(line, r, theta);
00259 if (!(r < r_dim_)||!(theta < th_dim_))
00260 return false;
00261 vcl_vector<vsol_line_2d_sptr>* lines = index_[r][theta];
00262
00263 vcl_vector<vsol_line_2d_sptr>::iterator lit =
00264 vcl_find(lines->begin(), lines->end(), line);
00265 if (lit == lines->end())
00266 return false;
00267 lines->erase(lit);
00268 return true;
00269 }
00270
00271
00272
00273
00274
00275
00276 void
00277 bsol_hough_line_index::lines_at_index(const int r, const int theta,
00278 vcl_vector<vsol_line_2d_sptr>& lines)
00279 {
00280 lines.clear();
00281 if ((theta<0)||(theta>=th_dim_)||(r<0)||(r>=r_dim_))
00282 return;
00283
00284 int count = this->count(r, theta);
00285 if (count==0)
00286 return;
00287
00288 for (int i = 0; i<count; i++)
00289 lines.push_back((*index_[r][theta])[i]);
00290 }
00291
00292
00293
00294
00295
00296
00297 vcl_vector<vsol_line_2d_sptr> bsol_hough_line_index::
00298 lines_at_index(const int r, const int theta)
00299 {
00300 vcl_vector<vsol_line_2d_sptr> out;
00301 this->lines_at_index(r, theta, out);
00302 return out;
00303 }
00304
00305
00306
00307
00308
00309
00310
00311 void bsol_hough_line_index::
00312 lines_in_interval(vsol_line_2d_sptr const & l,
00313 const float r_dist,
00314 const float theta_dist,
00315 vcl_vector<vsol_line_2d_sptr>& lines)
00316 {
00317 lines.clear();
00318 if (!l)
00319 {
00320 vcl_cout << "In bsol_hough_line_index::lines_in_interval(..) NULL line\n";
00321 return;
00322 }
00323 int r, theta;
00324 this->array_loc(l, r, theta);
00325 int angle_radius = (int)vcl_ceil(theta_dist/angle_increment_);
00326 int r_radius = (int)vcl_ceil(r_dist);
00327 int th_dim_m1 = th_dim_ - 1;
00328
00329 for (int i = -angle_radius; i<=angle_radius; i++)
00330 {
00331
00332 int t_indx = (theta + i) % (th_dim_m1);
00333 if (t_indx<0)
00334 t_indx += th_dim_m1;
00335
00336 for (int j = -r_radius; j<=r_radius; j++)
00337 {
00338 int r_indx = r + j;
00339 if ((r_indx<0)||(r_indx>=r_dim_))
00340 continue;
00341 vcl_vector<vsol_line_2d_sptr> temp;
00342 this->lines_at_index(r_indx, t_indx,temp);
00343 for (vcl_vector<vsol_line_2d_sptr>::iterator lit = temp.begin();
00344 lit != temp.end(); lit++)
00345 {
00346
00347
00348 vsol_line_2d_sptr line = *lit;
00349 float l_angle, line_angle;
00350 float l_ndist, line_ndist;
00351 this->array_loc(l, l_ndist, l_angle);
00352 this->array_loc(line, line_ndist, line_angle);
00353
00354
00355 bool within_r_radius = vcl_fabs(l_ndist - line_ndist) < r_dist;
00356 if (!within_r_radius)
00357 continue;
00358
00359
00360 bool within_angle_radius = vcl_fabs(l_angle - line_angle) < theta_dist;
00361 if (!within_angle_radius)
00362 continue;
00363
00364
00365 lines.push_back(line);
00366 }
00367 }
00368 }
00369 }
00370
00371
00372
00373
00374
00375
00376
00377 vcl_vector<vsol_line_2d_sptr>
00378 bsol_hough_line_index::lines_in_interval(vsol_line_2d_sptr const & l,
00379 const float r_dist,
00380 const float theta_dist)
00381 {
00382 vcl_vector<vsol_line_2d_sptr> out;
00383 if (!l)
00384 {
00385 vcl_cout << "In bsol_hough_line_index::lines_in_interval(..) NULL line\n";
00386 return out;
00387 }
00388
00389 this->lines_in_interval(l, r_dist, theta_dist, out);
00390 return out;
00391 }
00392
00393
00394
00395
00396
00397
00398
00399 void
00400 bsol_hough_line_index::parallel_lines(const float angle,
00401 const float angle_dist,
00402 vcl_vector<vsol_line_2d_sptr>& lines)
00403 {
00404 lines.clear();
00405
00406
00407 float ang = vcl_fmod(angle,180.f);
00408 if (ang < 0) ang = 180.0f-ang;
00409
00410 if (ang > angle_range_)
00411 {
00412 vcl_cout << "Warning - bsol_hough_line_index angle outside of range!\n";
00413 return;
00414 }
00415 int theta = (int)vcl_floor(ang/angle_increment_);
00416 int angle_radius = (int)vcl_ceil(angle_dist/angle_increment_);
00417 int th_dim_m1 = th_dim_ - 1;
00418
00419 for (int i = -angle_radius; i<=angle_radius; i++)
00420 {
00421
00422 int t_indx = (theta + i) % (th_dim_m1);
00423 if (t_indx<0)
00424 t_indx += th_dim_m1;
00425 for (int j = 0; j<r_dim_; j++)
00426 {
00427 if (!(this->count(j, t_indx)>0))
00428 continue;
00429 vcl_vector<vsol_line_2d_sptr> temp;
00430 this->lines_at_index(j, t_indx, temp);
00431
00432 for (vcl_vector<vsol_line_2d_sptr>::iterator lit = temp.begin();
00433 lit != temp.end(); lit++)
00434 {
00435 vsol_line_2d_sptr line = *lit;
00436
00437 float line_angle = (float)line->tangent_angle();
00438 if (line_angle >= 180.0f)
00439 line_angle -= 180.0f;
00440 float ang_error = vcl_fabs(ang - line_angle);
00441 if (ang_error<angle_dist)
00442 lines.push_back(line);
00443 ang_error-=180.0f;
00444 if (vcl_fabs(ang_error)<angle_dist)
00445 lines.push_back(line);
00446 }
00447 }
00448 }
00449 }
00450
00451
00452
00453
00454
00455
00456
00457 vcl_vector<vsol_line_2d_sptr >
00458 bsol_hough_line_index::parallel_lines(const float angle,
00459 const float angle_dist)
00460 {
00461 vcl_vector<vsol_line_2d_sptr> out;
00462 this->parallel_lines(angle, angle_dist, out);
00463 return out;
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473 void
00474 bsol_hough_line_index::lines_at_angle(vsol_line_2d_sptr const &l,
00475 const float angle,
00476 const float angle_dist,
00477 vcl_vector<vsol_line_2d_sptr >& lines)
00478 {
00479 lines.clear();
00480 if (!l)
00481 {
00482 vcl_cout << "In bsol_hough_line_index::lines_at_angle(..) NULL line\n";
00483 return;
00484 }
00485 float ang = (float)l->tangent_angle() + angle;
00486 this->parallel_lines(ang, angle_dist, lines);
00487 }
00488
00489
00490
00491
00492
00493
00494
00495 vcl_vector<vsol_line_2d_sptr>
00496 bsol_hough_line_index::lines_at_angle(vsol_line_2d_sptr const &l,
00497 const float angle,
00498 const float angle_dist)
00499 {
00500 vcl_vector<vsol_line_2d_sptr> out;
00501 this->lines_at_angle(l, angle, angle_dist, out);
00502 return out;
00503 }
00504
00505
00506
00507
00508
00509
00510
00511 void
00512 bsol_hough_line_index::parallel_lines(vsol_line_2d_sptr const &l,
00513 const float angle_dist,
00514 vcl_vector<vsol_line_2d_sptr>& lines)
00515 {
00516 lines.clear();
00517 if (!l)
00518 {
00519 vcl_cout << "In bsol_hough_line_index::parallel_lines(..) NULL line\n";
00520 return;
00521 }
00522 float angle = (float)l->tangent_angle();
00523 this->parallel_lines(angle, angle_dist, lines);
00524 }
00525
00526
00527
00528
00529
00530
00531
00532 vcl_vector<vsol_line_2d_sptr>
00533 bsol_hough_line_index::parallel_lines(vsol_line_2d_sptr const &l,
00534 const float angle_dist)
00535 {
00536 vcl_vector<vsol_line_2d_sptr> out;
00537 if (!l)
00538 {
00539 vcl_cout << "In bsol_hough_line_index::parallel_lines(..) NULL line\n";
00540 return out;
00541 }
00542 this->parallel_lines(l, angle_dist, out);
00543 return out;
00544 }
00545
00546
00547
00548
00549
00550
00551 void bsol_hough_line_index::clear_index()
00552 {
00553 for (int r=0;r<r_dim_;r++)
00554 for (int th=0;th<th_dim_;th++)
00555 index_[r][th]->clear();
00556 }
00557
00558
00559
00560
00561
00562 void bsol_hough_line_index::init(const int r_dimension,
00563 const int theta_dimension)
00564 {
00565 r_dim_ = r_dimension;
00566 th_dim_ = theta_dimension;
00567 index_.resize(r_dim_, th_dim_);
00568 for (int r=0;r<r_dim_;r++)
00569 for (int th=0;th<th_dim_;th++)
00570 index_.put(r,th, new vcl_vector<vsol_line_2d_sptr>);
00571 }
00572
00573
00574
00575
00576 vcl_vector<int> bsol_hough_line_index::angle_histogram()
00577 {
00578 vcl_vector<int> angle_hist(th_dim_);
00579 for (int x = 0; x<th_dim_; x++)
00580 {
00581 angle_hist[x]=0;
00582 for (int y = 0; y<r_dim_; y++)
00583 {
00584 vcl_vector<vsol_line_2d_sptr>* lines = index_[y][x];
00585 if (lines)
00586 angle_hist[x]+=lines->size();
00587 }
00588 }
00589 return angle_hist;
00590 }
00591
00592
00593
00594
00595
00596
00597 static int get_extended_count(int bin, vcl_vector<int> const& ang_hist)
00598 {
00599 int n_bins = ang_hist.size();
00600 int nbm = n_bins-1;
00601
00602 if (bin<0)
00603 return ang_hist[nbm+bin];
00604
00605 if (bin >= n_bins)
00606 return ang_hist[bin-n_bins];
00607
00608 return ang_hist[bin];
00609 }
00610
00611
00612
00613
00614
00615 static void remove_flat_peaks(vcl_vector<int>& angle_hist)
00616 {
00617 int nbins = angle_hist.size();
00618 int nbm = nbins-1;
00619
00620
00621
00622 bool init= get_extended_count(0, angle_hist)>0;
00623 int init_end =0;
00624
00625
00626 bool start=false;
00627 int start_index=0;
00628
00629
00630 for (int i = 0; i < nbins; i++)
00631 {
00632 int v = get_extended_count(i, angle_hist);
00633
00634
00635 if (init && v!=0)
00636 continue;
00637
00638 if (init && v==0)
00639 {
00640 init_end = i;
00641 init = false;
00642 continue;
00643 }
00644
00645
00646 if (!start && v==0)
00647 continue;
00648
00649
00650 if (!start && v!=0)
00651 {
00652 start_index = i;
00653 start = true;
00654 continue;
00655 }
00656
00657 if (start && v==0)
00658 {
00659 int peak_location = (start_index+i-1)/2;
00660 for (int k = start_index; k<=(i-1); k++)
00661 if (k!=peak_location)
00662 angle_hist[k] = 0;
00663 start = false;
00664 }
00665 }
00666
00667 if (init_end!=0) {
00668 if (start)
00669 {
00670 int peak_location = (start_index + init_end - nbm -1)/2;
00671 int k;
00672 if (peak_location < 0)
00673 {
00674 peak_location += nbm;
00675 for ( k = 0; k< init_end; k++)
00676 angle_hist[k]=0;
00677 for ( k= start_index; k <nbins; k++)
00678 if (k!=peak_location)
00679 angle_hist[k] = 0;
00680 }
00681 else
00682 {
00683 for ( k = start_index; k< nbins; k++)
00684 angle_hist[k]=0;
00685 for ( k= 0; k < init_end; k++)
00686 if (k!=peak_location)
00687 angle_hist[k] = 0;
00688 }
00689 }
00690 else
00691 {
00692 int init_location = (init_end-1)/2;
00693 for (int k = 0; k<=init_end; k++)
00694 if (k!=init_location)
00695 angle_hist[k] = 0;
00696 }
00697 }
00698 }
00699
00700
00701
00702
00703
00704
00705
00706 vcl_vector<int>
00707 bsol_hough_line_index::non_maximum_suppress(const int radius,
00708 vcl_vector<int> const& bins)
00709 {
00710 int num = bins.size();
00711 vcl_vector<int> out(num);
00712 if (4*radius +2 > num)
00713 {
00714 vcl_cout << "bsol_hough_line_index::non_maximum_suppress(..) - radius is too large\n";
00715 return out;
00716 }
00717
00718
00719 for (int indx =0; indx < num; indx++)
00720 out[indx] = 0;
00721
00722
00723 for (int indx = 0; indx<num; indx++)
00724 {
00725
00726 int max_count = bins[indx];
00727 for (int k = -radius; k <= radius ;k++)
00728 {
00729 int index = indx+k;
00730 int c = get_extended_count(index, bins);
00731 if ( c > max_count)
00732 max_count = c;
00733 }
00734
00735 if (max_count == bins[indx])
00736 out[indx] = max_count;
00737 }
00738 remove_flat_peaks(out);
00739 return out;
00740 }
00741
00742
00743
00744
00745
00746
00747 int bsol_hough_line_index::
00748 dominant_directions(const int thresh, const float angle_tol,
00749 vcl_vector<int>& dirs)
00750 {
00751 int radius = int(0.5f+angle_tol/angle_increment_);
00752 vcl_vector<int> angle_hist = this->angle_histogram();
00753 vcl_vector<int> suppressed_hist =
00754 this->non_maximum_suppress(radius, angle_hist);
00755 for (int i = 0; i<th_dim_; i++)
00756 if (suppressed_hist[i]>=thresh)
00757 dirs.push_back(i);
00758 return dirs.size();
00759 }
00760
00761
00762
00763
00764
00765 int bsol_hough_line_index::
00766 dominant_line_groups(const int thresh, const float angle_tol,
00767 vcl_vector<vcl_vector<vsol_line_2d_sptr> >& groups)
00768 {
00769 groups.clear();
00770 vcl_vector<int> dirs;
00771 int n_groups = this->dominant_directions(thresh, angle_tol, dirs);
00772 if (!n_groups)
00773 return 0;
00774 for (int gi = 0; gi<n_groups; gi++)
00775 {
00776 vcl_vector<vsol_line_2d_sptr> lines;
00777 float angle = dirs[gi]*angle_increment_;
00778 this->parallel_lines(angle, angle_tol, lines);
00779 groups.push_back(lines);
00780 }
00781 vcl_sort(groups.begin(), groups.end(), nlines());
00782 return n_groups;
00783 }
00784
00785
00786
00787 vbl_array_2d<unsigned char> bsol_hough_line_index::get_hough_image()
00788 {
00789 vbl_array_2d<unsigned char> out(r_dim_, th_dim_);
00790 int nmax = 0;
00791 for (int r=0;r<r_dim_;r++)
00792 for (int th=0;th<th_dim_;th++)
00793 {
00794 int n_lines = index_[r][th]->size();
00795 if (n_lines>nmax)
00796 nmax = n_lines;
00797 }
00798 float scale = 1;
00799 if (nmax != 0)
00800 scale /= 1.0f/nmax;
00801 for (int r=0;r<r_dim_;r++)
00802 for (int th=0;th<th_dim_;th++)
00803 {
00804 unsigned char val;
00805 int n_lines = index_[r][th]->size();
00806 float v = 255*n_lines/scale;
00807 val = (unsigned char)v;
00808 out.put(r,th,val);
00809 }
00810 return out;
00811 }