contrib/gel/gevd/gevd_step.cxx

Go to the documentation of this file.
00001 // This is gel/gevd/gevd_step.cxx
00002 #include "gevd_step.h"
00003 //:
00004 // \file
00005 // Use 8 directions, with 45 degree angle in between them.
00006 // The array DIS gives the i-component of the directions
00007 // The array DJS gives the j-component of the directions.
00008 // Shown here for a right-handed coordinate system for (i,j)
00009 // in accordance with standard texts. -- JLM
00010 //\verbatim
00011 //               j
00012 //         ______|_____________
00013 //        |      |      |      |
00014 //        |  3   |  2   |  1 <------ Direction Code
00015 //        |______|______|______|     for 8-connected
00016 //        |      |      |      |     neighbors
00017 //        |  4   |(i,j) |  0   |
00018 //        |______|______|______|___ i
00019 //        |      |      |      |
00020 //        |  5   |  6   |  7   |
00021 //        |______|______|______|
00022 //
00023 //\endverbatim
00024 
00025 #include <vcl_vector.h>
00026 #include <vcl_iostream.h>
00027 #include <vnl/vnl_math.h>
00028 #include <gevd/gevd_noise.h>
00029 #include <gevd/gevd_float_operators.h>
00030 #include <gevd/gevd_pixel.h>
00031 #include <gevd/gevd_bufferxy.h>
00032 #ifdef DEBUG
00033 # include <vul/vul_timer.h>
00034 #endif
00035 
00036 const unsigned char TWOPI = 8, FULLPI = 4, HALFPI = 2;
00037 const int DIS[] = { 1, 1, 0,-1,-1,-1, 0, 1, // 8-connected neighbors
00038                     1, 1, 0,-1,-1,-1, 0, 1, // wrapped by 2PI to
00039                     1, 1, 0,-1,-1,-1, 0, 1};// avoid modulo operations.
00040 const int DJS[] = { 0, 1, 1, 1, 0,-1,-1,-1,
00041                     0, 1, 1, 1, 0,-1,-1,-1,
00042                     0, 1, 1, 1, 0,-1,-1,-1};
00043 const int RDS[] = {0,-1, 1,-2, 2,-3, 3,-4, 4,-5, 5}; // radial search
00044 
00045 // const unsigned char DIR0 = 8, DIR1 = 9, DIR2 = 10, DIR3 = 11;
00046 const int FRAME = 4; // 3 for NMS and extension, 4 for contour
00047 
00048 //: Save parameters and create workspace for detecting step profiles.
00049 // High frequency features are smoothed away by smooth_sigma.
00050 // Texture or white noise less than noise_sigma are not detected.
00051 // smooth_sigma = 0.5-2.0, 1.0 insures separation of independent steps >= 2.
00052 //
00053 // If noise_sigma > 0, noise_sigma = is interpreted as the standard deviation
00054 //    of intensity z(x,y) in a uniform region.
00055 // If -1 <= noise_sigma <= 0, then noise_sigma is interpreted as a factor -k,
00056 // where k is a weighting factor between two estimates: sensorNoise and textureNoise.
00057 //
00058 //  noiseSigma = ((1-k)*sensorNoise + k*textureNoise)/K
00059 //
00060 // The values of sensorNoise and textureNoise are computed from the shape of
00061 // the histogram of gradient magnitude values, in the neighborhood of low gradients.
00062 // The value of K is computed in NoiseResponseToFilter and defined by:
00063 //
00064 //  1/(smoothSigma^1.5)*(.5/M_PI^.25)*filterFactor.
00065 //
00066 // Given the defaults:  smoothSigma =1 and filterFactor = 2, K = .75
00067 //
00068 // The threshold used to delete weak edges is modified depending on the
00069 // context.  For edgels along a contour, shortp = false, and the threshold
00070 // is given by:
00071 //
00072 //    NoiseThreshold(shortp) = 3*K*noiseSigma
00073 //
00074 // For edgels at junctions, shortp = true, the threshold is computed
00075 // using different factors.  The difference is controlled by the parameters:
00076 // contour_factor and junction_factor.  smoothSigma when extending the
00077 // boundary at junctions is 1/2 the value along contours.
00078 //
00079 gevd_step::gevd_step(float smooth_sigma, // width of filter dG
00080                      float noise_sigma,   // sensor/texture intensity noise -[0 1]
00081                      float contour_factor, float junction_factor)
00082   : smoothSigma(smooth_sigma), noiseSigma(noise_sigma),
00083     contourFactor(contour_factor), junctionFactor(junction_factor),
00084     filterFactor(2)              // factor from gevd_float_operators::Gradient
00085 {
00086   if (smoothSigma < 0.5)        // no guarrantee for 2-pixel separation
00087     vcl_cerr << "gevd_step::gevd_step -- too small smooth_sigma: "
00088              << smoothSigma << vcl_endl;
00089   if (smoothSigma > 3)          // smooth out too much the junctions
00090     vcl_cerr << "gevd_step::gevd_step -- too large smooth_sigma: "
00091              << smoothSigma << vcl_endl;
00092   if (noiseSigma < -1) {
00093     vcl_cerr << "gevd_step::gevd_step -- noiseSigma out of range -[0 1]: "
00094              << noiseSigma << ". Reset to -1.\n";
00095     noiseSigma = -1;
00096   }
00097 
00098   //vcl_cout << "Init Step\n" << *this << vcl_endl;
00099 }
00100 
00101 
00102 //: Free space allocated for detecting step profiles.  Does nothing.
00103 gevd_step::~gevd_step() {}
00104 
00105 //: Detect step profiles with Canny edge detector.
00106 // The image is convolved with a Gaussian to smooth away
00107 // high frequency noise, and insure separation of step responses.
00108 // Then local gradient magnitude and direction is detected
00109 // using first difference [-1 0 +1].
00110 // Optionally estimate sensor/texture sigma and set threshold.
00111 // Finally, non maximum suppression is done to find strict
00112 // local maxima of slope.
00113 // The Canny edge detector finds elongated contours only.
00114 // These contours are typically broken at junctions because non
00115 // maximum suppression is done along only the strongest direction.
00116 // Return contour (float), direction (byte), location (float) images.
00117 // Return true if no exception.
00118 // J. Canny, A Computational Approach to Edge Detection,
00119 // IEEE Trans on PAMI, vol 8, no 6, Nov 1986.
00120 bool
00121 gevd_step::DetectEdgels(const gevd_bufferxy& image,
00122                         gevd_bufferxy*& contour, gevd_bufferxy*& direction,
00123                         gevd_bufferxy*& locationx, gevd_bufferxy*& locationy,
00124                         gevd_bufferxy*& grad_mag, gevd_bufferxy*& angle)
00125 {
00126   //vcl_cout << "*** Detect step profiles with first-derivative of Gaussian"
00127   //         << *this
00128   //         << vcl_endl;
00129   if (image.GetBitsPixel() != bits_per_float) {
00130     vcl_cerr << "gevd_step::DetectEdgels requires float image\n";
00131     return false;
00132   }
00133 
00134   // -tpk @@ missing check if the requested buffer size is too small to contain the convolution operations
00135 
00136   // 1. Smooth image to regularize data, before taking derivatives
00137   gevd_bufferxy* smooth = NULL;      // Gaussian smoothed image
00138   // use float to avoid overflow/truncation
00139   filterFactor = gevd_float_operators::Gaussian((gevd_bufferxy&)image, // well-condition before
00140                                                 smooth, smoothSigma); // 1st-difference
00141 
00142   // 2. Use 1st-difference to estimate local slope, filter is dG.
00143   gevd_bufferxy *slope = NULL, *dirx=NULL, *diry=NULL;
00144   filterFactor *= gevd_float_operators::Gradient(*smooth, // directional 1st-difference
00145                                                  slope, dirx, diry); // mult factor returned
00146   delete smooth;
00147 
00148   // 2.5 JLM - Fill the theta array for use in outputting continuous digital curve
00149   //           directions later.  The angle definition here is consistent with
00150   //           EdgeDetector, i.e. angle = (180/M_PI)*vcl_atan2(dI/dy, dI/dx);
00151 
00152   grad_mag = gevd_float_operators::SimilarBuffer(image);
00153   angle = gevd_float_operators::SimilarBuffer(image);
00154   const double kdeg = 180*vnl_math::one_over_pi;
00155   for (int j = 0; j < image.GetSizeY(); j++)
00156     for (int i = 0; i < image.GetSizeX(); i++)
00157       if ((floatPixel(*grad_mag, i, j) = floatPixel(*slope, i, j)))
00158         floatPixel(*angle, i, j) = float(kdeg*vcl_atan2(floatPixel(*diry, i, j),
00159                                                         floatPixel(*dirx, i, j)));
00160       else
00161         floatPixel(*angle, i, j) = 0;
00162 
00163 
00164   // 3. Estimate sensor/texture sigmas from histogram of weak step edgels
00165   if (noiseSigma <= 0)  {
00166     int nedgel = 0;             // all edgels in ROI at center of image
00167     float* edgels = gevd_noise::EdgelsInCenteredROI(*slope, *dirx, *diry,
00168                                                     nedgel);
00169     if ((edgels) && (nedgel > 0 )) {
00170       gevd_noise noise(edgels, nedgel); // histogram of weak edgels only
00171       delete [] edgels;
00172       float sensorNoise, textureNoise;
00173       if (noise.EstimateSensorTexture(sensorNoise, textureNoise)) {
00174         const float k = -noiseSigma; // given linear interpolation factor
00175         noiseSigma = ((1-k)*sensorNoise + k*textureNoise) /
00176           NoiseResponseToFilter(1, smoothSigma, filterFactor);
00177       } else {
00178         vcl_cout << "Can not estimate sensor & texture noise\n";
00179         noiseSigma = 1;         // reasonable default for 8-bit
00180       }
00181     } else {
00182       vcl_cout << "Not enough edge elements to estimate noise\n";
00183       noiseSigma = 1;
00184     }
00185     //vcl_cout << "Set noise sigma = " << noiseSigma << vcl_endl;
00186   }
00187 
00188   // 4. Find contour pixels as local maxima along slope direction
00189   //
00190   //                  [i,j+1]
00191   //                    ^
00192   //                    |
00193   // Note that [i-1 ,j] -> [i+1,j] indicates the sign of dirx and diry.
00194   //                    |          That is, if the intensities at the arrows
00195   //                 [i, j-1]      are larger than that at (i,j) then dirx or
00196   //                               diry are positive.  Again shown for a
00197   //                               right-handed (i,j) system -- JLM
00198   //
00199   // Thus for the following contour:
00200   //          ^ j            Normal Direction
00201   //          |________            ^
00202   //    light |        |           |    dirx = 0 and diry = +.  The direction
00203   //        __|________|__Contour__|    code returned by NonMaximumSupression
00204   //          |xxxxxxxx|                is 10 -- modulo 8 is 2, as shown.
00205   //    dark  |xxxxxxxx|
00206   //           ----------> i
00207   //
00208   // -----------------------------------------------------------------
00209 
00210   gevd_float_operators::NonMaximumSuppression(*slope, *dirx, *diry,
00211                                               NoiseThreshold(), // above noise
00212                                               contour, direction,
00213                                               locationx, locationy);
00214   delete slope; delete dirx; delete diry;
00215   gevd_float_operators::FillFrameX(*contour, 0, FRAME); // erase pixels in frame border
00216   gevd_float_operators::FillFrameY(*contour, 0, FRAME);
00217   return true;
00218 }
00219 
00220 //:
00221 // Return -/+ PI/2, to encode the existence of an end point
00222 // on the left/right side of the current contour point i,j.
00223 // Note, in vil1, images have a left-handed (i,j) coordinate frame,
00224 // i.e., i increases left to right and j increases downward in the image.
00225 //
00226 // The search proceeds as follows:
00227 //
00228 // 1)
00229 //\verbatim
00230 //        X
00231 //    --(i,j)--
00232 //        X    |
00233 //             v  Normal to contour (dir)
00234 //\endverbatim
00235 // if either X is occupied then it must be a corner -- so do nothing.
00236 //
00237 // 2) Next, search along the contour to the left or right
00238 //\verbatim
00239 //      L         R
00240 //      L--(i,j)--R
00241 //      L    |    R
00242 //           v Normal to contour (dir)
00243 //
00244 //    left       right      if any R position is occupied but not any L
00245 //  neighbor    neighbor    return -2.
00246 //                          if any L position is occupied but not any R
00247 //                          return +2.  Otherwise return 0.
00248 //\endverbatim
00249 //  Thus, the direction code along the contour at the end of the contour
00250 //  is returned.
00251 static int
00252 LeftXorRightEnd(const gevd_bufferxy& contour,
00253                 int i, int j, // pixel on contour
00254                 const int dir) // normal to contour
00255 {
00256   int di = DIS[dir], dj = DJS[dir];
00257   bool normalp = (floatPixel(contour, i - di, j - dj) ||
00258                   floatPixel(contour, i + di, j + dj));
00259   if (normalp)                  // Substitute neighbor
00260     return 0;                   // for left or right side.
00261   bool leftp = false;
00262   int ndir = dir - HALFPI;      // left ndir
00263   for (int n = 0; n < 3; ++n) { // 3 neighbors
00264     int theta = ndir + RDS[n];
00265     if (floatPixel(contour, i+DIS[theta], j+DJS[theta])) {
00266       leftp = true;             // found neighbor on left side
00267       break;
00268     }
00269   }
00270   bool rightp = false;
00271   ndir = dir + HALFPI;          // right ndir
00272   for (int n = 0; n < 3; ++n) { // 3 neighbors
00273     int theta = ndir + RDS[n];
00274     if (floatPixel(contour, i+DIS[theta], j+DJS[theta])) {
00275     rightp = true;            // found neighbor on right side
00276       break;
00277     }
00278   }
00279   return (leftp? 0: -HALFPI) + (rightp? 0: HALFPI); // increment from dir
00280 }
00281 
00282 //: Find best step extension from end point, which has largest local maximum slope.
00283 // Search all 3x3=9 neighboring locations/orientations
00284 // in the direction of the contour.  If the best gradient along the contour
00285 // extension is below the threshold, then return 0, otherwise
00286 // return the location, direction and strength of the extension pixel.
00287 //
00288 static float
00289 BestStepExtension(const gevd_bufferxy& smooth,
00290                   const int i, const int j,
00291                   const int ndir, // tangential dir to neighbor
00292                   const float threshold,
00293                   int& best_i, int& best_j, // pixel
00294                   int& best_d, float& best_l) // direction + subloc
00295 {
00296   float best_s = threshold;     // insure greater response
00297   const int direc = ndir + HALFPI; // step direction
00298   for (int n = 0; n < 3; n++) { // all 3 neighboring pixels
00299     int ntheta = ndir + RDS[n];
00300     int ni = i + DIS[ntheta];
00301     int nj = j + DJS[ntheta];
00302     float pix = floatPixel(smooth, ni, nj); // center
00303     for (int d = 0; d < 3; d++) { // all 3 neighboring directions
00304       int dir = direc + RDS[d];
00305       int di = DIS[dir];
00306       int dj = DJS[dir];
00307       float pix_m = floatPixel(smooth, ni-di, nj-dj);
00308       float pix_p = floatPixel(smooth, ni+di, nj+dj);
00309       float slope = (float)vcl_fabs(pix_p - pix_m);
00310       float max_s = (dir%HALFPI)? best_s*(float)vcl_sqrt(2.0): best_s;
00311       if (slope > max_s) {      // find best strength
00312         int di2 = 2*di;
00313         int dj2 = 2*dj;
00314         if (slope > vcl_fabs(pix - floatPixel(smooth, ni-di2, nj-dj2)) &&
00315             slope > vcl_fabs(pix - floatPixel(smooth, ni+di2, nj+dj2))) {
00316           best_i = ni;
00317           best_j = nj;
00318           best_s = (dir%HALFPI)? slope/(float)vcl_sqrt(2.0) : slope;
00319           best_d = dir%FULLPI + TWOPI; // in range [0 FULLPI) + TWOPI
00320         }
00321       }
00322     }
00323   }
00324   if (best_s > threshold) {     // interpolate with parabola
00325     float pix = floatPixel(smooth, best_i, best_j);
00326     int di2 = 2 * DIS[best_d], dj2 = 2 * DJS[best_d];
00327     float s_m = (float)vcl_fabs(pix - floatPixel(smooth, best_i-di2, best_j-dj2));
00328     float s_p = (float)vcl_fabs(pix - floatPixel(smooth, best_i+di2, best_j+dj2));
00329     if (best_d%HALFPI) {
00330       s_m /= (float)vcl_sqrt(2.0);
00331       s_p /= (float)vcl_sqrt(2.0);
00332     }
00333     best_l = gevd_float_operators::InterpolateParabola(s_m, best_s, s_p, best_s);
00334     return best_s;
00335   } else                        // not found
00336     return 0;
00337 }
00338 
00339 
00340 //:
00341 // Find junctions by searching for extensions of contours from
00342 // their dangling end points. Non maximum suppression insures that
00343 // contours have width < 2, and so we can find the left/right neighbors,
00344 // and deduce end points. By using a minimally smoothed image,
00345 // we find step profiles up to joining with a stronger contour, thus
00346 // recovering the missing junction caused by NMS along only 1 direction.
00347 // The junctions are returned but are not set in the contour image,
00348 // to prevent incorrect tracing of stronger contours first.
00349 // The search is extended outward for a distance of kmax which is currently
00350 // 4*smoothSigma + 2.
00351 int
00352 gevd_step::RecoverJunctions(const gevd_bufferxy& image,
00353                             gevd_bufferxy& contour, gevd_bufferxy& direction,
00354                             gevd_bufferxy& locationx, gevd_bufferxy& locationy,
00355                             int*& junctionx, int*& junctiony)
00356 {
00357 #if defined(DEBUG)
00358   vul_timer t;
00359 #endif
00360   if (image.GetBitsPixel() != bits_per_float) {
00361     vcl_cerr << "gevd_step::RecoverJunction requires float image\n";
00362     return false;
00363   }
00364   const int rmax = 1+FRAME;     // 1 + kernel radius of BestStepExtension
00365   const int kmax = int(4 * smoothSigma + 0.5) + 2; // gap = 2
00366   const int xmax = image.GetSizeX()-rmax-1; // fill step direction
00367   const int ymax = image.GetSizeY()-rmax-1;
00368 #ifdef DEBUG
00369   vcl_cout << "RecoverJunctions: rmax, kmax, xmax, ymax:" << rmax << ' ' << kmax << ' ' << xmax << ' ' << ymax << '\n';
00370 #endif
00371   // 1. Find end points of dangling contours
00372   //const int length0 = xmax/kmax*ymax/kmax/4;// 25% size
00373   //const float growth = 2;     // growth ratio of the arrays
00374 
00375   vcl_vector<int> ndir; //  ndir.set_growth_ratio(growth);
00376   vcl_vector<int> xloc; //  xloc.set_growth_ratio(growth); // dynamic array instead of long lists
00377   vcl_vector<int> yloc; //  yloc.set_growth_ratio(growth);
00378   int xdir;
00379   for (int y = rmax; y <= ymax; y++) // find end points of long contours
00380     for (int x = rmax; x <= xmax; x++) // inside image border - rmax
00381       if (floatPixel(contour, x, y) && // on contour
00382           (xdir = LeftXorRightEnd(contour, x, y, // left xor right neighbor
00383                                   bytePixel(direction, x, y))) != 0)
00384       {
00385         ndir.push_back(xdir);   // save end point of elongated contours
00386         xloc.push_back(x);
00387         yloc.push_back(y);
00388       }
00389   const int length = ndir.size();
00390   //vcl_cout << "% end pats = "     // trace allocated size
00391   //          << length*100 / float((xmax/kmax)*(ymax/kmax)) << vcl_endl;
00392   if (!length) return 0;        // no end points exist
00393 
00394   // 2. Extend from end points until they touch other contours
00395   gevd_bufferxy* smooth = NULL;
00396   gevd_float_operators::Gaussian((gevd_bufferxy&)image, smooth, smoothSigma/2); // avoid oversmoothing
00397   const bool shortp = true;     // short contours
00398   const float threshold = NoiseThreshold(shortp);
00399   float slope, loc;
00400   int njunction = 0;            // number of junctions found
00401   for (int r = 1; r <= kmax; r++) { // breadth-first extension
00402     int ntouch = 0, nextension = 0;
00403     for (int i = 0; i < length; i++)
00404       if ((xdir = ndir[i]) != 0 && xdir != TWOPI) // still extension?
00405       {
00406         int x = xloc[i], y = yloc[i];
00407         int dir = bytePixel(direction, x, y); // direction of step
00408         slope = BestStepExtension(*smooth,
00409                                   x, y, dir + xdir,     // current end pt
00410                                   threshold,
00411                                   x, y, dir, loc);
00412         if (slope) {                 // next end point
00413           xloc[i] = x, yloc[i] = y; // update new end point
00414           xdir = LeftXorRightEnd(contour,    // mark completed if
00415                                  x, y, dir); // another contour is reached,
00416                                              // indicated by xdir==0.
00417           if (xdir)
00418           {
00419             if (x < rmax || x > xmax || // check for reaching border
00420                 y < rmax || y > ymax)
00421               xdir = 0;               // junction with virtual border
00422             else
00423               nextension++;
00424             floatPixel(contour, x, y) = slope; // still disconnected
00425           }
00426           else
00427           {           // touching another contour
00428             ntouch++;
00429             xdir = TWOPI;     // mark junction, without linking chains
00430           }
00431           ndir[i] = xdir;
00432           bytePixel(direction, x, y) = byte(dir);
00433           floatPixel(locationx, x, y) = loc*DIS[dir];
00434           floatPixel(locationy, x, y) = loc*DJS[dir];
00435         } else                  // no further extension found
00436           ndir[i] = 0;
00437       }
00438     //vcl_cout << "Touch " << ntouch << " contours.\n";
00439     // vcl_cout << "Will extend " << nextension << " contours.\n";
00440     njunction += ntouch;
00441     if (!nextension) break;     // all either junction or termination
00442   }
00443   delete smooth;
00444 
00445   // 3. Return the end points or junctions found
00446   if (junctionx) delete [] junctionx;
00447   if (junctiony) delete [] junctiony;
00448   junctionx = new int[njunction];
00449   junctiony = new int[njunction];
00450   for (int i = 0, j = 0; i < length; i++)
00451     if (ndir[i] == TWOPI) {
00452       junctionx[j] = xloc[i];
00453       junctiony[j] = yloc[i];
00454       j++;
00455     }
00456 #if defined(DEBUG)
00457   vcl_cout << "Find " << length << " end points, and "
00458            << njunction << " junctions.\n"
00459            << "Recover " << 100.0*njunction/length
00460            << "% end points as junctions > "
00461            << threshold << ", in " << t.real() << " msecs.\n";
00462 #endif
00463   return njunction;
00464 }
00465 
00466 
00467 //:
00468 // Return the standard deviation of raw noise, in the original image,
00469 // either estimated or given by the user. If the noise has not been
00470 // estimated, return 0.
00471 float
00472 gevd_step::NoiseSigma() const
00473 {
00474   return (noiseSigma <= 0)? 0: noiseSigma;
00475 }
00476 
00477 
00478 //:
00479 // Compute response of white noise through the filter dG, or
00480 // second-derivative of the Gaussian. Using a threshold of 3 times
00481 // this noise response would eliminate 99% of the noise edges.
00482 float
00483 gevd_step::NoiseResponse() const
00484 {
00485   return NoiseResponseToFilter(noiseSigma,
00486                                smoothSigma, filterFactor);
00487 }
00488 
00489 
00490 //:
00491 // Return threshold for detecting contour or junction,
00492 // which is response of white gaussian noise, noise_sigma,
00493 // to step edge detector, i.e. first-order derivative of Gaussian,
00494 // smooth_sigma.
00495 // noise_sigma can be estimated by finding the standard deviation
00496 // in a region of constant intensity, and no texture patterns.
00497 // Use short_factor*noise_sigma and smooth_sigma/2, when detecting
00498 // junctions, to account for multiple responses to step edge detector.
00499 float
00500 gevd_step::NoiseThreshold(bool shortp) const
00501 {
00502   float factor = (shortp? junctionFactor : contourFactor);
00503   float smooth = (shortp? smoothSigma/2 : smoothSigma);
00504   return factor * 3 *          // 3*sigma for 99% removal confidence
00505          NoiseResponseToFilter(noiseSigma, smooth, filterFactor);
00506 }
00507 
00508 
00509 //:
00510 // Compute response of white noise through the filter dG, or
00511 // first-derivative of the Gaussian. Using a threshold of 3 times
00512 // this noise response would eliminate 99% of the noise edges.
00513 float
00514 gevd_step::NoiseResponseToFilter(const float noiseSigma,
00515                                  const float smoothSigma,
00516                                  const float filterFactor)
00517 {
00518   return noiseSigma /          // white noise
00519          (float)vcl_pow((double)smoothSigma, 1.5) * // size of filter dG
00520          (0.5f / (float)vcl_pow(vnl_math::pi, 0.25)) *
00521          filterFactor;        // multiplication factor
00522 }
00523 
00524 
00525 //: Output a snapshot of current control parameters
00526 vcl_ostream& operator<< (vcl_ostream& os, const gevd_step& st)
00527 {
00528   os << "Step:\n"
00529      << "   smoothSigma " << st.smoothSigma << vcl_endl
00530      << "   noiseSigma " << st.noiseSigma << vcl_endl
00531      << "   contourFactor " << st.contourFactor << vcl_endl
00532      << "   junctionFactor " << st.junctionFactor << vcl_endl
00533      << "   filterFactor " << st.filterFactor << vcl_endl;
00534     return os;
00535 }
00536 
00537 
00538 //: Output a snapshot of current control parameters
00539 vcl_ostream& operator<< (vcl_ostream& os, gevd_step& st)
00540 {
00541   os << "Step:\n"
00542      << "   smoothSigma " << st.smoothSigma << vcl_endl
00543      << "   noiseSigma " << st.noiseSigma << vcl_endl
00544      << "   contourFactor " << st.contourFactor << vcl_endl
00545      << "   junctionFactor " << st.junctionFactor << vcl_endl
00546      << "   filterFactor " << st.filterFactor << vcl_endl;
00547     return os;
00548 }

Generated on Thu Jan 8 05:15:48 2009 for contrib/gel/gevd by  doxygen 1.5.1