00001
00002 #include "osl_canny_rothwell.h"
00003
00004
00005
00006 #include <osl/osl_canny_rothwell_params.h>
00007 #include <osl/osl_kernel.h>
00008 #include <osl/osl_canny_smooth.h>
00009 #include <osl/osl_canny_gradient.h>
00010 #include <vnl/vnl_math.h>
00011
00012 #include <vcl_list.h>
00013 #include <vcl_cmath.h>
00014 #include <vcl_cstdlib.h>
00015 #include <vcl_cstdio.h>
00016 #include <vcl_iostream.h>
00017 #include <vcl_cassert.h>
00018
00019 const float DUMMYTHETA = 10000.0;
00020
00021
00022
00023 osl_canny_rothwell::osl_canny_rothwell(osl_canny_rothwell_params const ¶ms)
00024 : osl_canny_base(params.sigma, params.low, params.high, params.verbose)
00025 {
00026
00027 range_ = params.range;
00028 gauss_tail_ = 0.01f;
00029 width_ = int(sigma_*vcl_sqrt(2*vcl_log(1/gauss_tail_))+1);
00030 w0_ = width_;
00031 k_size_ = 2*width_+ 1;
00032 kernel_ = new float[k_size_];
00033
00034 xdang_ = new vcl_list<int>;
00035 ydang_ = new vcl_list<int>;
00036 xjunc_ = new vcl_list<int>;
00037 yjunc_ = new vcl_list<int>;
00038 vlist_ = new vcl_list<osl_Vertex*>;
00039
00040 dummy_ = 1000.0;
00041 jval_ = 2000.0;
00042 }
00043
00044
00045
00046 osl_canny_rothwell::~osl_canny_rothwell()
00047 {
00048 osl_canny_base_free_raw_image(smooth_);
00049 osl_canny_base_free_raw_image(dx_);
00050 osl_canny_base_free_raw_image(dy_);
00051 osl_canny_base_free_raw_image(grad_);
00052
00053 osl_canny_base_free_raw_image(thick_);
00054 osl_canny_base_free_raw_image(thin_);
00055 osl_canny_base_free_raw_image(theta_);
00056
00057 osl_canny_base_free_raw_image(dangling_);
00058 osl_canny_base_free_raw_image(junction_);
00059 osl_canny_base_free_raw_image(jx_);
00060 osl_canny_base_free_raw_image(jy_);
00061
00062
00063 delete vlist_;
00064 delete [] kernel_;
00065 delete xdang_;
00066 delete ydang_;
00067 delete xjunc_;
00068 delete yjunc_;
00069 }
00070
00071
00072
00073
00074 void osl_canny_rothwell::detect_edges(vil1_image const &image, vcl_list<osl_edge*> *edges, bool adaptive)
00075 {
00076 assert(edges!=0);
00077
00078 xsize_ = image.height();
00079 ysize_ = image.width();
00080 xstart_ = 0;
00081 ystart_ = 0;
00082
00083 if (verbose)
00084 vcl_cerr << "Doing Canny on image region "
00085 << xsize_ << " by " << ysize_ << vcl_endl
00086 << "Gaussian tail = " << gauss_tail_ << vcl_endl
00087 << "Sigma = " << sigma_ << vcl_endl
00088 << "Kernel size = " << k_size_ << vcl_endl
00089 << "Upper threshold = " << high_ << vcl_endl
00090 << "Lower threshold = " << low_ << vcl_endl
00091 << "Smoothing range = " << range_ << vcl_endl << vcl_endl;
00092
00093 smooth_ = osl_canny_base_make_raw_image(xsize_, ysize_, (float*)0);
00094 dx_ = osl_canny_base_make_raw_image(xsize_, ysize_, (float*)0);
00095 dy_ = osl_canny_base_make_raw_image(xsize_, ysize_, (float*)0);
00096 grad_ = osl_canny_base_make_raw_image(xsize_, ysize_, (float*)0);
00097 thick_ = osl_canny_base_make_raw_image(xsize_, ysize_, (float*)0);
00098 thin_ = osl_canny_base_make_raw_image(xsize_, ysize_, (float*)0);
00099 theta_ = osl_canny_base_make_raw_image(xsize_, ysize_, (float*)0);
00100 dangling_ = osl_canny_base_make_raw_image(xsize_, ysize_, (int*)0);
00101 junction_ = osl_canny_base_make_raw_image(xsize_, ysize_, (int*)0);
00102 jx_ = osl_canny_base_make_raw_image(xsize_, ysize_, (int*)0);
00103 jy_ = osl_canny_base_make_raw_image(xsize_, ysize_, (int*)0);
00104
00105 osl_canny_base_fill_raw_image(theta_ ,xsize_, ysize_, DUMMYTHETA);
00106 osl_canny_base_fill_raw_image(smooth_,xsize_, ysize_, 0.0f);
00107 osl_canny_base_fill_raw_image(dx_, xsize_, ysize_, 0.0f);
00108 osl_canny_base_fill_raw_image(dy_, xsize_, ysize_, 0.0f);
00109 osl_canny_base_fill_raw_image(grad_, xsize_, ysize_, 0.0f);
00110 osl_canny_base_fill_raw_image(thick_, xsize_, ysize_, 0.0f);
00111 osl_canny_base_fill_raw_image(thin_, xsize_, ysize_, 0.0f);
00112
00113
00114 if (verbose) vcl_cerr << "setting convolution kernel and zeroing images\n";
00115 osl_kernel_DOG(sigma_, kernel_, k_size_, width_);
00116
00117 if (verbose) vcl_cerr << "smoothing the image\n";
00118 osl_canny_smooth_rothwell(image, kernel_, width_, k_size_, smooth_);
00119
00120 if (verbose) vcl_cerr << "computing derivatives\n";
00121 osl_canny_gradient_central(xsize_, ysize_, smooth_, dx_, dy_, grad_);
00122
00123 if (verbose) vcl_cerr << "doing non-maximal suppression\n";
00124 Non_maximal_suppression();
00125
00126
00127 if (verbose) vcl_cerr << "thinning edges\n";
00128 osl_canny_base_copy_raw_image(VCL_OVERLOAD_CAST(float const*const*, thick_),
00129 VCL_OVERLOAD_CAST(float *const*, thin_), xsize_, ysize_);
00130 Thin_edges();
00131
00132 if (verbose) vcl_cerr << "doing hysteresis\n";
00133 Initial_hysteresis();
00134
00135 if ( adaptive ) {
00136
00137
00138
00139 double min_sigma = range_ / vcl_sqrt(-2.0*vcl_log(gauss_tail_));
00140 if (verbose) vcl_cerr << "\nadaptive Canny with smoothing sigma bound = " << min_sigma << vcl_endl;
00141
00142
00143 if (verbose) vcl_cerr << "searching for dangling ends\n";
00144 Find_dangling_ends();
00145 if (verbose) vcl_cerr << xdang_->size() << " dangling edges found initially\n"
00146 << "looking for single pixel breaks - ";
00147 Jump_single_breaks();
00148 Thin_edges();
00149 Find_dangling_ends();
00150 if (verbose) vcl_cerr << xdang_->size() << " dangling edges found after joining\n";
00151
00152 while ( sigma_ > min_sigma ) {
00153
00154 if (verbose) vcl_cerr << "computing current junction set";
00155 Find_junctions();
00156
00157 if (verbose) vcl_cerr << "\nrunning adaptive Canny\n";
00158 Adaptive_Canny(image);
00159
00160
00161 if (verbose) vcl_cerr << "thinning edges - reprise\n";
00162 Thin_edges();
00163
00164 Find_dangling_ends();
00165 if (verbose) vcl_cerr << xdang_->size() << " dangling edges found after scale reduction\n"
00166 << "looking for single pixel breaks - ";
00167 Jump_single_breaks();
00168 Thin_edges();
00169 Find_dangling_ends();
00170 if (verbose) vcl_cerr << xdang_->size() << " dangling edges found after re-joining\n";
00171 }
00172 }
00173
00174
00175 if (verbose) vcl_cerr << "locating junctions in the edge image - ";
00176 Find_junctions();
00177 if (verbose) vcl_cerr << xjunc_->size() << " junctions found\n";
00178 Find_junction_clusters();
00179 if (verbose) vcl_cerr << vlist_->size() << " junction clusters found\n";
00180
00181
00182 if (verbose) vcl_cerr << "doing final edge following\n";
00183 Final_hysteresis(edges);
00184 if (verbose) vcl_cerr << "finished Canny\n";
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 void osl_canny_rothwell::Non_maximal_suppression()
00198 {
00199 float h1=0,h2=0;
00200 float k = float(vnl_math::deg_per_rad);
00201
00202
00203 for (unsigned int x=w0_; x+2+w0_<xsize_; ++x) {
00204 float *g0 = grad_[x];
00205 float *g1 = grad_[x+1];
00206 float *g2 = grad_[x+2];
00207 float *dx = dx_[x+1];
00208 float *dy = dy_[x+1];
00209
00210 for (unsigned int y=w0_; y+2+w0_<ysize_; ++y) {
00211
00212 if ( g1[y+1] > low_ ) {
00213 double theta = k*vcl_atan2(dy[y+1],dx[y+1]);
00214
00215
00216
00217 int orient = int(theta/45.0+8) % 4;
00218
00219
00220 float grad;
00221 switch ( orient ) {
00222 case 0:
00223 grad = dy[y+1]/dx[y+1];
00224 h1 = grad*g0[y] + (1 - grad)*g0[y+1];
00225 h2 = grad*g2[y] + (1 - grad)*g2[y+1];
00226 break;
00227 case 1:
00228 grad = dx[y+1]/dy[y+1];
00229 h1 = grad*g0[y] + (1 - grad)*g1[y];
00230 h2 = grad*g2[y] + (1 - grad)*g1[y];
00231 break;
00232 case 2:
00233 grad = -dx[y+1]/dy[y+1];
00234 h1 = grad*g2[y] + (1 - grad)*g1[y];
00235 h2 = grad*g0[y] + (1 - grad)*g1[y];
00236 break;
00237 case 3:
00238 grad = -dy[y+1]/dx[y+1];
00239 h1 = grad*g2[y] + (1 - grad)*g2[y+1];
00240 h2 = grad*g0[y] + (1 - grad)*g0[y+1];
00241 break;
00242 default:
00243 vcl_cerr << "*** ERROR ON SWITCH IN NMS ***: orient="<< orient<< '\n';
00244 vcl_abort();
00245 }
00246
00247
00248
00249
00250 if ( (g1[y+1]>h1) && (g1[y+1]>h2) )
00251 {
00252 float fraction = (h1-h2)/(2*(h1-2*g1[y+1]+h2));
00253 float newx=0.f, newy=0.f;
00254 switch ( orient ) {
00255 case 0:
00256 newx = x + fraction;
00257 newy = y + dy[y+1]/dx[y+1]*fraction;
00258 break;
00259 case 1:
00260 newx = x + dx[y+1]/dy[y+1]*fraction;
00261 newy = y + fraction;
00262 break;
00263 case 2:
00264 newx = x + dx[y+1]/dy[y+1]*fraction;
00265 newy = y + fraction;
00266 break;
00267 case 3:
00268 newx = x - fraction;
00269 newy = y - dy[y+1]/dx[y+1]*fraction;
00270 break;
00271 default:
00272 vcl_cerr<<"*** ERROR ON SWITCH IN NMS ***: orient="<< orient<< '\n';
00273 vcl_abort();
00274 }
00275
00276
00277
00278
00279
00280 thick_[x+1][y+1] = g1[y+1];
00281 dx[y+1] = newx + 1.5f;
00282 dy[y+1] = newy + 1.5f;
00283 theta_[x+1][y+1] = float(theta);
00284 }
00285 }
00286 }
00287 }
00288 }
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299 void osl_canny_rothwell::Initial_hysteresis()
00300 {
00301 vcl_list<int> xcoords,ycoords;
00302 vcl_list<float> grad;
00303 vcl_list<osl_edgel_chain*> edges;
00304 float *thin,*px,*py,*pg;
00305 osl_edgel_chain *edgels;
00306
00307
00308
00309
00310
00311 edges.clear();
00312 for (unsigned int x=w0_; x+w0_<xsize_; ++x) {
00313 thin = thin_[x];
00314 for (unsigned int y=w0_; y+w0_<ysize_; ++y)
00315 if ( thin[y]>high_ ) {
00316 Initial_follow(thin_, xsize_, ysize_, low_,
00317 x,y,&xcoords,&ycoords,&grad);
00318
00319
00320 edgels = new osl_edgel_chain(xcoords.size());
00321 px = edgels->GetX();
00322 py = edgels->GetY();
00323 pg = edgels->GetGrad();
00324 while ( xcoords.size() ) {
00325 *(px++) = float(xcoords.front()); xcoords.pop_front();
00326 *(py++) = float(ycoords.front()); ycoords.pop_front();
00327 *(pg++) = grad.front(); grad.pop_front();
00328 }
00329 edges.push_front(edgels);
00330 }
00331 }
00332
00333
00334 osl_canny_base_fill_raw_image(thin_, xsize_, ysize_, 0.0f);
00335 while (edges.size()) {
00336
00337 edgels = edges.front(); edges.pop_front();
00338 px = edgels->GetX();
00339 py = edgels->GetY();
00340 pg = edgels->GetGrad();
00341 for (unsigned int i=0; i<edgels->size(); ++i)
00342 thin_[int(px[i])][int(py[i])] = pg[i];
00343 delete edgels;
00344 }
00345 }
00346
00347
00348
00349
00350
00351 extern osl_Vertex *osl_find(vcl_list<osl_Vertex*> const *l, osl_Vertex const &v);
00352 extern osl_Vertex *osl_find(vcl_list<osl_Vertex*> const *l, float x, float y);
00353
00354
00355
00356
00357
00358
00359
00360 void osl_canny_rothwell::Final_hysteresis(vcl_list<osl_edge*> *edges)
00361 {
00362 vcl_list<int> xcoords,ycoords;
00363 vcl_list<float> grad;
00364 float *thin,*px,*py,*pg,*pt,val;
00365
00366 chain_no_ = 10;
00367
00368
00369 edges->clear();
00370 for (unsigned int x=w0_; x+w0_<xsize_; ++x) {
00371 thin = thin_[x];
00372 for (unsigned int y=w0_; y+w0_<ysize_; ++y) {
00373
00374 if ( thin[y]<=low_ || junction_[x][y] )
00375 continue;
00376
00377
00378 chain_no_++;
00379
00380
00381 xcoords.clear();
00382 ycoords.clear();
00383 grad.clear();
00384
00385
00386 Final_follow(x,y, &xcoords,&ycoords,&grad, 0);
00387
00388
00389
00390
00391 xcoords.reverse();
00392 ycoords.reverse();
00393 grad.reverse();
00394 Final_follow(x,y,&xcoords,&ycoords,&grad,1);
00395
00396
00397
00398 if ( xcoords.size() < 2 )
00399
00400 continue;
00401
00402
00403 int count=0;
00404 for (vcl_list<float>::iterator i=grad.begin(); i!=grad.end(); ++i)
00405 if ( (*i) != dummy_ )
00406 count++;
00407
00408
00409
00410
00411 if ( count < 2 )
00412 continue;
00413
00414
00415 osl_edgel_chain *dc = new osl_edgel_chain(count);
00416 px = dc->GetX(); py = dc->GetY();
00417 pg = dc->GetGrad(); pt = dc->GetTheta();
00418
00419
00420
00421 while (count) {
00422 int tmpx = xcoords.front(); xcoords.pop_front();
00423 int tmpy = ycoords.front(); ycoords.pop_front();
00424 val = grad.front(); grad.pop_front();
00425 if ( val != dummy_ ) {
00426 --count;
00427
00428 if ( val != jval_ ) {
00429 *(px++) = dx_[tmpx][tmpy] + xstart_;
00430 *(py++) = dy_[tmpx][tmpy] + ystart_;
00431 *(pg++) = val;
00432 }
00433 else {
00434 *(px++) = float(tmpx + xstart_);
00435 *(py++) = float(tmpy + ystart_);
00436 *(pg++) = 0.0f;
00437 }
00438 if (theta_[tmpx][tmpy] == DUMMYTHETA) {
00439 const float k = float(vnl_math::deg_per_rad);
00440 float *dx = dx_[tmpx];
00441 float *dy = dy_[tmpx];
00442
00443
00444
00445 theta_[tmpx][tmpy] = k*(float)vcl_atan2(dy[tmpy],dx[tmpy]);
00446 }
00447
00448 *(pt++) = theta_[tmpx][tmpy];
00449 }
00450
00451 }
00452
00453
00454
00455 if ( (dc->size()==2) &&
00456 (dc->GetX(0)==dc->GetX(1)) &&
00457 (dc->GetY(0)==dc->GetY(1)) ) {
00458 delete dc;
00459 continue;
00460 }
00461
00462 else if ( dc->size() > 1 ) {
00463
00464
00465 osl_Vertex *v1 = new osl_Vertex(dc->GetX(0), dc->GetY(0));
00466 osl_Vertex *v2 = new osl_Vertex(dc->GetX(dc->size()-1), dc->GetY(dc->size()-1));
00467
00468
00469 osl_Vertex *V1=osl_find(vlist_, *v1);
00470 osl_Vertex *V2=osl_find(vlist_, *v2);
00471
00472
00473
00474 bool single_chain = false;
00475 if ( !V1 && !V2 ) {
00476
00477 float dx = dc->GetX(0) - dc->GetX(dc->size()-1);
00478 float dy = dc->GetY(0) - dc->GetY(dc->size()-1);
00479 if ( dx*dx+dy*dy < 4 ) {
00480 V1 = v1;
00481 V2 = v1;
00482 osl_IUDelete(v2);
00483 single_chain = true;
00484 }
00485 }
00486 if ( !single_chain ) {
00487 if ( !V1 )
00488 V1 = v1;
00489 else
00490 { osl_IUDelete (v1); }
00491 if ( !V2 )
00492 V2 = v2;
00493 else
00494 { osl_IUDelete(v2); }
00495 }
00496
00497
00498
00499
00500
00501
00502 edges->push_front(new osl_edge(*dc, V1, V2));
00503 delete dc;
00504 }
00505
00506 }
00507 }
00508 }
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 void osl_canny_rothwell::Thin_edges()
00520 {
00521
00522
00523 float threshold=dummy_-0.001f;
00524
00525 for (int i=0; i<2; threshold=low_,++i)
00526 {
00527 int count = 1;
00528 while (count)
00529 {
00530 count = 0;
00531 for (unsigned int x=w0_; x+w0_<xsize_; ++x)
00532 for (unsigned int y=w0_; y+w0_<ysize_; ++y)
00533 {
00534 if ( thin_[x][y] <= threshold )
00535 continue;
00536
00537 int a = thin_[x-1][y-1] > low_ ? 1 : 0;
00538 int b = thin_[x ][y-1] > low_ ? 1 : 0;
00539 int c = thin_[x+1][y-1] > low_ ? 1 : 0;
00540 int d = thin_[x+1][y ] > low_ ? 1 : 0;
00541 int e = thin_[x+1][y+1] > low_ ? 1 : 0;
00542 int f = thin_[x ][y+1] > low_ ? 1 : 0;
00543 int g = thin_[x-1][y+1] > low_ ? 1 : 0;
00544 int h = thin_[x-1][y ] > low_ ? 1 : 0;
00545
00546 int genus = a+b+c+d+e+f+g+h;
00547
00548
00549 if ( genus == 1 )
00550 continue;
00551
00552 genus += h*a*b+b*c*d+d*e*f+f*g*h-a*b-b*c-c*d-d*e-e*f-f*g
00553 - g*h-h*a-h*b-b*d-d*f-f*h-1;
00554
00555
00556 if ( genus == 0 ) {
00557 ++count;
00558 thin_[x][y] = 0.0;
00559 }
00560 }
00561 }
00562 }
00563 }
00564
00565
00566
00567
00568
00569
00570
00571 void osl_canny_rothwell::Jump_single_breaks()
00572 {
00573
00574
00575
00576 int x,y,i,j;
00577 float **t = thin_;
00578
00579
00580 while (xdang_->size()) {
00581
00582 x = xdang_->front(); xdang_->pop_front();
00583 y = ydang_->front(); ydang_->pop_front();
00584
00585
00586 if (thin_[x-1][y-1]) {i=-1; j=-1;}
00587 else if (thin_[x ][y-1]) {i= 0; j=-1;}
00588 else if (thin_[x+1][y-1]) {i= 1; j=-1;}
00589 else if (thin_[x+1][y ]) {i= 1; j= 0;}
00590 else if (thin_[x+1][y+1]) {i= 1; j= 1;}
00591 else if (thin_[x ][y+1]) {i= 0; j= 1;}
00592 else if (thin_[x-1][y+1]) {i=-1; j= 1;}
00593 else if (thin_[x-1][y ]) {i=-1; j= 0;}
00594 else { i = j = 0; }
00595
00596
00597 if ( i && j ) {
00598
00599 if (t[x-2*i][y-2*j]>low_) {
00600 t[x-i][y-j]=dummy_;thick_[x-i][y-j]=dummy_;}
00601 else if ((t[x+i][y-2*j]>low_)||(t[x ][y-2*j]>low_)||(t[x-i][y-2*j]>low_)) {
00602 t[x ][y-j]=dummy_;thick_[x ][y-j]=dummy_;}
00603 else if ((t[x-2*i][y+j]>low_)||(t[x-2*i][y ]>low_)||(t[x-2*i][y-j]>low_)) {
00604 t[x-i][y]=dummy_;thick_[x-i][y ]=dummy_;}
00605 else if ((!(t[x+2*i][y ]>low_))&&((t[x+2*i][y-j]>low_)||(t[x+2*i][y-2*j]>low_))) {
00606 t[x+i][y-j]=dummy_;thick_[x+i][y-j]=dummy_;}
00607 else if ((!(t[x ][y+2*j]>low_))&&((t[x-i][y+2*j]>low_)||(t[x-2*i][y+2*j]>low_))) {
00608 t[x-i][y+j]=dummy_;thick_[x-i][y+j]=dummy_;}
00609 }
00610
00611
00612 else if ( i == 0 ) {
00613
00614 if ((t[x-1][y-2*j]>low_)||(t[x ][y-2*j]>low_)||(t[x+1][y-2*j]>low_)) {
00615 t[x ][y-j]=dummy_;thick_[x ][y-j]=dummy_;}
00616 else if ((t[x+2][y-j]>low_)||(t[x+2][y-2*j]>low_)) {
00617 t[x+1][y-j]=dummy_;thick_[x+1][y-j]=dummy_;}
00618 else if ((t[x-2][y-j]>low_)||(t[x-2][y-2*j]>low_)) {
00619 t[x-1][y-j]=dummy_;thick_[x-1][y-j]=dummy_;}
00620 else if ((!(t[x-2][y+j]>low_))&&(t[x-2][y]>low_)) {
00621 t[x-1][y ]=dummy_;thick_[x-1][y ]=dummy_;}
00622 else if ((!(t[x+2][y+j]>low_))&&(t[x+2][y]>low_)) {
00623 t[x+1][y ]=dummy_;thick_[x+1][y ]=dummy_;}
00624 }
00625
00626
00627
00628
00629 else if ( j == 0 ) {
00630
00631 if ((t[x-2*i][y-1]>low_)||(t[x-2*i][y]>low_)||(t[x-2*i][y]>low_)) {
00632 t[x-i][y]=dummy_;thick_[x-i][y]=dummy_;}
00633 else if ((t[x-i][y+2]>low_)||(t[x-2*i][y+2]>low_)) {
00634 t[x-1][y+j]=dummy_;thick_[x-1][y+j]=dummy_;}
00635 else if ((t[x-i][y-2]>low_)||(t[x-2*i][y-2]>low_)) {
00636 t[x-1][y-j]=dummy_;thick_[x-1][y-j]=dummy_;}
00637 else if ((!(t[x+i][y-2]>low_))&&(t[x][y-2]>low_)) {
00638 t[x][y-1]=dummy_;thick_[x][y-1]=dummy_;}
00639 else if ((!(t[x+i][y+2]>low_))&&(t[x][y+2]>low_)) {
00640 t[x][y+1]=dummy_;thick_[x][y+1]=dummy_;}
00641 }
00642 }
00643 }
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654 void osl_canny_rothwell::Adaptive_Canny(vil1_image const &image)
00655 {
00656
00657
00658 old_sigma_ = sigma_; sigma_ /= 2.0f;
00659 old_width_ = width_;
00660 width_ = int(sigma_*vcl_sqrt(2*vcl_log(1.0/gauss_tail_))+1);
00661 old_k_size_ = k_size_; k_size_ = 2*width_+ 1;
00662 delete kernel_; kernel_ = new float [k_size_];
00663 osl_kernel_DOG(sigma_, kernel_, k_size_, width_);
00664
00665
00666
00667 int image_size = old_k_size_ + k_size_ - 1;
00668 int half_size = (image_size - 1)/2;
00669
00670 if (verbose) vcl_cerr << "new image region "
00671 << image_size << " by " << image_size << vcl_endl
00672 << "Sigma = " << sigma_ << vcl_endl
00673 << "Kernel size = " << k_size_ << vcl_endl;
00674
00675
00676 float **dx = osl_canny_base_make_raw_image(image_size,image_size, (float*)0);
00677 float **dy = osl_canny_base_make_raw_image(image_size,image_size, (float*)0);
00678 float **grad = osl_canny_base_make_raw_image(image_size,image_size, (float*)0);
00679
00680
00681 int count=0;
00682 if (verbose) vcl_cerr << "percentage of endings examined = 0";
00683 typedef vcl_list<int>::iterator it;
00684 for (it i=xdang_->begin(), j=ydang_->begin(); i!=xdang_->end() && j!=ydang_->end(); ++i, ++j)
00685 {
00686
00687
00688 int X = (*i), Y = (*j);
00689 int x0 = X-half_size, y0 = Y - half_size;
00690
00691
00692
00693
00694
00695
00696 if ( !Junction_neighbour(junction_, X, Y) &&
00697 (x0>=0) && ((unsigned int)x0+image_size<=xsize_) &&
00698 (y0>=0) && ((unsigned int)y0+image_size<=ysize_) )
00699 {
00700
00701 osl_canny_smooth_rothwell_adaptive(image, x0,y0,image_size, kernel_, width_, k_size_, dx,dy,grad);
00702
00703
00704
00705 Subtract_thick(x0,y0,image_size,grad);
00706
00707
00708
00709 int newx,newy;
00710 X -= x0; Y -= y0;
00711 for (int ii=1; ii<=old_k_size_ && Dangling_end(X+x0,Y+y0)==1; ++ii)
00712 {
00713
00714 newx = X; newy = Y;
00715 Best_eight_way(X,Y,grad,&newx,&newy);
00716
00717 if ( (newx==X) && (newy==Y) )
00718 break;
00719
00720 else {
00721 thin_[newx+x0][newy+y0] = dummy_; thick_[newx+x0][newy+y0] = dummy_;
00722 X = newx; Y = newy;
00723 }
00724 }
00725 }
00726 if (verbose) vcl_fprintf(stderr,"\b\b\b%3d", int(10*((++count)*10/xdang_->size())));
00727 }
00728 if (verbose) vcl_cerr << vcl_endl;
00729
00730
00731 osl_canny_base_free_raw_image(dx);
00732 osl_canny_base_free_raw_image(dy);
00733 osl_canny_base_free_raw_image(grad);
00734 }
00735
00736
00737
00738
00739
00740 void osl_canny_rothwell::Subtract_thick(int x0, int y0, int image_size, float **grad)
00741 {
00742 for (int x=width_; x<image_size-width_; ++x)
00743 for (int y=width_; y<image_size-width_; ++y)
00744 if ( thick_[x+x0][y+y0] > low_ )
00745 grad[x][y] = 0.0f;
00746 }
00747
00748
00749
00750
00751
00752
00753
00754
00755 void osl_canny_rothwell::Best_eight_way(int x, int y, float **grad, int *xnew, int *ynew)
00756 {
00757 float max = low_;
00758 if ( grad[x-1][y-1] > max ) { *xnew = x-1; *ynew = y-1; }
00759 if ( grad[x ][y-1] > max ) { *xnew = x; *ynew = y-1; }
00760 if ( grad[x+1][y-1] > max ) { *xnew = x+1; *ynew = y-1; }
00761 if ( grad[x+1][y ] > max ) { *xnew = x+1; *ynew = y; }
00762 if ( grad[x+1][y+1] > max ) { *xnew = x+1; *ynew = y+1; }
00763 if ( grad[x ][y+1] > max ) { *xnew = x; *ynew = y+1; }
00764 if ( grad[x-1][y+1] > max ) { *xnew = x-1; *ynew = y+1; }
00765 if ( grad[x-1][y ] > max ) { *xnew = x-1; *ynew = y; }
00766
00767
00768 for (int j=y-1; j<=y+1; ++j)
00769 for (int i=x-1; i<=x+1; ++i)
00770 grad[i][j] = 0.0;
00771 }
00772
00773
00774
00775
00776
00777
00778 void osl_canny_rothwell::Find_dangling_ends()
00779 {
00780
00781 xdang_->clear();
00782 ydang_->clear();
00783 osl_canny_base_fill_raw_image(dangling_, xsize_, ysize_, 0);
00784
00785 for (unsigned int x=w0_; x+w0_<xsize_; ++x)
00786 for (unsigned int y=w0_; y+w0_<ysize_; ++y)
00787 {
00788 if (Dangling_end(x,y) == 1) {
00789 xdang_->push_front(x);
00790 ydang_->push_front(y);
00791 dangling_[x][y] = 1;
00792 }
00793 }
00794 }
00795
00796
00797
00798
00799
00800
00801
00802 int osl_canny_rothwell::Dangling_end(int x, int y)
00803 {
00804 if ( thin_[x][y] <= low_ )
00805 return 0;
00806
00807 int a = thin_[x-1][y-1] > low_ ? 1 : 0;
00808 int b = thin_[x ][y-1] > low_ ? 1 : 0;
00809 int c = thin_[x+1][y-1] > low_ ? 1 : 0;
00810 int d = thin_[x+1][y ] > low_ ? 1 : 0;
00811 int e = thin_[x+1][y+1] > low_ ? 1 : 0;
00812 int f = thin_[x ][y+1] > low_ ? 1 : 0;
00813 int g = thin_[x-1][y+1] > low_ ? 1 : 0;
00814 int h = thin_[x-1][y ] > low_ ? 1 : 0;
00815
00816 return a+b+c+d+e+f+g+h;
00817 }
00818
00819
00820
00821
00822
00823
00824 void osl_canny_rothwell::Find_junctions()
00825 {
00826
00827 xjunc_->clear();
00828 yjunc_->clear();
00829 osl_canny_base_fill_raw_image(junction_, xsize_, ysize_, 0);
00830
00831 for (unsigned int x=w0_; x+w0_<xsize_; ++x)
00832 for (unsigned int y=w0_; y+w0_<ysize_; ++y)
00833 {
00834 if (Dangling_end(x,y) > 2) {
00835 xjunc_->push_front(x);
00836 yjunc_->push_front(y);
00837 junction_[x][y] = 1;
00838 }
00839 }
00840 }
00841
00842
00843
00844
00845
00846
00847 void osl_canny_rothwell::Find_junction_clusters()
00848 {
00849 vcl_list<int> xcoords,ycoords,xvertices,yvertices,xjunc,yjunc;
00850
00851 xvertices.clear(); yvertices.clear();
00852 xjunc.clear(); yjunc.clear();
00853 for (unsigned int x=w0_; x+w0_<xsize_; ++x)
00854 for (unsigned int y=w0_; y+w0_<ysize_; ++y)
00855 if ( junction_[x][y] ) {
00856
00857
00858 xcoords.clear(); ycoords.clear();
00859 Follow_junctions(junction_, x,y,&xcoords,&ycoords);
00860
00861
00862
00863 int x0,y0;
00864 Cluster_centre_of_gravity(jx_, jy_, xcoords,ycoords,x0,y0);
00865
00866
00867
00868 xvertices.push_front(x0);
00869 yvertices.push_front(y0);
00870 xjunc.insert(xjunc.begin(), xcoords.begin(), xcoords.end());
00871 yjunc.insert(yjunc.begin(), ycoords.begin(), ycoords.end());
00872 }
00873
00874
00875
00876
00877 while ( xjunc.size() ) {
00878 junction_[xjunc.front()][yjunc.front()] = 1;
00879 xjunc.pop_front();
00880 yjunc.pop_front();
00881 }
00882
00883
00884 vlist_->clear();
00885 for (vcl_list<int>::iterator i=xvertices.begin(), j=yvertices.begin();
00886 i!=xvertices.end() && j!=yvertices.end();
00887 ++i, ++j) {
00888
00889
00890 osl_Vertex *v = new osl_Vertex( float((*i)+xstart_),
00891 float((*j)+ystart_));
00892 vlist_->push_front(v);
00893 junction_[(*i)][(*j)] = 2;
00894 }
00895
00896 xvertices.clear();
00897 yvertices.clear();
00898 }