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 = vnl_math::deg_per_rad;
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 }
00178 else {
00179 vcl_cout << "Can not estimate sensor & texture noise\n";
00180 noiseSigma = 1;
00181 }
00182 }
00183 else {
00184 vcl_cout << "Not enough edge elements to estimate noise\n";
00185 noiseSigma = 1;
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
00211
00212 gevd_float_operators::NonMaximumSuppression(*slope, *dirx, *diry,
00213 NoiseThreshold(),
00214 contour, direction,
00215 locationx, locationy);
00216 delete slope; delete dirx; delete diry;
00217 gevd_float_operators::FillFrameX(*contour, 0, FRAME);
00218 gevd_float_operators::FillFrameY(*contour, 0, FRAME);
00219 return true;
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
00252
00253 static int
00254 LeftXorRightEnd(const gevd_bufferxy& contour,
00255 int i, int j,
00256 const int dir)
00257 {
00258 int di = DIS[dir], dj = DJS[dir];
00259 bool normalp = (floatPixel(contour, i - di, j - dj) ||
00260 floatPixel(contour, i + di, j + dj));
00261 if (normalp)
00262 return 0;
00263 bool leftp = false;
00264 int ndir = dir - HALFPI;
00265 for (int n = 0; n < 3; ++n) {
00266 int theta = ndir + RDS[n];
00267 if (floatPixel(contour, i+DIS[theta], j+DJS[theta])) {
00268 leftp = true;
00269 break;
00270 }
00271 }
00272 bool rightp = false;
00273 ndir = dir + HALFPI;
00274 for (int n = 0; n < 3; ++n) {
00275 int theta = ndir + RDS[n];
00276 if (floatPixel(contour, i+DIS[theta], j+DJS[theta])) {
00277 rightp = true;
00278 break;
00279 }
00280 }
00281 return (leftp? 0: -HALFPI) + (rightp? 0: HALFPI);
00282 }
00283
00284
00285
00286
00287
00288
00289
00290 static float
00291 BestStepExtension(const gevd_bufferxy& smooth,
00292 const int i, const int j,
00293 const int ndir,
00294 const float threshold,
00295 int& best_i, int& best_j,
00296 int& best_d, float& best_l)
00297 {
00298 float best_s = threshold;
00299 const int direc = ndir + HALFPI;
00300 for (int n = 0; n < 3; n++) {
00301 int ntheta = ndir + RDS[n];
00302 int ni = i + DIS[ntheta];
00303 int nj = j + DJS[ntheta];
00304 float pix = floatPixel(smooth, ni, nj);
00305 for (int d = 0; d < 3; d++) {
00306 int dir = direc + RDS[d];
00307 int di = DIS[dir];
00308 int dj = DJS[dir];
00309 float pix_m = floatPixel(smooth, ni-di, nj-dj);
00310 float pix_p = floatPixel(smooth, ni+di, nj+dj);
00311 float slope = (float)vcl_fabs(pix_p - pix_m);
00312 float max_s = (dir%HALFPI)? best_s*(float)vcl_sqrt(2.0): best_s;
00313 if (slope > max_s) {
00314 int di2 = 2*di;
00315 int dj2 = 2*dj;
00316 if (slope > vcl_fabs(pix - floatPixel(smooth, ni-di2, nj-dj2)) &&
00317 slope > vcl_fabs(pix - floatPixel(smooth, ni+di2, nj+dj2))) {
00318 best_i = ni;
00319 best_j = nj;
00320 best_s = (dir%HALFPI)? slope/(float)vcl_sqrt(2.0) : slope;
00321 best_d = dir%FULLPI + TWOPI;
00322 }
00323 }
00324 }
00325 }
00326 if (best_s > threshold) {
00327 float pix = floatPixel(smooth, best_i, best_j);
00328 int di2 = 2 * DIS[best_d], dj2 = 2 * DJS[best_d];
00329 float s_m = (float)vcl_fabs(pix - floatPixel(smooth, best_i-di2, best_j-dj2));
00330 float s_p = (float)vcl_fabs(pix - floatPixel(smooth, best_i+di2, best_j+dj2));
00331 if (best_d%HALFPI) {
00332 s_m /= (float)vcl_sqrt(2.0);
00333 s_p /= (float)vcl_sqrt(2.0);
00334 }
00335 best_l = gevd_float_operators::InterpolateParabola(s_m, best_s, s_p, best_s);
00336 return best_s;
00337 }
00338 else
00339 return 0;
00340 }
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354 int
00355 gevd_step::RecoverJunctions(const gevd_bufferxy& image,
00356 gevd_bufferxy& contour, gevd_bufferxy& direction,
00357 gevd_bufferxy& locationx, gevd_bufferxy& locationy,
00358 int*& junctionx, int*& junctiony)
00359 {
00360 #if defined(DEBUG)
00361 vul_timer t;
00362 #endif
00363 if (image.GetBitsPixel() != bits_per_float) {
00364 vcl_cerr << "gevd_step::RecoverJunction requires float image\n";
00365 return false;
00366 }
00367 const int rmax = 1+FRAME;
00368 const int kmax = int(4 * smoothSigma + 0.5) + 2;
00369 const int xmax = image.GetSizeX()-rmax-1;
00370 const int ymax = image.GetSizeY()-rmax-1;
00371 #ifdef DEBUG
00372 vcl_cout << "RecoverJunctions: rmax, kmax, xmax, ymax:" << rmax << ' ' << kmax << ' ' << xmax << ' ' << ymax << '\n';
00373 #endif
00374
00375
00376
00377
00378 vcl_vector<int> ndir;
00379 vcl_vector<int> xloc;
00380 vcl_vector<int> yloc;
00381 int xdir;
00382 for (int y = rmax; y <= ymax; y++)
00383 for (int x = rmax; x <= xmax; x++)
00384 if (floatPixel(contour, x, y) &&
00385 (xdir = LeftXorRightEnd(contour, x, y,
00386 bytePixel(direction, x, y))) != 0)
00387 {
00388 ndir.push_back(xdir);
00389 xloc.push_back(x);
00390 yloc.push_back(y);
00391 }
00392 const int length = ndir.size();
00393
00394
00395 if (!length) return 0;
00396
00397
00398 gevd_bufferxy* smooth = NULL;
00399 gevd_float_operators::Gaussian((gevd_bufferxy&)image, smooth, smoothSigma/2);
00400 const bool shortp = true;
00401 const float threshold = NoiseThreshold(shortp);
00402 float slope, loc;
00403 int njunction = 0;
00404 for (int r = 1; r <= kmax; r++) {
00405 int ntouch = 0, nextension = 0;
00406 for (int i = 0; i < length; i++)
00407 if ((xdir = ndir[i]) != 0 && xdir != TWOPI)
00408 {
00409 int x = xloc[i], y = yloc[i];
00410 int dir = bytePixel(direction, x, y);
00411 slope = BestStepExtension(*smooth,
00412 x, y, dir + xdir,
00413 threshold,
00414 x, y, dir, loc);
00415 if (slope) {
00416 xloc[i] = x, yloc[i] = y;
00417 xdir = LeftXorRightEnd(contour,
00418 x, y, dir);
00419
00420 if (xdir)
00421 {
00422 if (x < rmax || x > xmax ||
00423 y < rmax || y > ymax)
00424 xdir = 0;
00425 else
00426 nextension++;
00427 floatPixel(contour, x, y) = slope;
00428 }
00429 else
00430 {
00431 ntouch++;
00432 xdir = TWOPI;
00433 }
00434 ndir[i] = xdir;
00435 bytePixel(direction, x, y) = byte(dir);
00436 floatPixel(locationx, x, y) = loc*DIS[dir];
00437 floatPixel(locationy, x, y) = loc*DJS[dir];
00438 }
00439 else
00440 ndir[i] = 0;
00441 }
00442
00443
00444 njunction += ntouch;
00445 if (!nextension) break;
00446 }
00447 delete smooth;
00448
00449
00450 if (junctionx) delete [] junctionx;
00451 if (junctiony) delete [] junctiony;
00452 junctionx = new int[njunction];
00453 junctiony = new int[njunction];
00454 for (int i = 0, j = 0; i < length; i++)
00455 if (ndir[i] == TWOPI) {
00456 junctionx[j] = xloc[i];
00457 junctiony[j] = yloc[i];
00458 j++;
00459 }
00460 #if defined(DEBUG)
00461 vcl_cout << "Find " << length << " end points, and "
00462 << njunction << " junctions.\n"
00463 << "Recover " << 100.0*njunction/length
00464 << "% end points as junctions > "
00465 << threshold << ", in " << t.real() << " msecs.\n";
00466 #endif
00467 return njunction;
00468 }
00469
00470
00471
00472
00473
00474
00475 float
00476 gevd_step::NoiseSigma() const
00477 {
00478 return (noiseSigma <= 0)? 0: noiseSigma;
00479 }
00480
00481
00482
00483
00484
00485
00486 float
00487 gevd_step::NoiseResponse() const
00488 {
00489 return NoiseResponseToFilter(noiseSigma,
00490 smoothSigma, filterFactor);
00491 }
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503 float
00504 gevd_step::NoiseThreshold(bool shortp) const
00505 {
00506 float factor = (shortp? junctionFactor : contourFactor);
00507 float smooth = (shortp? smoothSigma/2 : smoothSigma);
00508 return factor * 3 *
00509 NoiseResponseToFilter(noiseSigma, smooth, filterFactor);
00510 }
00511
00512
00513
00514
00515
00516
00517 float
00518 gevd_step::NoiseResponseToFilter(const float noiseSigma,
00519 const float smoothSigma,
00520 const float filterFactor)
00521 {
00522 return noiseSigma /
00523 (float)vcl_pow((double)smoothSigma, 1.5) *
00524 (0.5f / (float)vcl_pow(vnl_math::pi, 0.25)) *
00525 filterFactor;
00526 }
00527
00528
00529
00530 vcl_ostream& operator<< (vcl_ostream& os, const gevd_step& st)
00531 {
00532 os << "Step:\n"
00533 << " smoothSigma " << st.smoothSigma << vcl_endl
00534 << " noiseSigma " << st.noiseSigma << vcl_endl
00535 << " contourFactor " << st.contourFactor << vcl_endl
00536 << " junctionFactor " << st.junctionFactor << vcl_endl
00537 << " filterFactor " << st.filterFactor << vcl_endl;
00538 return os;
00539 }
00540
00541
00542
00543 vcl_ostream& operator<< (vcl_ostream& os, gevd_step& st)
00544 {
00545 os << "Step:\n"
00546 << " smoothSigma " << st.smoothSigma << vcl_endl
00547 << " noiseSigma " << st.noiseSigma << vcl_endl
00548 << " contourFactor " << st.contourFactor << vcl_endl
00549 << " junctionFactor " << st.junctionFactor << vcl_endl
00550 << " filterFactor " << st.filterFactor << vcl_endl;
00551 return os;
00552 }