00001
00002 #include "osl_edge_detector.h"
00003
00004
00005
00006 #include <vcl_cmath.h>
00007 #include <vcl_cstdlib.h>
00008 #include <vcl_cassert.h>
00009 #include <vcl_list.h>
00010 #include <vcl_iostream.h>
00011 #include <vcl_algorithm.h>
00012
00013 #include <osl/osl_canny_base.h>
00014 #include <osl/osl_kernel.h>
00015 #include <osl/osl_canny_smooth.h>
00016 #include <osl/osl_canny_gradient.h>
00017 #include <osl/osl_chamfer.h>
00018 #include <osl/internals/osl_reorder_chain.h>
00019 #include <vnl/vnl_math.h>
00020
00021 const float DUMMYTHETA = 10000.0f;
00022 const float ALPHA = 0.9f;
00023
00024 #define FAR 65535
00025
00026 #define Make_float_image(w, h) osl_canny_base_make_raw_image(w, h, (float*)0)
00027 #define Make_int_image(w, h) osl_canny_base_make_raw_image(w, h, (int*)0)
00028 #define Free_float_image(i,dummy) osl_canny_base_free_raw_image(i)
00029 #define Free_int_image(i,dummy) osl_canny_base_free_raw_image(i)
00030
00031
00032
00033 osl_edge_detector::osl_edge_detector(osl_edge_detector_params const ¶ms)
00034 : osl_edge_detector_params(params)
00035 {
00036
00037 gradient_histogram_ = false;
00038 histogram_resolution_ = 15;
00039
00040 width_ = int(sigma_*vcl_sqrt(2*vcl_log(1.0/gauss_tail_))+1);
00041 k_size_ = 2*width_+ 1;
00042 kernel_ = new float[k_size_];
00043 max_gradient_ = low_;
00044 xjunc_ = new vcl_list<int>;
00045 yjunc_ = new vcl_list<int>;
00046 vlist_ = new vcl_list<osl_Vertex*>;
00047
00048 jval_ = 2000.0;
00049
00050 vertidcount_ = 0;
00051 }
00052
00053
00054
00055 osl_edge_detector::~osl_edge_detector()
00056 {
00057 Free_float_image(dx_,xsize_);
00058 Free_float_image(dy_,xsize_);
00059 Free_float_image(grad_,xsize_);
00060
00061 Free_float_image(thin_,xsize_);
00062 Free_float_image(theta_,xsize_);
00063 Free_float_image(thresh_,xsize_);
00064
00065 Free_int_image(dist_,xsize_);
00066 Free_int_image(jx_,xsize_);
00067 Free_int_image(jy_,xsize_);
00068 Free_int_image(junction_,xsize_);
00069
00070
00071 delete vlist_;
00072 delete [] kernel_;
00073 delete xjunc_;
00074 delete yjunc_;
00075 }
00076
00077
00078
00079
00080 void osl_edge_detector::detect_edges(vil1_image const &image,
00081 vcl_list<osl_edge*> *edges,
00082 bool maintain_topology)
00083 {
00084 assert(edges!=0);
00085
00086
00087 xsize_ = image.height();
00088 ysize_ = image.width();
00089 xstart_ = 0;
00090 ystart_ = 0;
00091
00092
00093
00094
00095 dx_ = Make_float_image(xsize_,ysize_);
00096 dy_ = Make_float_image(xsize_,ysize_);
00097 grad_ = Make_float_image(xsize_,ysize_);
00098 smooth_ = Make_float_image(xsize_,ysize_);
00099
00100 thin_ = Make_float_image(xsize_,ysize_);
00101 thresh_ = Make_float_image(xsize_,ysize_);
00102 theta_ = Make_float_image(xsize_,ysize_);
00103
00104 dist_ = Make_int_image(xsize_,ysize_);
00105 junction_ = Make_int_image(xsize_,ysize_);
00106 jx_ = Make_int_image(xsize_,ysize_);
00107 jy_ = Make_int_image(xsize_,ysize_);
00108
00109 if (verbose_)
00110 vcl_cerr << "Doing canny on image region "
00111 << xsize_ << " by " << ysize_ << vcl_endl
00112 << "Gaussian tail = " << gauss_tail_ << vcl_endl
00113 << "Sigma = " << sigma_ << vcl_endl
00114 << "Kernel size = " << k_size_ << vcl_endl
00115 << "Threshold = " << low_ << vcl_endl;
00116
00117 if (verbose_)
00118 vcl_cerr << "setting convolution kernel and zeroing images\n";
00119 osl_kernel_DOG(sigma_, kernel_, k_size_, width_);
00120
00121 osl_canny_base_fill_raw_image(thin_, xsize_, ysize_, 0.0f);
00122 osl_canny_base_fill_raw_image(thresh_, xsize_, ysize_, low_);
00123 osl_canny_base_fill_raw_image(theta_, xsize_, ysize_, DUMMYTHETA);
00124
00125
00126
00127 osl_canny_base_fill_raw_image(dist_, xsize_, ysize_, FAR);
00128
00129
00130
00131 if (verbose_) vcl_cerr << "smoothing the image\n";
00132 osl_canny_smooth_rothwell(image, kernel_, width_, k_size_, smooth_);
00133
00134 if (verbose_)
00135 vcl_cerr << "computing x,y derivatives and norm of gradient\n";
00136 osl_canny_gradient(xsize_, ysize_, smooth_, dx_, dy_, grad_);
00137
00138 if (verbose_)
00139 vcl_cerr << "doing sub-pixel interpolation\n";
00140 Sub_pixel_interpolation();
00141
00142 if (verbose_) vcl_cerr << "assigning thresholds\n";
00143 Set_thresholds();
00144
00145
00146
00147
00148 if ( !maintain_topology ) {
00149 vcl_cerr << "Filling holes\n";
00150 Fill_holes();
00151 }
00152
00153
00154 if (verbose_) vcl_cerr << "thinning edges\n";
00155 Thin_edges();
00156
00157
00158
00159 if (verbose_)
00160 vcl_cerr << "locating junctions in the edge image - ";
00161 Find_junctions();
00162 if (verbose_)
00163 vcl_cerr << xjunc_->size() << " junctions found\n";
00164
00165 Find_junction_clusters();
00166 if (verbose_)
00167 vcl_cerr << vlist_->size() << " junction clusters found\n";
00168
00169
00170 if (verbose_) vcl_cerr << "doing final edge following\n";
00171 Follow_curves(edges);
00172
00173 if (verbose_) vcl_cerr << "finished osl_edge_detector\n";
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 void osl_edge_detector::Sub_pixel_interpolation()
00185 {
00186 float h1=0.0,h2=0.0;
00187 float k = float(vnl_math::deg_per_rad);
00188 int orient;
00189 float theta,grad;
00190 float fraction,dnewx=0.0,dnewy=0.0;
00191
00192
00193 for (unsigned int x=width_+1; x+width_+1<xsize_; ++x)
00194 {
00195 float *g0 = grad_[x-1];
00196 float *g1 = grad_[x];
00197 float *g2 = grad_[x+1];
00198 float *dx = dx_[x];
00199 float *dy = dy_[x];
00200
00201 for (unsigned int y=width_+1; y+width_+1<ysize_; ++y)
00202 {
00203
00204 if ( g1[y] > low_ ) {
00205 theta = k*(float)vcl_atan2(dy[y],dx[y]);
00206
00207
00208
00209 if ( theta >= 0.0 )
00210 orient = int(theta/45.0);
00211 else
00212 orient = int(theta/45.0+4);
00213
00214 orient = orient%4;
00215
00216
00217 switch ( orient ) {
00218 case 0:
00219 grad = dy[y]/dx[y];
00220 h1 = grad*g0[y-1] + (1 - grad)*g0[y];
00221 h2 = grad*g2[y+1] + (1 - grad)*g2[y];
00222 break;
00223
00224 case 1:
00225 grad = dx[y]/dy[y];
00226 h1 = grad*g0[y-1] + (1 - grad)*g1[y-1];
00227 h2 = grad*g2[y+1] + (1 - grad)*g1[y+1];
00228 break;
00229
00230 case 2:
00231 grad = -dx[y]/dy[y];
00232 h1 = grad*g2[y-1] + (1 - grad)*g1[y-1];
00233 h2 = grad*g0[y+1] + (1 - grad)*g1[y+1];
00234 break;
00235
00236 case 3:
00237 grad = -dy[y]/dx[y];
00238 h1 = grad*g2[y-1] + (1 - grad)*g2[y];
00239 h2 = grad*g0[y+1] + (1 - grad)*g0[y];
00240 break;
00241
00242 default:
00243 vcl_abort();
00244
00245 }
00246
00247
00248
00249 fraction = (h1-h2)/(2*(h1-2*g1[y]+h2));
00250 switch ( orient ) {
00251 case 0:
00252 dnewx = fraction;
00253 dnewy = dy[y]/dx[y]*fraction;
00254 break;
00255
00256 case 1:
00257 dnewx = dx[y]/dy[y]*fraction;
00258 dnewy = fraction;
00259 break;
00260
00261 case 2:
00262 dnewx = dx[y]/dy[y]*fraction;
00263 dnewy = fraction;
00264 break;
00265
00266 case 3:
00267 dnewx = - fraction;
00268 dnewy = - dy[y]/dx[y]*fraction;
00269 break;
00270
00271 default:
00272 vcl_abort();
00273
00274 }
00275
00276
00277
00278
00279
00280
00281
00282
00283 if ( g1[y]>=h1 && g1[y]>=h2 && vcl_fabs(dnewx)<=0.5 && vcl_fabs(dnewy)<=0.5 )
00284 {
00285 if ( g1[y]*ALPHA > low_ )
00286 thresh_[x][y] = ALPHA * g1[y];
00287
00288
00289
00290 Thicken_threshold(x,y);
00291 }
00292
00293
00294 if ( (vcl_fabs(dnewx)<=0.5) && (vcl_fabs(dnewy)<=0.5) ) {
00295 dx[y] = x + dnewx + 0.5f;
00296 dy[y] = y + dnewy + 0.5f;
00297 }
00298 else {
00299 dx[y] = x + 0.5f;
00300 dy[y] = y + 0.5f;
00301 }
00302 theta_[x][y] = theta;
00303 }
00304
00305
00306 else {
00307 dx[y] = x + 0.5f;
00308 dy[y] = y + 0.5f;
00309 }
00310 }
00311 }
00312
00313
00314 for (unsigned int x=0; x<xsize_; ++x) {
00315 for (unsigned int y=0; y<=width_; ++y) {
00316 dx_[x][y] = x + 0.5f;
00317 dy_[x][y] = y + 0.5f;
00318 }
00319 for (int y=ysize_-width_-1; y<int(ysize_); ++y)
00320 {
00321 dx_[x][y] = x + 0.5f;
00322 dy_[x][y] = y + 0.5f;
00323 }
00324 }
00325
00326 for (unsigned int y=width_+1; y+width_+1<ysize_; ++y)
00327 {
00328 for (unsigned int x=0; x<=width_; ++x) {
00329 dx_[x][y] = x + 0.5f;
00330 dy_[x][y] = y + 0.5f;
00331 }
00332 for (int x=xsize_-width_-1; x<int(xsize_); ++x)
00333 {
00334 dx_[x][y] = x + 0.5f;
00335 dy_[x][y] = y + 0.5f;
00336 }
00337 }
00338 }
00339
00340
00341
00342
00343
00344
00345
00346 void osl_edge_detector::Thicken_threshold(int x, int y)
00347 {
00348
00349 int width = width_;
00350
00351
00352 for (int i=x-width; i<=x+width; ++i)
00353 for (int j=y-width; j<=y+width; ++j) {
00354
00355 dist_[i][j] = 0;
00356 if ( thresh_[i][j] != low_ )
00357 thresh_[i][j] = vcl_min(thresh_[x][y], thresh_[i][j]);
00358 else
00359 thresh_[i][j] = thresh_[x][y];
00360 }
00361 }
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 void osl_edge_detector::Set_thresholds()
00384 {
00385 int** fdist = Make_int_image(xsize_,ysize_);
00386 int** bdist = Make_int_image(xsize_,ysize_);
00387 int**a1dist = Make_int_image(xsize_,ysize_);
00388 int**a2dist = Make_int_image(xsize_,ysize_);
00389 osl_canny_base_copy_raw_image(VCL_OVERLOAD_CAST(int const*const*, dist_), fdist, xsize_, ysize_);
00390 osl_canny_base_copy_raw_image(VCL_OVERLOAD_CAST(int const*const*, dist_), bdist, xsize_, ysize_);
00391 osl_canny_base_copy_raw_image(VCL_OVERLOAD_CAST(int const*const*, dist_),a1dist, xsize_, ysize_);
00392 osl_canny_base_copy_raw_image(VCL_OVERLOAD_CAST(int const*const*, dist_),a2dist, xsize_, ysize_);
00393
00394 float** fth = Make_float_image(xsize_,ysize_);
00395 float** bth = Make_float_image(xsize_,ysize_);
00396 float**a1th = Make_float_image(xsize_,ysize_);
00397 float**a2th = Make_float_image(xsize_,ysize_);
00398 osl_canny_base_copy_raw_image(VCL_OVERLOAD_CAST(float const *const*, thresh_), fth, xsize_, ysize_);
00399 osl_canny_base_copy_raw_image(VCL_OVERLOAD_CAST(float const *const*, thresh_), bth, xsize_, ysize_);
00400 osl_canny_base_copy_raw_image(VCL_OVERLOAD_CAST(float const *const*, thresh_),a1th, xsize_, ysize_);
00401 osl_canny_base_copy_raw_image(VCL_OVERLOAD_CAST(float const *const*, thresh_),a2th, xsize_, ysize_);
00402
00403 osl_chamfer_Forward (xsize_, ysize_, fdist, fth);
00404 osl_chamfer_Backward(xsize_, ysize_, bdist, bth);
00405 osl_chamfer_Alt1(xsize_, ysize_, a1dist, a1th);
00406 osl_chamfer_Alt2(xsize_, ysize_, a2dist, a2th);
00407
00408
00409
00410
00411
00412
00413 for (unsigned int x=0; x<xsize_; ++x) {
00414 for (unsigned int y=0; y<ysize_; ++y) {
00415
00416 if ( thresh_[x][y] == low_ ) {
00417
00418
00419 int option = osl_Minimum4(fdist[x][y],
00420 bdist[x][y],
00421 a1dist[x][y],
00422 a2dist[x][y]);
00423 float num=1.0f; int den=1;
00424 switch (option) {
00425 case 1:
00426 case 2:
00427 den = fdist[x][y]+bdist[x][y];
00428 num = bdist[x][y]*fth[x][y]+fdist[x][y]*bth[x][y];
00429 break;
00430
00431 case 3:
00432 case 4:
00433 den = a1dist[x][y]+a2dist[x][y];
00434 num = a2dist[x][y]*a1th[x][y]+a1dist[x][y]*a2th[x][y];
00435 break;
00436
00437 default:
00438 vcl_abort();
00439
00440 }
00441 if ( den != 0.0 )
00442 thresh_[x][y] = num / den;
00443 else if ( thresh_[x][y] <= low_ )
00444 thresh_[x][y] = low_;
00445 }
00446
00447 if ( grad_[x][y]>thresh_[x][y] ) {
00448
00449 if (grad_[x][y]>max_gradient_)
00450 max_gradient_=grad_[x][y];
00451 thin_[x][y] = grad_[x][y];
00452 }
00453 }
00454 }
00455
00456
00457 #if 0 // commented out
00458 if (gradient_histogram_)
00459 {
00460 ghist_ = new Histogram(histogram_resolution_, low_, max_gradient);
00461 for (x=0; x<xsize_; ++x)
00462 for (y=0; y<ysize_; ++y)
00463
00464 ghist_->UpCount(thin_[x][y]);
00465 }
00466 #endif
00467
00468 Free_int_image(fdist,xsize_);
00469 Free_int_image(bdist,xsize_);
00470 Free_int_image(a1dist,xsize_);
00471 Free_int_image(a2dist,xsize_);
00472 Free_float_image(fth,xsize_);
00473 Free_float_image(bth,xsize_);
00474 Free_float_image(a1th,xsize_);
00475 Free_float_image(a2th,xsize_);
00476 }
00477
00478 struct osl_edge_detector_xyfloat
00479 {
00480 int x;
00481 int y;
00482 float thin;
00483 };
00484
00485 static int compare(osl_edge_detector_xyfloat* xyf1, osl_edge_detector_xyfloat* xyf2)
00486 {
00487 if (xyf1->thin < xyf2->thin)
00488 return -1;
00489 if (xyf1->thin == xyf2->thin)
00490 return 0;
00491 return 1;
00492 }
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506 void osl_edge_detector::Thin_edges()
00507 {
00508
00509 bool do_output = true;
00510
00511 vcl_cerr << __FILE__ ": Fast Sort\n";
00512 osl_edge_detector_xyfloat* edgel_array = new osl_edge_detector_xyfloat[xsize_ * ysize_];
00513 int count = 1;
00514 while ( count!=0 )
00515 {
00516 count = 0;
00517 int edgel_array_len = 0;
00518 for (unsigned int x=width_; x+width_<xsize_; ++x)
00519 for (unsigned int y=width_; y+width_<ysize_; ++y)
00520 if ( thin_[x][y] > thresh_[x][y] )
00521 {
00522 edgel_array[edgel_array_len].x = x;
00523 edgel_array[edgel_array_len].y = y;
00524 edgel_array[edgel_array_len].thin = thin_[x][y];
00525 edgel_array_len++;
00526 }
00527
00528
00529
00530
00531 vcl_qsort(edgel_array,
00532 edgel_array_len,
00533 sizeof(osl_edge_detector_xyfloat),
00534 (int (*)(const void *, const void *))&compare);
00535
00536
00537 if ( do_output && (edgel_array_len > 0) ) {
00538
00539 vcl_cerr << "edgel strengths range from "
00540 << edgel_array[0].thin << " to "
00541 << edgel_array[edgel_array_len-1].thin << vcl_endl;
00542 do_output = false;
00543 }
00544
00545
00546
00547 for (int pos=0; pos<edgel_array_len; ++pos)
00548 {
00549 int x = edgel_array[pos].x;
00550 int y = edgel_array[pos].y;
00551
00552 int a = ( thin_[x-1][y-1] > thresh_[x-1][y-1] ) ? 1 : 0;
00553 int b = ( thin_[x ][y-1] > thresh_[x ][y-1] ) ? 1 : 0;
00554 int c = ( thin_[x+1][y-1] > thresh_[x+1][y-1] ) ? 1 : 0;
00555 int d = ( thin_[x+1][y ] > thresh_[x+1][y ] ) ? 1 : 0;
00556 int e = ( thin_[x+1][y+1] > thresh_[x+1][y+1] ) ? 1 : 0;
00557 int f = ( thin_[x ][y+1] > thresh_[x ][y+1] ) ? 1 : 0;
00558 int g = ( thin_[x-1][y+1] > thresh_[x-1][y+1] ) ? 1 : 0;
00559 int h = ( thin_[x-1][y ] > thresh_[x-1][y ] ) ? 1 : 0;
00560
00561 int genus = a+b+c+d+e+f+g+h;
00562
00563
00564 if ( (genus!=1) && (genus!=8) ) {
00565
00566 genus += h*a*b+b*c*d+d*e*f+f*g*h
00567 - a*b-b*c-c*d-d*e-e*f-f*g
00568 - g*h-h*a-h*b-b*d-d*f-f*h-1;
00569
00570
00571 if ( genus == 0 ) {
00572 count++;
00573 thin_[x][y] = 0.0;
00574 }
00575 }
00576 }
00577 }
00578
00579 delete [] edgel_array;
00580 }
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590 void osl_edge_detector::Fill_holes()
00591 {
00592
00593 float SMALL = 0.0001f;
00594
00595 for (unsigned int x=width_; x+width_<xsize_; ++x)
00596 for (unsigned int y=width_; y+width_<ysize_; ++y)
00597 if ( thin_[x][y] <= thresh_[x][y] )
00598 {
00599 int count = 0;
00600 if ( thin_[x ][y-1] > thresh_[x ][y-1] ) count++;
00601 if ( thin_[x ][y+1] > thresh_[x ][y+1] ) count++;
00602 if ( thin_[x+1][y ] > thresh_[x+1][y ] ) count++;
00603 if ( thin_[x-1][y ] > thresh_[x-1][y ] ) count++;
00604
00605 if ( count == 4 )
00606 thin_[x][y] = thresh_[x][y] + SMALL;
00607 }
00608 }
00609
00610
00611
00612
00613
00614 extern osl_Vertex *osl_find(vcl_list<osl_Vertex*> const *l, osl_Vertex const &v);
00615
00616
00617
00618
00619
00620 void osl_edge_detector::Follow_curves(vcl_list<osl_edge*> *edges)
00621 {
00622
00623
00624
00625
00626 vcl_list<int> xcoords,ycoords;
00627 vcl_list<float> grad;
00628
00629 chain_no_ = 10;
00630
00631
00632 edges->clear();
00633 for (unsigned int x=width_; x+width_<xsize_; ++x)
00634 {
00635 float *thin = thin_[x];
00636 for (unsigned int y=width_; y+width_<ysize_; ++y)
00637 {
00638 if ( (thin[y]<=thresh_[x][y]) || junction_[x][y] )
00639 continue;
00640
00641
00642 chain_no_++;
00643
00644
00645 xcoords.clear();
00646 ycoords.clear();
00647 grad.clear();
00648
00649 Follow(x,y,&xcoords,&ycoords,&grad,0);
00650
00651
00652
00653
00654 xcoords.reverse(); ycoords.reverse(); grad.reverse();
00655 Follow(x,y,&xcoords,&ycoords,&grad,1);
00656
00657
00658
00659 if ( xcoords.size() < 2 )
00660
00661 continue;
00662
00663 int count=0;
00664 for (vcl_list<float>::iterator i=grad.begin(); i!=grad.end(); ++i)
00665 count++;
00666
00667
00668
00669
00670 if ( count < 2 )
00671 continue;
00672
00673
00674 osl_edgel_chain *dc = new osl_edgel_chain(count);
00675 float *px = dc->GetX();
00676 float *py = dc->GetY();
00677 float *pg = dc->GetGrad();
00678 float *pt = dc->GetTheta();
00679
00680
00681 while (count) {
00682 int tmpx = xcoords.front(); xcoords.pop_front();
00683 int tmpy = ycoords.front(); ycoords.pop_front();
00684 float val = grad.front(); grad.pop_front();
00685 count--;
00686
00687
00688 if ( val != jval_ ) {
00689 *(px++) = dx_[tmpx][tmpy] + xstart_;
00690 *(py++) = dy_[tmpx][tmpy] + ystart_;
00691 *(pg++) = val;
00692
00693
00694 }
00695 else {
00696 *(px++) = float(tmpx + xstart_);
00697 *(py++) = float(tmpy + ystart_);
00698 *(pg++) = 0.0f;
00699 }
00700 if (theta_[tmpx][tmpy] == DUMMYTHETA) {
00701 const float k = float(vnl_math::deg_per_rad);
00702 theta_[tmpx][tmpy] = k*(float)vcl_atan2(dy_[tmpx][y],dx_[tmpx][y]);
00703 }
00704
00705 *(pt++) = theta_[tmpx][tmpy];
00706 }
00707
00708
00709
00710 if ( (dc->size()==2) &&
00711 (dc->GetX(0)==dc->GetX(1)) &&
00712 (dc->GetY(0)==dc->GetY(1)) ) {
00713 delete dc;
00714 continue;
00715 }
00716
00717 else if ( dc->size() > 1 ) {
00718
00719 osl_Vertex *v1 = new osl_Vertex(dc->GetX(0),dc->GetY(0));
00720 v1->SetId(vertidcount_++);
00721 osl_Vertex *v2 = new osl_Vertex(dc->GetX(dc->size()-1),dc->GetY(dc->size()-1));
00722 v2->SetId(vertidcount_++);
00723
00724 osl_Vertex *V1 = osl_find(vlist_, *v1);
00725 osl_Vertex *V2 = osl_find(vlist_, *v2);
00726
00727
00728
00729 int single_chain = false;
00730 if ( !V1 && !V2 ) {
00731 float dx = dc->GetX(0) - dc->GetX(dc->size()-1);
00732 float dy = dc->GetY(0) - dc->GetY(dc->size()-1);
00733 if ( dx*dx+dy*dy<4 ) {
00734 osl_reorder_chain(dc);
00735 osl_IUDelete(v1);
00736 osl_IUDelete(v2);
00737 v1 = new osl_Vertex(dc->GetX(0),dc->GetY(0));
00738 v1->SetId(vertidcount_++);
00739 V1 = v1; V2 = v1;
00740 single_chain = true;
00741 }
00742 }
00743 if ( !single_chain ) {
00744 if ( !V1 )
00745 V1 = v1;
00746 else
00747 { osl_IUDelete(v1); }
00748 if ( !V2 )
00749 V2 = v2;
00750 else
00751 { osl_IUDelete(v2); }
00752 }
00753
00754
00755
00756
00757
00758
00759
00760
00761 edges->push_front(new osl_edge(*dc, V1, V2));
00762 delete dc;
00763 }
00764 }
00765 }
00766 }
00767
00768
00769
00770
00771
00772
00773 void osl_edge_detector::Follow(int x, int y,
00774 vcl_list<int> *xc,
00775 vcl_list<int> *yc,
00776 vcl_list<float> *grad,
00777 int reverse)
00778 {
00779
00780 assert( x>0 && y>0 );
00781 assert( (unsigned int)x+1<xsize_ );
00782 assert( (unsigned int)y+1<ysize_ );
00783
00784
00785
00786 if (!reverse) {
00787 xc->push_front(x);
00788 yc->push_front(y);
00789 grad->push_front(thin_[x][y]);
00790 }
00791 thin_[x][y] = 0.0;
00792
00793
00794
00795
00796
00797
00798
00799 if (false) { }
00800
00801
00802 #define smoo(a, b) \
00803 else if ( (thin_[a][b]>thresh_[a][b]) && (junction_[a][b]==0) ) \
00804 Follow(a, b, xc,yc, grad, 0);
00805 smoo(x , y-1)
00806 smoo(x-1, y )
00807 smoo(x , y+1)
00808 smoo(x+1, y )
00809 smoo(x+1, y-1)
00810 smoo(x-1, y-1)
00811 smoo(x-1, y+1)
00812 smoo(x+1, y+1)
00813 #undef smoo
00814
00815
00816
00817
00818
00819 #define smoo(a, b) \
00820 else if ( junction_[a][b] && ((xc->size()>2) || (junction_[a][b]!=chain_no_)) ) { \
00821 xc->push_front(jx_[a][b]); \
00822 yc->push_front(jy_[a][b]); \
00823 grad->push_front(jval_); \
00824 junction_[a][b] = chain_no_; \
00825 }
00826 smoo(x , y-1)
00827 smoo(x-1, y )
00828 smoo(x , y+1)
00829 smoo(x+1, y )
00830 smoo(x+1, y-1)
00831 smoo(x-1, y-1)
00832 smoo(x-1, y+1)
00833 smoo(x+1, y+1)
00834 #undef smoo
00835 else {
00836
00837 }
00838 }
00839
00840
00841
00842
00843
00844
00845 void osl_edge_detector::Find_junctions()
00846 {
00847
00848 xjunc_->clear();
00849 yjunc_->clear();
00850 osl_canny_base_fill_raw_image(junction_, xsize_, ysize_, 0);
00851
00852 for (unsigned int x=width_; x+width_<xsize_; ++x)
00853 for (unsigned int y=width_; y+width_<ysize_; ++y)
00854 {
00855 if ( thin_[x][y] <= thresh_[x][y] )
00856 continue;
00857
00858 int count = 0;
00859 if ( thin_[x-1][y-1] > thresh_[x-1][y-1] ) count++;
00860 if ( thin_[x ][y-1] > thresh_[x ][y-1] ) count++;
00861 if ( thin_[x+1][y-1] > thresh_[x+1][y-1] ) count++;
00862 if ( thin_[x+1][y ] > thresh_[x+1][y ] ) count++;
00863 if ( thin_[x+1][y+1] > thresh_[x+1][y+1] ) count++;
00864 if ( thin_[x ][y+1] > thresh_[x ][y+1] ) count++;
00865 if ( thin_[x-1][y+1] > thresh_[x-1][y+1] ) count++;
00866 if ( thin_[x-1][y ] > thresh_[x-1][y ] ) count++;
00867
00868 if ( count > 2 ) {
00869 xjunc_->push_front(x);
00870 yjunc_->push_front(y);
00871 junction_[x][y] = 1;
00872 }
00873 }
00874 }
00875
00876
00877
00878
00879
00880
00881
00882 void osl_edge_detector::Find_junction_clusters()
00883 {
00884 vcl_list<int> xcoords,ycoords,xvertices,yvertices,xjunc,yjunc;
00885
00886
00887 xvertices.clear();
00888 yvertices.clear();
00889 xjunc.clear();
00890 yjunc.clear();
00891 for (unsigned int x=width_; x+width_<xsize_; ++x)
00892 {
00893 for (unsigned int y=width_; y+width_<ysize_; ++y)
00894 {
00895 if ( junction_[x][y] )
00896 {
00897
00898 xcoords.clear(); ycoords.clear();
00899 Follow_junctions(x,y,&xcoords,&ycoords);
00900
00901
00902
00903 int x0, y0;
00904 Cluster_centre(xcoords,ycoords,x0,y0);
00905
00906
00907
00908 xvertices.push_front(x0);
00909 yvertices.push_front(y0);
00910 xjunc.insert(xjunc.begin(), xcoords.begin(), xcoords.end());
00911 yjunc.insert(yjunc.begin(), ycoords.begin(), ycoords.end());
00912 }
00913 }
00914 }
00915
00916
00917
00918
00919 while ( xjunc.size() ) {
00920 junction_[xjunc.front()][yjunc.front()] = 1;
00921 xjunc.pop_front();
00922 yjunc.pop_front();
00923 }
00924
00925
00926 vlist_->clear();
00927 for (vcl_list<int>::iterator i=xvertices.begin(), j=yvertices.begin();
00928 i!=xvertices.end() && j!=yvertices.end();
00929 ++i, ++j) {
00930
00931 osl_Vertex *v = new osl_Vertex( float((*i)+xstart_),
00932 float((*j)+ystart_));
00933 vlist_->push_front(v);
00934 junction_[(*i)][(*j)] = 2;
00935 }
00936
00937 xvertices.clear();
00938 yvertices.clear();
00939 }
00940
00941
00942
00943
00944
00945
00946 void osl_edge_detector::Follow_junctions(int x, int y, vcl_list<int> *xc, vcl_list<int> *yc)
00947 {
00948
00949
00950 xc->push_front(x);
00951 yc->push_front(y);
00952 junction_[x][y] = 0;
00953
00954
00955
00956
00957
00958 #define smoo(a, b) \
00959 if ( junction_[a][b] ) Follow_junctions(a,b, xc,yc);
00960 smoo(x , y-1)
00961 smoo(x-1, y )
00962 smoo(x , y+1)
00963 smoo(x+1, y )
00964 smoo(x+1, y-1)
00965 smoo(x-1, y-1)
00966 smoo(x-1, y+1)
00967 smoo(x+1, y+1)
00968 #undef smoo
00969 }
00970
00971
00972
00973
00974
00975
00976
00977 void osl_edge_detector::Cluster_centre(vcl_list<int> &xc,
00978 vcl_list<int> &yc,
00979 int &x0,
00980 int &y0)
00981 {
00982 if ( xc.empty() )
00983 return;
00984
00985 #if 0 // commented out
00986
00987 double x=0.0,y=0.0;
00988 for (xc.reset(),yc.reset(); xc.next(),yc.next(); )
00989 {
00990 x += xc.value(); y += yc.value();
00991 }
00992 x /= xc.size(); y /= yc.size();
00993
00994
00995 float dist,newdist;
00996 dist = xsize_*ysize_;
00997 for (xc.reset(),yc.reset(); xc.next(),yc.next(); )
00998 if ( (newdist=hypot(x-xc.value(),y-yc.value())) < dist )
00999 {
01000 x0 = xc.value(); y0 = yc.value();
01001 dist = newdist;
01002 }
01003 #endif
01004
01005 typedef vcl_list<int>::iterator it;
01006
01007
01008 float grad = -1.0;
01009 for (it i=xc.begin(),j=yc.begin(); i!=xc.end() && j!=yc.end(); ++i, ++j)
01010
01011 if ( grad_[(*i)][(*j)] > grad ) {
01012 grad = grad_[(*i)][(*j)];
01013 x0 = (*i);
01014 y0 = (*j);
01015 }
01016
01017
01018 for (it i=xc.begin(), j=yc.begin(); i!=xc.end() && j!=yc.end(); ++i, ++j) {
01019
01020 jx_[(*i)][(*j)] = x0;
01021 jy_[(*i)][(*j)] = y0;
01022 }
01023 }
01024
01025
01026