contrib/brl/bseg/sdet/sdet_img_edge.cxx
Go to the documentation of this file.
00001 // This is brl/bseg/sdet/sdet_img_edge.cxx
00002 
00003 #include "sdet_img_edge.h"
00004 
00005 #include <sdet/sdet_detector.h>
00006 #include <bsta/bsta_gaussian_sphere.h>
00007 #include <brip/brip_vil_float_ops.h>
00008 #include <vdgl/vdgl_digital_curve.h>
00009 #include <vdgl/vdgl_edgel.h>
00010 #include <vdgl/vdgl_edgel_chain.h>
00011 #include <vdgl/vdgl_interpolator.h>
00012 #include <vdgl/vdgl_interpolator_cubic.h>
00013 #include <vdgl/vdgl_interpolator_linear.h>
00014 #include <vtol/vtol_edge_2d.h>
00015 #include <bil/algo/bil_edt.h>
00016 #include <vil/vil_convert.h>
00017 #include <vnl/algo/vnl_gaussian_kernel_1d.h>
00018 #include <vnl/algo/vnl_chi_squared.h>
00019 #include <vnl/vnl_vector_fixed.h>
00020 #include <vil/vil_new.h>
00021 #include <vnl/vnl_math.h>
00022 #include <vcl_iostream.h>
00023 #include <vcl_fstream.h>
00024 #include <vcl_cmath.h>
00025 #include <vcl_string.h>
00026 #include <vcl_vector.h>
00027 #include <vcl_cassert.h>
00028 #include <vgl/vgl_line_2d.h>
00029 #include <vsol/vsol_line_2d.h>
00030 #include <vsol/vsol_point_2d_sptr.h>
00031 #include <vsol/vsol_digital_curve_2d.h>
00032 #include <sdet/sdet_fit_lines_params.h>
00033 #include <sdet/sdet_fit_lines.h>
00034 
00035 vil_image_view<vxl_byte> sdet_img_edge::detect_edges(vil_image_view<vxl_byte> img,
00036                                                      double noise_multiplier,
00037                                                      double smooth,
00038                                                      bool automatic_threshold,
00039                                                      bool junctionp,
00040                                                      bool aggressive_junction_closure)
00041 {
00042   if ( img.nplanes() >= 3 )
00043   {
00044     vil_image_view<vxl_byte> img_rgb;
00045     img_rgb.deep_copy(img);
00046     vil_convert_planes_to_grey(img_rgb,img);
00047   }
00048 
00049   // set parameters for the edge detector
00050   sdet_detector_params dp;
00051   dp.noise_multiplier = (float)noise_multiplier;
00052   dp.smooth = (float)smooth;
00053   dp.automatic_threshold = automatic_threshold;
00054   dp.junctionp = junctionp;
00055   dp.aggressive_junction_closure = aggressive_junction_closure;
00056 
00057   // detect edgels from the input image
00058   sdet_detector detector(dp);
00059   vil_image_resource_sptr img_res_sptr = vil_new_image_resource_of_view(img);
00060   detector.SetImage(img_res_sptr);
00061   detector.DoContour();
00062   vcl_vector<vtol_edge_2d_sptr> * edges = detector.GetEdges();
00063 
00064   // initialize the output edge image
00065   vil_image_view<vxl_byte> img_edge(img.ni(),img.nj(),1);
00066   img_edge.fill(0);
00067 
00068   // iterate over each connected edge component
00069   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges->begin(); eit != edges->end(); eit++)
00070   {
00071     vsol_curve_2d_sptr c = (*eit)->curve();
00072     vdgl_digital_curve_sptr dc = c->cast_to_vdgl_digital_curve();
00073     if (!dc)
00074       continue;
00075     vdgl_interpolator_sptr intp = dc->get_interpolator();
00076     vdgl_edgel_chain_sptr ec = intp->get_edgel_chain();
00077 
00078     // iterate over each point in the connected edge component
00079     for (unsigned j=0; j<ec->size(); j++) {
00080       vdgl_edgel curr_edgel = ec->edgel(j);
00081       int cr_x = (int)curr_edgel.x();
00082       int cr_y = (int)curr_edgel.y();
00083 
00084       // set the current edge pixel in the edge image
00085       img_edge(cr_x,cr_y) = 255;
00086     }
00087   }
00088 
00089   // Following loop removes the edges in the image boundary
00090   int temp_index = img_edge.nj()-1;
00091   for (unsigned i=0; i<img_edge.ni(); i++) {
00092     img_edge(i,0) = 0;
00093     img_edge(i,temp_index) = 0;
00094   }
00095   temp_index = img_edge.ni()-1;
00096   for (unsigned j=0; j<img_edge.nj(); j++) {
00097     img_edge(0,j) = 0;
00098     img_edge(temp_index,j) = 0;
00099   }
00100   return img_edge;
00101 }
00102 
00103 static double angle_0_360(double angle)
00104 {
00105   double ang = angle;
00106   while (ang<0)
00107     ang += (2.0*vnl_math::pi);
00108   while (ang > 2.0*vnl_math::pi)
00109     ang -= (2.0*vnl_math::pi);
00110   return ang;
00111 }
00112 
00113 vil_image_view<float>
00114 sdet_img_edge::detect_edge_tangent(vil_image_view<vxl_byte> img,
00115                                    double noise_multiplier,
00116                                    double smooth,
00117                                    bool automatic_threshold,
00118                                    bool junctionp,
00119                                    bool aggressive_junction_closure)
00120 {
00121   // set parameters for the edge detector
00122   sdet_detector_params dp;
00123   dp.noise_multiplier = (float)noise_multiplier;
00124   dp.smooth = (float)smooth;
00125   dp.automatic_threshold = automatic_threshold;
00126   dp.junctionp = junctionp;
00127   dp.aggressive_junction_closure = aggressive_junction_closure;
00128 
00129   // detect edgels from the input image
00130   sdet_detector detector(dp);
00131   vil_image_resource_sptr img_res_sptr = vil_new_image_resource_of_view(img);
00132   detector.SetImage(img_res_sptr);
00133   detector.DoContour();
00134   vcl_vector<vtol_edge_2d_sptr> * edges = detector.GetEdges();
00135 
00136   // initialize the output edge image
00137   vil_image_view<float> edge_img(img.ni(),img.nj(),3);
00138   edge_img.fill(-1.0f);
00139 
00140   // iterate over each connected edge component
00141   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges->begin(); eit != edges->end(); eit++)
00142   {
00143     vsol_curve_2d_sptr c = (*eit)->curve();
00144     vdgl_digital_curve_sptr dc = c->cast_to_vdgl_digital_curve();
00145     if (!dc)
00146       continue;
00147     vdgl_interpolator_sptr intp = dc->get_interpolator();
00148     vdgl_edgel_chain_sptr ec = intp->get_edgel_chain();
00149     unsigned n = ec->size();
00150     if (n<3) continue; //can't estimate edge tangent on short chains
00151     //special case at start
00152     vdgl_edgel e0 = ec->edgel(0);
00153     vdgl_edgel e1 = ec->edgel(1);
00154     double e0x  = e0.x(), e0y = e0.y();
00155     double e1x  = e1.x(), e1y = e0.y();
00156     if (e0x<0||e0y<0) continue;
00157     double ang = angle_0_360(vcl_atan2(e1y-e0y, e1x-e0x));
00158     unsigned x0 = static_cast<unsigned>(e0x);
00159     unsigned y0 = static_cast<unsigned>(e0y);
00160     edge_img(x0, y0, 0) = static_cast<float>(e0x);
00161     edge_img(x0, y0, 1) = static_cast<float>(e0y);
00162     edge_img(x0, y0, 2) = static_cast<float>(ang);
00163     //special case at end of chain
00164     vdgl_edgel enm2 = ec->edgel(n-2);
00165     vdgl_edgel enm1 = ec->edgel(n-1);
00166     double enm2x  = enm2.x(), enm2y = enm2.y();
00167     double enm1x  = enm1.x(), enm1y = enm1.y();
00168     if (enm1x<0||enm1y<0) continue;
00169     double angnm1 = angle_0_360(vcl_atan2(enm1y-enm2y, enm1x-enm2x));
00170     unsigned xnm1 = static_cast<unsigned>(enm1x);
00171     unsigned ynm1 = static_cast<unsigned>(enm1y);
00172     edge_img(xnm1, ynm1, 0) = static_cast<float>(enm1x);
00173     edge_img(xnm1, ynm1, 1) = static_cast<float>(enm1y);
00174     edge_img(xnm1, ynm1, 2) = static_cast<float>(angnm1);
00175     // the general case
00176     for (unsigned j=1; j<n-1; j++) {
00177       vdgl_edgel pe = ec->edgel(j-1);
00178       vdgl_edgel ce = ec->edgel(j);
00179       vdgl_edgel ne = ec->edgel(j+1);
00180       double pex  = pe.x(), pey = pe.y();
00181       double cex  = ce.x(), cey = ce.y();
00182       double nex  = ne.x(), ney = ne.y();
00183       if (cex<0||cey<0) continue;
00184       double angle = angle_0_360(vcl_atan2(ney-pey, nex-pex));
00185       unsigned xc = static_cast<unsigned>(cex);
00186       unsigned yc = static_cast<unsigned>(cey);
00187       // set the current edge pixel in the edge image
00188       edge_img(xc, yc, 0) = static_cast<float>(cex);
00189       edge_img(xc, yc, 1) = static_cast<float>(cey);
00190       edge_img(xc, yc, 2) = static_cast<float>(angle);
00191     }
00192   }
00193 
00194   // Following loop removes the edges in the image boundary
00195   int temp_index = edge_img.nj()-1;
00196   for (unsigned i=0; i<edge_img.ni(); i++) {
00197     edge_img(i,0,0) = -1;     edge_img(i,0,1) = -1;
00198     edge_img(i,temp_index,0) = -1;
00199     edge_img(i,temp_index,1) = -1;
00200   }
00201   temp_index = edge_img.ni()-1;
00202   for (unsigned j=0; j<edge_img.nj(); j++) {
00203     edge_img(0,j,0) = -1;     edge_img(0,j,1) = -1;
00204     edge_img(temp_index,j,0) = -1;
00205     edge_img(temp_index,j,1) = -1;
00206   }
00207   return edge_img;
00208 }
00209 
00210 // return image has three planes as in detect_edge_tangent
00211 // Canny edge detector returns edgel chains with a linear interpolator by default, replace this interpolator with a cubic one and read the edge tangents from this interpolator
00212 vil_image_view<float>
00213 sdet_img_edge::detect_edge_tangent_interpolated(vil_image_view<vxl_byte> img,
00214                                                 double noise_multiplier,
00215                                                 double smooth,
00216                                                 bool automatic_threshold,
00217                                                 bool junctionp,
00218                                                 bool aggressive_junction_closure)
00219 {
00220   // set parameters for the edge detector
00221   sdet_detector_params dp;
00222   dp.noise_multiplier = (float)noise_multiplier;
00223   dp.smooth = (float)smooth;
00224   dp.automatic_threshold = automatic_threshold;
00225   dp.junctionp = junctionp;
00226   dp.aggressive_junction_closure = aggressive_junction_closure;
00227 
00228   // detect edgels from the input image
00229   sdet_detector detector(dp);
00230   vil_image_resource_sptr img_res_sptr = vil_new_image_resource_of_view(img);
00231   detector.SetImage(img_res_sptr);
00232   detector.DoContour();
00233   vcl_vector<vdgl_digital_curve_sptr> edges;
00234   detector.get_vdgl_edges(edges);
00235 
00236   // initialize the output edge image
00237   vil_image_view<float> edge_img(img.ni(),img.nj(),3);
00238   edge_img.fill(-1.0f);
00239 
00240   // iterate over each connected edge component
00241   //for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges->begin(); eit != edges->end(); eit++)
00242   for (unsigned ii = 0; ii < edges.size(); ii++)
00243   {
00244     vdgl_digital_curve_sptr dc = edges[ii];
00245     if (!dc)
00246       continue;
00247     vdgl_interpolator_sptr intp = dc->get_interpolator();
00248     vdgl_edgel_chain_sptr ec = intp->get_edgel_chain();
00249     unsigned n = ec->size();
00250 
00251     vdgl_interpolator_sptr cubic_intp = new vdgl_interpolator_cubic(ec);
00252     //vdgl_interpolator_sptr cubic_intp = new vdgl_interpolator_linear(ec);
00253     vcl_cout << " length: " << cubic_intp->get_length()  << vcl_endl;
00254 
00255     for (unsigned j=1; j<n-1; j++) {
00256       double cex = cubic_intp->get_x(j);
00257       double cey = cubic_intp->get_y(j);
00258 
00259       unsigned xc = static_cast<unsigned>(cex);
00260       unsigned yc = static_cast<unsigned>(cey);
00261       double angle = angle_0_360((vnl_math::pi_over_180)*cubic_intp->get_theta(j)+vnl_math::pi_over_2);
00262       //double angle = angle_0_360((vnl_math::pi_over_180)*cubic_intp->get_tangent_angle(j));
00263 
00264       edge_img(xc, yc, 0) = static_cast<float>(cex);
00265       edge_img(xc, yc, 1) = static_cast<float>(cey);
00266       edge_img(xc, yc, 2) = static_cast<float>(angle);
00267     }
00268   }
00269 
00270   // Following loop removes the edges in the image boundary
00271   int temp_index = edge_img.nj()-1;
00272   for (unsigned i=0; i<edge_img.ni(); i++) {
00273     edge_img(i,0,0) = -1;     edge_img(i,0,1) = -1;
00274     edge_img(i,temp_index,0) = -1;
00275     edge_img(i,temp_index,1) = -1;
00276   }
00277   temp_index = edge_img.ni()-1;
00278   for (unsigned j=0; j<edge_img.nj(); j++) {
00279     edge_img(0,j,0) = -1;     edge_img(0,j,1) = -1;
00280     edge_img(temp_index,j,0) = -1;
00281     edge_img(temp_index,j,1) = -1;
00282   }
00283   return edge_img;
00284 }
00285 
00286 // return image has three planes as in detect_edge_tangent
00287 vil_image_view<float>
00288 sdet_img_edge::detect_edge_line_fitted(vil_image_view<vxl_byte> img,
00289                                        double noise_multiplier,
00290                                        double smooth,
00291                                        bool automatic_threshold,
00292                                        bool junctionp,
00293                                        bool aggressive_junction_closure,
00294                                        int min_fit_length, double rms_distance)
00295 {
00296   sdet_detector_params dp;
00297 
00298   dp.noise_multiplier = (float)noise_multiplier;
00299   dp.smooth = (float)smooth;
00300   dp.automatic_threshold = automatic_threshold;
00301   dp.junctionp = junctionp;
00302   dp.aggressive_junction_closure = aggressive_junction_closure;
00303   dp.borderp = false;
00304 
00305   sdet_fit_lines_params flp;
00306   flp.min_fit_length_ = min_fit_length;
00307   flp.rms_distance_ = rms_distance;
00308 
00309   sdet_detector det(dp);
00310 
00311   vil_image_resource_sptr img_res_sptr = vil_new_image_resource_of_view(img);
00312   unsigned ni = img.ni(); unsigned nj = img.nj();
00313 
00314   // initialize the output edge image
00315   vil_image_view<float> edge_img(img.ni(),img.nj(),3);
00316   edge_img.fill(-1.0f);
00317 
00318   det.SetImage(img_res_sptr);
00319   det.DoContour();
00320   vcl_vector<vtol_edge_2d_sptr>* edges = det.GetEdges();
00321   if (!edges)
00322   {
00323     vcl_cerr << "In sdet_img_edge::detect_edge_line_fitted() - No edges found in the image\n";
00324     return edge_img;
00325   }
00326   sdet_fit_lines fl(flp);
00327   fl.set_edges(*edges);
00328   fl.fit_lines();
00329   vcl_vector<vsol_line_2d_sptr> lines = fl.get_line_segs();
00330 
00331   for (unsigned i = 0; i < lines.size(); i++) {
00332     vsol_line_2d_sptr l = lines[i];
00333     int length = (int)vcl_ceil(l->length());
00334     double angle = angle_0_360(vnl_math::pi_over_180*l->tangent_angle());
00335 #if 0
00336     vcl_cout << " line: " << i << " length: " << l->length()
00337              << " p0: (" << l->p0()->x() << ", " << l->p0()->y() << ')'
00338              << " p1: (" << l->p1()->x() << ", " << l->p1()->y() << ')'
00339              << " mid: (" << l->middle()->x() << ", " << l->middle()->y() << ")\n";
00340 #endif
00341     vcl_vector<vsol_point_2d_sptr> samples; samples.push_back(l->p0()); samples.push_back(l->p1());
00342     vsol_digital_curve_2d_sptr dc = new vsol_digital_curve_2d(samples);
00343 
00344     // now sample length many samples along the line
00345     float inc = 1.0f/(float)length;
00346     for (float index = 0.0f; index <= 1.0f; index += inc) {
00347       vgl_point_2d<double> pt = dc->interp((double)index);
00348 
00349       double cex = pt.x();
00350       double cey = pt.y();
00351       if (cex < 0 || cey < 0) continue;
00352 
00353       unsigned xc = static_cast<unsigned>(cex);
00354       unsigned yc = static_cast<unsigned>(cey);
00355       if (xc > ni || yc > nj) continue;
00356 
00357       edge_img(xc, yc, 0) = static_cast<float>(cex);
00358       edge_img(xc, yc, 1) = static_cast<float>(cey);
00359       edge_img(xc, yc, 2) = static_cast<float>(angle);
00360     }
00361   }
00362   return edge_img;
00363 }
00364 
00365 
00366 void
00367 sdet_img_edge::convert_edge_image_to_line_image(vil_image_view<float>& edge_image, vil_image_view<float>& line_image)
00368 {
00369   if (line_image.ni() != edge_image.ni() || line_image.nj() != edge_image.nj() ||
00370       line_image.nplanes() != edge_image.nplanes() || line_image.nplanes() != 3) {
00371     vcl_cerr << "In sdet_img_edge::convert_edge_image_to_line_image() -- incompatible input output image pair!\n";
00372     return;
00373   }
00374 
00375   line_image.fill(-2.0f);
00376   for (unsigned j = 0; j<line_image.nj(); ++j)
00377     for (unsigned i = 0; i<line_image.ni(); ++i) {
00378       float x = edge_image(i,j,0);
00379       float y = edge_image(i,j,1);
00380       if (x<0||y<0)
00381         continue;
00382       float angle = edge_image(i,j,2);
00383       vgl_vector_2d<float> tangent(vcl_cos(angle), vcl_sin(angle));
00384       vgl_point_2d<float> pt(x,y);
00385       vgl_line_2d<float> l(pt, tangent);
00386       float a = l.a(), b = l.b(), c = l.c();
00387       float norm = vcl_sqrt(a*a+b*b);
00388       a/=norm; b/=norm; c/=norm;
00389       line_image(i,j,0)= a;
00390       line_image(i,j,1)= b;
00391       line_image(i,j,2)= c;
00392     }
00393 }
00394 
00395 void sdet_img_edge::edge_distance_transform(vil_image_view<vxl_byte>& inp_image, vil_image_view<float>& out_edt)
00396 {
00397   vil_image_view<vxl_byte> edge_image_negated(inp_image);
00398   vil_math_scale_and_offset_values<vxl_byte,double>(edge_image_negated,-1.0,255.0);
00399 
00400   unsigned ni = edge_image_negated.ni();
00401   unsigned nj = edge_image_negated.nj();
00402 
00403   vil_image_view<vxl_uint_32> curr_image_edt(ni,nj,1);
00404   for (unsigned i=0; i<ni; i++) {
00405     for (unsigned j=0; j<nj; j++) {
00406       curr_image_edt(i,j) = edge_image_negated(i,j);
00407     }
00408   }
00409 
00410   bil_edt_maurer(curr_image_edt);
00411 
00412   out_edt.set_size(ni,nj,1);
00413   for (unsigned i=0; i<ni; i++) {
00414     for (unsigned j=0; j<nj; j++) {
00415       out_edt(i,j) = vcl_sqrt((float)curr_image_edt(i,j));
00416     }
00417   }
00418 }
00419 
00420 
00421 /************************************************************************/
00422 /* Functions related to estimating edge probability given an edge image */
00423 /************************************************************************/
00424 
00425 vil_image_view<float> sdet_img_edge::multiply_image_with_gaussian_kernel(vil_image_view<float> img, double gaussian_sigma)
00426 {
00427   vil_image_view<float> ret_img(img.ni(),img.nj(),1);
00428 
00429   vnl_gaussian_kernel_1d gaussian(gaussian_sigma);
00430 
00431   for (unsigned i=0; i<img.ni(); i++) {
00432     for (unsigned j=0; j<img.nj(); j++) {
00433       ret_img(i,j) = (float)gaussian.G((double)img(i,j));
00434     }
00435   }
00436   return ret_img;
00437 }
00438 
00439 vbl_array_2d<float> sdet_img_edge::get_spherical_gaussian_kernel(const int size, const float sigma)
00440 {
00441   assert(size>=3 && size%2==1);
00442 
00443   vbl_array_2d<float> kernel(size,size,0.0f);
00444 
00445   vnl_vector_fixed<float,2> mean(0.0f);
00446   float variance = (sigma*sigma);
00447   bsta_gaussian_sphere<float,2> gaussian(mean,variance);
00448 
00449   int center = (size-1)/2;
00450 
00451   vnl_vector_fixed<float,2> min_pt;
00452   vnl_vector_fixed<float,2> max_pt;
00453   for (int i=0; i<size; i++) {
00454     for (int j=0; j<size; j++) {
00455       min_pt[0] = ((float)(i-center))-0.5f;
00456       min_pt[1] = ((float)(j-center))-0.5f;
00457       max_pt[0] = ((float)(i-center))+0.5f;
00458       max_pt[1] = ((float)(j-center))+0.5f;
00459       kernel(i,j) = gaussian.probability(min_pt,max_pt);
00460     }
00461   }
00462   return kernel;
00463 }
00464 
00465 void sdet_img_edge::estimate_edge_prob_image(const vil_image_view<vxl_byte>& img_edge, vil_image_view<float>& img_edgeness, const int mask_size, const float mask_sigma)
00466 {
00467   vbl_array_2d<float> kernel = get_spherical_gaussian_kernel(mask_size,mask_sigma);
00468 
00469   for (unsigned i=0; i<kernel.rows(); i++) {
00470     for (unsigned j=0; j<kernel.columns(); j++) {
00471       kernel(i,j) = vcl_log(1.0f - kernel(i,j));
00472     }
00473   }
00474 
00475   vil_convert_cast<vxl_byte,float>(img_edge,img_edgeness);
00476   vil_math_scale_values<float>(img_edgeness,1.0/255.0);
00477   img_edgeness = brip_vil_float_ops::convolve(img_edgeness,kernel);
00478 
00479   for (unsigned i=0; i<img_edgeness.ni(); i++) {
00480     for (unsigned j=0; j<img_edgeness.nj(); j++) {
00481       img_edgeness(i,j) = 1.0f - vcl_exp(img_edgeness(i,j));
00482     }
00483   }
00484 }
00485 
00486 void sdet_img_edge::convert_true_edge_prob_to_edge_statistics(
00487   const vil_image_view<float>& img_tep,
00488   vil_image_view<float>& img_es)
00489 {
00490   float img_mean,img_var;
00491   vil_math_mean_and_variance(img_mean,img_var,img_tep,0);
00492   img_var = vcl_sqrt(img_mean*img_var);
00493 
00494   img_es.set_size(img_tep.ni(),img_tep.nj());
00495 
00496   for (unsigned i=0; i<img_tep.ni(); i++) {
00497     for (unsigned j=0; j<img_tep.nj(); j++) {
00498       img_es(i,j) = ((img_tep(i,j)-img_mean)*(img_tep(i,j)-img_mean))/img_var;
00499     }
00500   }
00501 }
00502 
00503 float sdet_img_edge::convert_edge_statistics_to_probability(float edge_statistic, float n_normal, int dof)
00504 {
00505   if (dof<1) {
00506     return edge_statistic;
00507   }
00508   return (float)vnl_chi_squared_cumulative(edge_statistic,dof);
00509 }