00001
00002 #include "gevd_step.h"
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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,
00038 1, 1, 0,-1,-1,-1, 0, 1,
00039 1, 1, 0,-1,-1,-1, 0, 1};
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};
00044
00045
00046 const int FRAME = 4;
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 gevd_step::gevd_step(float smooth_sigma,
00080 float noise_sigma,
00081 float contour_factor, float junction_factor)
00082 : smoothSigma(smooth_sigma), noiseSigma(noise_sigma),
00083 contourFactor(contour_factor), junctionFactor(junction_factor),
00084 filterFactor(2)
00085 {
00086 if (smoothSigma < 0.5)
00087 vcl_cerr << "gevd_step::gevd_step -- too small smooth_sigma: "
00088 << smoothSigma << vcl_endl;
00089 if (smoothSigma > 3)
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
00099 }
00100
00101
00102
00103 gevd_step::~gevd_step() {}
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
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
00127
00128
00129 if (image.GetBitsPixel() != bits_per_float) {
00130 vcl_cerr << "gevd_step::DetectEdgels requires float image\n";
00131 return false;
00132 }
00133
00134
00135
00136
00137 gevd_bufferxy* smooth = NULL;
00138
00139 filterFactor = gevd_float_operators::Gaussian((gevd_bufferxy&)image,
00140 smooth, smoothSigma);
00141
00142
00143 gevd_bufferxy *slope = NULL, *dirx=NULL, *diry=NULL;
00144 filterFactor *= gevd_float_operators::Gradient(*smooth,
00145 slope, dirx, diry);
00146 delete smooth;
00147
00148
00149
00150
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
00165 if (noiseSigma <= 0) {
00166 int nedgel = 0;
00167 float* edgels = gevd_noise::EdgelsInCenteredROI(*slope, *dirx, *diry,
00168 nedgel);
00169 if ((edgels) && (nedgel > 0 )) {
00170 gevd_noise noise(edgels, nedgel);
00171 delete [] edgels;
00172 float sensorNoise, textureNoise;
00173 if (noise.EstimateSensorTexture(sensorNoise, textureNoise)) {
00174 const float k = -noiseSigma;
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;
00180 }
00181 } else {
00182 vcl_cout << "Not enough edge elements to estimate noise\n";
00183 noiseSigma = 1;
00184 }
00185
00186 }
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 gevd_float_operators::NonMaximumSuppression(*slope, *dirx, *diry,
00211 NoiseThreshold(),
00212 contour, direction,
00213 locationx, locationy);
00214 delete slope; delete dirx; delete diry;
00215 gevd_float_operators::FillFrameX(*contour, 0, FRAME);
00216 gevd_float_operators::FillFrameY(*contour, 0, FRAME);
00217 return true;
00218 }
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 static int
00252 LeftXorRightEnd(const gevd_bufferxy& contour,
00253 int i, int j,
00254 const int dir)
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)
00260 return 0;
00261 bool leftp = false;
00262 int ndir = dir - HALFPI;
00263 for (int n = 0; n < 3; ++n) {
00264 int theta = ndir + RDS[n];
00265 if (floatPixel(contour, i+DIS[theta], j+DJS[theta])) {
00266 leftp = true;
00267 break;
00268 }
00269 }
00270 bool rightp = false;
00271 ndir = dir + HALFPI;
00272 for (int n = 0; n < 3; ++n) {
00273 int theta = ndir + RDS[n];
00274 if (floatPixel(contour, i+DIS[theta], j+DJS[theta])) {
00275 rightp = true;
00276 break;
00277 }
00278 }
00279 return (leftp? 0: -HALFPI) + (rightp? 0: HALFPI);
00280 }
00281
00282
00283
00284
00285
00286
00287
00288 static float
00289 BestStepExtension(const gevd_bufferxy& smooth,
00290 const int i, const int j,
00291 const int ndir,
00292 const float threshold,
00293 int& best_i, int& best_j,
00294 int& best_d, float& best_l)
00295 {
00296 float best_s = threshold;
00297 const int direc = ndir + HALFPI;
00298 for (int n = 0; n < 3; n++) {
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);
00303 for (int d = 0; d < 3; d++) {
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) {
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;
00320 }
00321 }
00322 }
00323 }
00324 if (best_s > threshold) {
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
00336 return 0;
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
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;
00365 const int kmax = int(4 * smoothSigma + 0.5) + 2;
00366 const int xmax = image.GetSizeX()-rmax-1;
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
00372
00373
00374
00375 vcl_vector<int> ndir;
00376 vcl_vector<int> xloc;
00377 vcl_vector<int> yloc;
00378 int xdir;
00379 for (int y = rmax; y <= ymax; y++)
00380 for (int x = rmax; x <= xmax; x++)
00381 if (floatPixel(contour, x, y) &&
00382 (xdir = LeftXorRightEnd(contour, x, y,
00383 bytePixel(direction, x, y))) != 0)
00384 {
00385 ndir.push_back(xdir);
00386 xloc.push_back(x);
00387 yloc.push_back(y);
00388 }
00389 const int length = ndir.size();
00390
00391
00392 if (!length) return 0;
00393
00394
00395 gevd_bufferxy* smooth = NULL;
00396 gevd_float_operators::Gaussian((gevd_bufferxy&)image, smooth, smoothSigma/2);
00397 const bool shortp = true;
00398 const float threshold = NoiseThreshold(shortp);
00399 float slope, loc;
00400 int njunction = 0;
00401 for (int r = 1; r <= kmax; r++) {
00402 int ntouch = 0, nextension = 0;
00403 for (int i = 0; i < length; i++)
00404 if ((xdir = ndir[i]) != 0 && xdir != TWOPI)
00405 {
00406 int x = xloc[i], y = yloc[i];
00407 int dir = bytePixel(direction, x, y);
00408 slope = BestStepExtension(*smooth,
00409 x, y, dir + xdir,
00410 threshold,
00411 x, y, dir, loc);
00412 if (slope) {
00413 xloc[i] = x, yloc[i] = y;
00414 xdir = LeftXorRightEnd(contour,
00415 x, y, dir);
00416
00417 if (xdir)
00418 {
00419 if (x < rmax || x > xmax ||
00420 y < rmax || y > ymax)
00421 xdir = 0;
00422 else
00423 nextension++;
00424 floatPixel(contour, x, y) = slope;
00425 }
00426 else
00427 {
00428 ntouch++;
00429 xdir = TWOPI;
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
00436 ndir[i] = 0;
00437 }
00438
00439
00440 njunction += ntouch;
00441 if (!nextension) break;
00442 }
00443 delete smooth;
00444
00445
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
00469
00470
00471 float
00472 gevd_step::NoiseSigma() const
00473 {
00474 return (noiseSigma <= 0)? 0: noiseSigma;
00475 }
00476
00477
00478
00479
00480
00481
00482 float
00483 gevd_step::NoiseResponse() const
00484 {
00485 return NoiseResponseToFilter(noiseSigma,
00486 smoothSigma, filterFactor);
00487 }
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
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 *
00505 NoiseResponseToFilter(noiseSigma, smooth, filterFactor);
00506 }
00507
00508
00509
00510
00511
00512
00513 float
00514 gevd_step::NoiseResponseToFilter(const float noiseSigma,
00515 const float smoothSigma,
00516 const float filterFactor)
00517 {
00518 return noiseSigma /
00519 (float)vcl_pow((double)smoothSigma, 1.5) *
00520 (0.5f / (float)vcl_pow(vnl_math::pi, 0.25)) *
00521 filterFactor;
00522 }
00523
00524
00525
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
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 }