contrib/brl/bseg/sdet/sdet_detector.cxx
Go to the documentation of this file.
00001 // This is brl/bseg/sdet/sdet_detector.cxx
00002 #include "sdet_detector.h"
00003 //:
00004 // \file
00005 // see sdet_detector.h
00006 //
00007 //-----------------------------------------------------------------------------
00008 
00009 #include <vil1/vil1_image.h>
00010 #include <vcl_iostream.h>
00011 #include <gevd/gevd_float_operators.h>
00012 #include <gevd/gevd_step.h>
00013 #include <gevd/gevd_bufferxy.h>
00014 #include <sdet/sdet_contour.h>
00015 #include <vil/vil_new.h>
00016 #include <vil/vil_image_view.h>
00017 #include <brip/brip_vil_float_ops.h>
00018 #include <vdgl/vdgl_digital_curve.h>
00019 #include <vdgl/vdgl_edgel_chain.h>
00020 #include <vdgl/vdgl_interpolator.h>
00021 #include <vsol/vsol_point_2d.h>
00022 //--------------------------------------------------------------------------------
00023 //
00024 //: Constructors.
00025 //
00026 sdet_detector::sdet_detector(sdet_detector_params& params)
00027   : sdet_detector_params(params),
00028     edgel(NULL), direction(NULL),
00029     locationx(NULL), locationy(NULL), grad_mag(NULL),
00030     angle(NULL), junctionx(NULL), junctiony(NULL), njunction(0),
00031     vertices(NULL), edges(NULL),
00032     filterFactor(2), hysteresisFactor(2.0), noiseThreshold(0.0)
00033 {
00034   if (params.automatic_threshold)
00035     noise = -params.noise_weight;
00036   else
00037     noise = params.noise_multiplier;
00038 //don't really know but have to pick one
00039   use_vil_image = true;
00040   image=0;
00041   vimage=0;
00042   use_roi_ = false;
00043 }
00044 
00045 sdet_detector::sdet_detector(vil1_image img, float smoothSigma, float noiseSigma,
00046                              float contour_factor, float junction_factor, int min_length,
00047                              float maxgap, float min_jump)
00048   : image(img), vimage(0), noise(noiseSigma), edgel(NULL), direction(NULL),
00049     locationx(NULL), locationy(NULL), grad_mag(NULL),
00050     angle(NULL), junctionx(NULL), junctiony(NULL), njunction(0),
00051     vertices(NULL), edges(NULL),
00052     filterFactor(2), hysteresisFactor(2.0f), noiseThreshold(0.0f)
00053 {
00054   use_vil_image = false;
00055   sdet_detector_params::smooth = smoothSigma;
00056   sdet_detector_params::contourFactor = contour_factor;
00057   sdet_detector_params::junctionFactor = junction_factor;
00058   sdet_detector_params::minLength = min_length;
00059   sdet_detector_params::maxGap = maxgap;
00060   sdet_detector_params::minJump = min_jump;
00061   use_roi_ = false;
00062 }
00063 
00064 sdet_detector::sdet_detector(vil_image_resource_sptr & img, float smoothSigma, float noiseSigma,
00065                              float contour_factor, float junction_factor, int min_length,
00066                              float maxgap, float min_jump)
00067   : image(0),vimage(img), noise(noiseSigma), edgel(NULL), direction(NULL),
00068     locationx(NULL), locationy(NULL), grad_mag(NULL),
00069     angle(NULL), junctionx(NULL), junctiony(NULL), njunction(0),
00070     vertices(NULL), edges(NULL),
00071     filterFactor(2), hysteresisFactor(2.0f), noiseThreshold(0.0f)
00072 {
00073   use_vil_image = true;
00074   sdet_detector_params::smooth = smoothSigma;
00075   sdet_detector_params::contourFactor = contour_factor;
00076   sdet_detector_params::junctionFactor = junction_factor;
00077   sdet_detector_params::minLength = min_length;
00078   sdet_detector_params::maxGap = maxgap;
00079   sdet_detector_params::minJump = min_jump;
00080   use_roi_ = false;
00081 }
00082 
00083 
00084 //: Destructor.
00085 //  Caller has an obligation to clear all the created edges and vertices.
00086 sdet_detector::~sdet_detector()
00087 {
00088   ClearData();
00089 }
00090 
00091 
00092 //: Clear data buffer.  Protected.
00093 //
00094 void sdet_detector::ClearData()
00095 {
00096   delete edgel; delete direction; delete locationx; delete locationy;
00097   delete grad_mag; delete angle;
00098   delete [] junctionx; delete [] junctiony;
00099   if (vertices)
00100     vertices->clear();
00101   if (edges)
00102     edges->clear();
00103   delete vertices;
00104   vertices = 0;
00105   delete edges;
00106   edges = 0;
00107 }
00108 
00109 
00110 //: Detect the contour, a list of edges and vertices are generated.
00111 //
00112 bool  sdet_detector::DoContour()
00113 {
00114   if (edges && vertices) return true;
00115 
00116   if (!DoStep()) {
00117     vcl_cout << "***Fail on DoContour.\n";
00118     return false;
00119   }
00120 
00121   sdet_contour::ClearNetwork(edges, vertices);       // delete vertices/edges
00122   sdet_contour contour(this->hysteresisFactor*this->noiseThreshold,
00123                        this->minLength, this->minJump*this->noiseThreshold,
00124                        this->maxGap);
00125 
00126   // first, find isolated chains/cycles
00127   bool find_net  = contour.FindNetwork(*edgel, junctionp,
00128                                        njunction,
00129                                        junctionx, junctiony,
00130                                        edges, vertices);
00131   if (!find_net) {
00132     vcl_cout << "***Fail on FindNetwork.\n";
00133     return false;
00134   }
00135 
00136   //Insert a virtual border to enforce closure to support region topology.
00137   if (this->borderp)
00138     contour.InsertBorder(*edges, *vertices);
00139 
00140   //Move the edgel locations to interpolated positions using zero crossings
00141   contour.SubPixelAccuracy(*edges, *vertices,
00142                            *locationx, *locationy);
00143 
00144   // Reduce zig-zags and space out pixels in chains
00145   if (this->spacingp)
00146     sdet_contour::EqualizeSpacing(*edges);
00147 
00148   //Set gradient magnitude and angle values on each edgel
00149   if (grad_mag&&angle)
00150     sdet_contour::SetEdgelData(*grad_mag, *angle, *edges);
00151 
00152   //Keep this code which will be needed when we have ROI's
00153 #if 0 // TargetJr
00154    const RectROI* roi = image->GetROI();
00155    sdet_contour::Translate(*edges, *vertices, // display location at center
00156                            roi->GetOrigX()+0.5, // of pixel instead of
00157                            roi->GetOrigY()+0.5); // upper-left corner
00158 #endif
00159    if (!use_roi_)
00160      return true;
00161    sdet_contour::Translate(*edges, *vertices, // display location at center
00162                            static_cast<float>(roi_.cmin(0)), // of pixel instead of
00163                            static_cast<float>(roi_.rmin(0))); // upper-left corner
00164    return true;
00165 }
00166 
00167 //--------------------------------------------------------------------------------
00168 //
00169 //: Detect the fold contour, a list of edges and vertices are generated.
00170 //
00171 bool  sdet_detector::DoFoldContour()
00172 {
00173   if (edges && vertices) return true;
00174 
00175 #if 0
00176   if (!DoFold()) {
00177     vcl_cout << "***Fail on DoFoldContour.\n";
00178     return false;
00179   }
00180 #endif
00181   sdet_contour::ClearNetwork(edges, vertices);       // delete vertices/edges
00182   sdet_contour contour(this->hysteresisFactor*this->noiseThreshold,
00183                        this->minLength, this->minJump*this->noiseThreshold,
00184                        this->maxGap);
00185 
00186   // first, find isolated  chains/cycles
00187   bool t  = contour.FindNetwork(*edgel, junctionp,
00188                                 njunction,
00189                                 junctionx, junctiony,
00190                                 edges, vertices);
00191   if (!t) {
00192     vcl_cout << "***Fail on FindNetwork.\n";
00193     return false;
00194   }
00195   contour.SubPixelAccuracy(*edges, *vertices, // insert subpixel
00196                            *locationx, *locationy); // accuracy
00197   if (this->spacingp)           // reduce zig-zags and space out pixels
00198     sdet_contour::EqualizeSpacing(*edges); // in chains
00199   if (this->borderp)            // insert a virtual contour to enforce
00200     contour.InsertBorder(*edges, *vertices); // closure at border
00201   if (grad_mag&&angle)
00202     sdet_contour::SetEdgelData(*grad_mag, *angle, *edges); //Continuous edgel orientation.
00203 #if 0 // TargetJr
00204   sdet_contour::add_vertex_edgels(*edges);
00205   const RectROI* roi = image->GetROI();
00206   sdet_contour::Translate(*edges, *vertices, // display location at center
00207                           roi->GetOrigX()+0.5, // of pixel instead of
00208                           roi->GetOrigY()+0.5); // upper-left corner
00209 #endif
00210   return true;
00211 }
00212 
00213 //---------------------------------------------------------------------------
00214 //
00215 //: Detect step profiles in the image, using dG+NMS+extension.
00216 //
00217 bool sdet_detector::DoStep()
00218 {
00219   if (edgel) return true;
00220 
00221   const gevd_bufferxy* source;
00222   if (use_vil_image)
00223     source = GetBufferFromVilImage();
00224   else
00225     source = GetBufferFromImage();
00226   if (!source) {
00227     vcl_cout << " cannot get image buffer\n";
00228     return false;
00229   }
00230   gevd_step step(this->smooth, this->noise, this->contourFactor, this->junctionFactor);
00231 
00232   step.DetectEdgels(*source, edgel, direction, locationx, locationy, grad_mag, angle);
00233 
00234   if (this->junctionp) {                // extension to real/virtual contours
00235     njunction = step.RecoverJunctions(*source,
00236                                       *edgel, *direction,
00237                                       *locationx, *locationy,
00238                                       junctionx, junctiony);
00239   }
00240   else {
00241     njunction = 0;
00242     delete [] junctionx; junctionx = NULL;
00243     delete [] junctiony; junctiony = NULL;
00244   }
00245 
00246   this->noiseThreshold = step.NoiseThreshold();
00247   delete source;//this fixes a leak
00248   return edgel!=NULL;
00249 }
00250 
00251 #if 0 // commented out
00252 //---------------------------------------------------------------------------
00253 //
00254 //: Detect fold profiles in the image, using dG+NMS+extension.
00255 //
00256 bool sdet_detector::DoFold()
00257 {
00258   if (edgel) return true;
00259 
00260   const BufferXY* source = GetBufferFromImage();
00261   if (!source) {
00262     vcl_cout << " cannot get image buffer\n";
00263     return false;
00264   }
00265 
00266   Fold fold(this->smooth, this->noise,
00267             this->contourFactor,
00268             this->junctionFactor);
00269   fold.DetectEdgels(*source, edgel, direction,
00270                     locationx, locationy, true, //Flag to compute mag, angle
00271                     grad_mag, angle); //Reusing grad_mag, actually |d2G|
00272 
00273   if (this->junctionp) {                // extension to real/virtual contours
00274     njunction = fold.RecoverJunctions(*source,
00275                                       *edgel, *direction,
00276                                       *locationx, *locationy,
00277                                       junctionx, junctiony);
00278   }
00279   else {
00280     njunction = 0;
00281     delete [] junctionx; junctionx = NULL;
00282     delete [] junctiony; junctiony = NULL;
00283   }
00284 
00285   this->noiseThreshold = fold.NoiseThreshold();
00286   return edgel!=NULL;
00287 }
00288 #endif // 0
00289 
00290 //--------------------------------------------------------------------------------
00291 //
00292 //: Transform data in the image as float buffer.
00293 //
00294 // two versions so as not to break anything from the ancient code JLM
00295 // vil1_image version
00296 gevd_bufferxy* sdet_detector::GetBufferFromImage()
00297 {
00298   gevd_bufferxy* image_float_buf = 0;
00299 
00300   if (image_float_buf) return image_float_buf;
00301   //Tests for validity
00302   if (!image)
00303   {
00304     vcl_cout << "In sdet_detector::GetBufferFromImage() - no image\n";
00305     return 0;
00306   }
00307   if (image.components()!=1)
00308   {
00309     vcl_cout << "In sdet_detector::GetBufferFromImage() -"
00310              << " not exactly one component\n";
00311     return 0;
00312   }
00313 
00314 #if 0 // TargetJr
00315   RectROI* roi = image->GetROI(); // find user-selected region of interest
00316   int sizex = roi->GetSizeX();
00317   int sizey = roi->GetSizeY();
00318 #endif
00319   int sizey= image.rows();
00320   int sizex= image.cols();
00321 
00322   image_float_buf = new gevd_bufferxy(sizex, sizey,8*sizeof(float));
00323 
00324 #if 0 // commented out
00325   if (image->GetPixelType() == Image::FLOAT)
00326   {
00327     image->GetSection(image_float_buf->GetBuffer(),
00328                       roi->GetOrigX(), roi->GetOrigY(), sizex, sizey);
00329     return image_float_buf;
00330   }
00331 #endif
00332 
00333   gevd_bufferxy image_buf(sizex, sizey, image.bits_per_component());
00334 
00335 #if 0 // commented out
00336   image->GetSection(image_buf.GetBuffer(),      // copy bytes image into buf
00337                     roi->GetOrigX(), roi->GetOrigY(), sizex, sizey);
00338 #endif
00339 
00340   image.get_section(image_buf.GetBuffer(),     // copy bytes image into buf
00341                     0, 0, sizex, sizey);
00342 
00343   if (! gevd_float_operators::BufferToFloat(image_buf, *image_float_buf))
00344   {
00345     delete image_float_buf;
00346     image_float_buf = 0;
00347   }
00348 
00349   return image_float_buf;
00350 }
00351 // vil_image version
00352 gevd_bufferxy* sdet_detector::GetBufferFromVilImage()
00353 {
00354   gevd_bufferxy* image_float_buf = 0;
00355 
00356   if (image_float_buf) return image_float_buf;
00357   //Tests for validity
00358 
00359   if (!use_vil_image||!vimage->ni()||!vimage->nj())
00360   {
00361     vcl_cout << "In sdet_detector::GetBufferFromVilImage() - no image\n";
00362     return 0;
00363   }
00364 
00365   vil_image_resource_sptr process_region = vimage;
00366 
00367   //if an roi is specified then extract view and wrap a resource around it
00368   if (use_roi_)
00369   {
00370     if (roi_.n_regions()!=1)//no roi to process
00371       return 0;
00372     vil_image_view_base_sptr vb =
00373       vimage->get_view(roi_.cmin(0), roi_.csize(0), roi_.rmin(0), roi_.rsize(0));
00374     if (!vb)
00375       return 0;
00376     process_region = vil_new_image_resource_of_view(*vb);
00377   }
00378 
00379   if (vimage->nplanes()!=1)
00380   {
00381     vil_image_view<unsigned short> sview
00382       = brip_vil_float_ops::convert_to_short(process_region);
00383     process_region = vil_new_image_resource_of_view(sview);
00384   }
00385 
00386   int sizey= process_region->nj();
00387   int sizex= process_region->ni();
00388 
00389   image_float_buf = new gevd_bufferxy(sizex, sizey,8*sizeof(float));
00390 
00391   gevd_bufferxy image_buf(process_region);
00392 
00393   if (! gevd_float_operators::BufferToFloat(image_buf, *image_float_buf))
00394   {
00395     delete image_float_buf;
00396     image_float_buf = 0;
00397   }
00398 
00399   return image_float_buf;
00400 }
00401 
00402 void sdet_detector::print(vcl_ostream &strm) const
00403 {
00404   strm << "sdet_detector:\n"
00405        << "    noise " << noise << vcl_endl
00406        << "    njunction " << njunction << vcl_endl
00407        << "    num vertices " << vertices->size() << vcl_endl
00408        << "    num edges " << edges->size() << vcl_endl
00409        << "    filterfactor " << filterFactor << vcl_endl
00410        << "    hysteresisfactor " << hysteresisFactor << vcl_endl
00411        << "    noiseThreshold " << noiseThreshold << vcl_endl
00412        << "    smooth " <<   smooth << vcl_endl // Smoothing kernel sigma
00413        << "    noise_weight " <<   noise_weight << vcl_endl //The weight between sensor noise and texture noise
00414        << "    noise_multiplier " <<   noise_multiplier << vcl_endl // The overal noise threshold scale factor
00415        << "    automatic_threshold " <<   automatic_threshold << vcl_endl // Determine the threshold values from image
00416        << "    aggressive_junction_closure " <<   aggressive_junction_closure << vcl_endl //Close junctions aggressively
00417        << "    minLength " <<   minLength << vcl_endl          // minimum chain length
00418        << "    contourFactor " <<   contourFactor << vcl_endl  // Threshold along contours
00419        << "    junctionFactor " <<   junctionFactor << vcl_endl //Threshold at junctions
00420        << "    filterFactor " <<   filterFactor << vcl_endl    // ratio of sensor to texture noise
00421        << "    junctionp " <<   junctionp << vcl_endl // recover missing junctions
00422        << "    minJump " <<   minJump << vcl_endl  // change in strength at junction
00423        << "    maxGap " <<   maxGap << vcl_endl   // Bridge small gaps up to max_gap across.
00424        << "    spacingp " <<   spacingp << vcl_endl  // equalize spacing?
00425        << "    borderp " <<   borderp << vcl_endl   // insert virtual border for closure?
00426        << "    corner_angle " <<   corner_angle << vcl_endl // smallest angle at corner
00427        << "    separation " <<   separation << vcl_endl // |mean1-mean2|/sigma
00428        << "    min_corner_length " <<   min_corner_length << vcl_endl // min length to find corners
00429        << "    cycle " <<   cycle << vcl_endl // number of corners in a cycle
00430        << "    ndimension " <<   ndimension // spatial dimension of edgel chains.
00431        << vcl_endl;
00432 }
00433 
00434 void sdet_detector::DoBreakCorners(vcl_vector<vtol_edge_2d_sptr >& /* in_edgels */,
00435                                    vcl_vector<vtol_edge_2d_sptr >& /* out_edgels */)
00436 {
00437   vcl_cerr << "sdet_detector::DoBreakCorners() NYI\n";
00438 }
00439 
00440 void sdet_detector::SetImage(vil1_image img)
00441 {
00442   use_vil_image = false;
00443   image = img;
00444 }
00445 
00446 void sdet_detector::SetImage(vil_image_resource_sptr const& img, brip_roi const& roi)
00447 {
00448   use_vil_image = true;
00449   vimage = img;
00450   use_roi_ = true;
00451   roi_ = roi;
00452 }
00453 
00454 void sdet_detector::SetImage(vil_image_resource_sptr const& img)
00455 {
00456   use_vil_image = true;
00457   vimage = img;
00458 }
00459 
00460 bool sdet_detector::
00461 get_vdgl_edges(vcl_vector<vdgl_digital_curve_sptr>& vd_edges )
00462 {
00463   vd_edges.clear();
00464   if (!edges)
00465     return false;
00466 
00467   for (vcl_vector<vtol_edge_2d_sptr >::iterator eit = edges->begin();
00468        eit != edges->end(); ++eit)
00469   {
00470     vtol_edge_2d_sptr & e = *eit;
00471     if (!e)
00472       continue;
00473     vsol_curve_2d_sptr c = e->curve();
00474     vdgl_digital_curve* dc = c->cast_to_vdgl_digital_curve();
00475     if (!dc)
00476       continue;
00477 
00478     vd_edges.push_back(dc);
00479   }
00480   if (!vd_edges.size())
00481     return false;
00482   return true;
00483 }
00484 
00485 bool
00486 sdet_detector::get_vsol_edges(vcl_vector<vsol_digital_curve_2d_sptr>& edges )
00487 {
00488   vcl_vector<vdgl_digital_curve_sptr> vd_edges;
00489   if (!this->get_vdgl_edges(vd_edges))
00490     return false;
00491   edges.clear();
00492   for (vcl_vector<vdgl_digital_curve_sptr>::iterator eit = vd_edges.begin();
00493        eit != vd_edges.end(); ++eit)
00494   {
00495       //get the edgel chain
00496     vdgl_interpolator_sptr itrp = (*eit)->get_interpolator();
00497     vdgl_edgel_chain_sptr ech = itrp->get_edgel_chain();
00498     unsigned int n = ech->size();
00499     // convert to vsol_digital curve
00500     vsol_digital_curve_2d_sptr vsdc = new vsol_digital_curve_2d();
00501     for (unsigned int i=0; i<n;i++)
00502     {
00503       vdgl_edgel ed = (*ech)[i];
00504       double x = ed.get_x(), y = ed.get_y();
00505       vsdc->add_vertex(new vsol_point_2d(x, y));
00506     }
00507 
00508    edges.push_back(vsdc);
00509   }
00510   return true;
00511 }