00001
00002 #include "vdgl_digital_region.h"
00003
00004
00005
00006 #include <vcl_cmath.h>
00007 #include <vcl_cassert.h>
00008 #include <vnl/algo/vnl_svd.h>
00009 #include <vnl/vnl_float_3.h>
00010
00011 #ifndef MAX_ROUNDOFF
00012 #define MAX_ROUNDOFF .000025
00013 #endif
00014
00015 #define near_zero(a) (vcl_fabs (a) < MAX_ROUNDOFF)
00016
00017 vsol_spatial_object_2d* vdgl_digital_region::clone() const
00018 {
00019 return new vdgl_digital_region(*this);
00020 }
00021
00022
00023
00024
00025 vdgl_digital_region::vdgl_digital_region(vdgl_digital_region const& r)
00026 : vsol_region_2d(r),
00027 npts_(0), pixel_size_(1.f), xp_(0), yp_(0), pix_(0),
00028 max_(0), min_((unsigned short)(-1)), xo_(0.f), yo_(0.f),
00029 io_(0.f), io_stdev_(0.0f), pix_index_(0),
00030 fit_valid_(false), scatter_matrix_valid_(false),
00031 X2_(0), Y2_(0), I2_(0), XY_(0), XI_(0), YI_(0), error_(0), sigma_sq_(0)
00032 {
00033 for (unsigned int i = 0; i<r.Npix(); ++i)
00034 this->IncrementMeans(r.Xj()[i], r.Yj()[i], r.Ij()[i]);
00035 this->InitPixelArrays();
00036 for (unsigned int i = 0; i<r.Npix(); i++)
00037 this->InsertInPixelArrays(r.Xj()[i], r.Yj()[i], r.Ij()[i]);
00038 this->ComputeIntensityStdev();
00039 }
00040
00041 vdgl_digital_region::vdgl_digital_region(int npts, const float* xp, const float* yp,
00042 const unsigned short *pix)
00043 : vsol_region_2d(),
00044 npts_(0), pixel_size_(1.f), xp_(0), yp_(0), pix_(0),
00045 max_(0), min_((unsigned short)(-1)), xo_(0.f), yo_(0.f),
00046 io_(0.f), io_stdev_(0.0f), pix_index_(0),
00047 fit_valid_(false), scatter_matrix_valid_(false),
00048 X2_(0), Y2_(0), I2_(0), XY_(0), XI_(0), YI_(0), error_(0), sigma_sq_(0)
00049 {
00050 assert(npts > 0);
00051 for (int i = 0; i<npts; i++)
00052 this->IncrementMeans(xp[i], yp[i], pix[i]);
00053 this->InitPixelArrays();
00054 for (unsigned int i = 0; i<npts_; i++)
00055 this->InsertInPixelArrays(xp[i], yp[i], pix[i]);
00056 this->ComputeIntensityStdev();
00057 }
00058
00059
00060
00061
00062
00063 vdgl_digital_region::~vdgl_digital_region()
00064 {
00065 delete[] xp_;
00066 delete[] yp_;
00067 delete[] pix_;
00068 }
00069
00070
00071
00072 float vdgl_digital_region::X() const
00073 {
00074 if (pix_index_<0 || pix_index_ >= (int)npts_)
00075 return 0.0f;
00076 else
00077 return xp_[pix_index_];
00078 }
00079
00080
00081
00082 float vdgl_digital_region::Y() const
00083 {
00084 if (pix_index_<0 || pix_index_ >= (int)npts_)
00085 return 0.0f;
00086 else
00087 return yp_[pix_index_];
00088 }
00089
00090
00091
00092 unsigned short vdgl_digital_region::I() const
00093 {
00094 if (pix_index_<0 || pix_index_ >= (int)npts_)
00095 return (unsigned short)0;
00096 else
00097 return pix_[pix_index_];
00098 }
00099
00100
00101
00102 void vdgl_digital_region::set_X(float x)
00103 {
00104 if (pix_index_<0 || pix_index_ >= (int)npts_)
00105 return;
00106 xp_[pix_index_]=x;
00107 }
00108
00109
00110
00111 void vdgl_digital_region::set_Y(float y)
00112 {
00113 if (pix_index_<0 || pix_index_ >= (int)npts_)
00114 return;
00115 yp_[pix_index_]=y;
00116 }
00117
00118
00119
00120 void vdgl_digital_region::set_I(unsigned short I)
00121 {
00122 if (pix_index_<0 || pix_index_ >= (int)npts_)
00123 return;
00124 pix_[pix_index_]=I;
00125 }
00126
00127
00128
00129
00130
00131 void vdgl_digital_region::ResetPixelData()
00132 {
00133 npts_ = 0;
00134 delete [] xp_; xp_ = NULL;
00135 delete [] yp_; yp_ = NULL;
00136 delete [] pix_; pix_ = NULL;
00137 xo_ = yo_ = io_ = io_stdev_=0.0f;
00138 }
00139
00140
00141
00142
00143
00144
00145
00146
00147 void vdgl_digital_region::IncrementMeans(float x, float y,
00148 unsigned short pix)
00149 {
00150 ++npts_;
00151 xo_ += x;
00152 yo_ += y;
00153 io_ += pix;
00154 }
00155
00156
00157
00158
00159
00160 float vdgl_digital_region::ComputeIntensityStdev()
00161 {
00162 io_stdev_ = 0.0f;
00163 float mean = this->Io();
00164 for (unsigned int i=0; i<npts_; i++) {
00165 io_stdev_ += (pix_[i]-mean)*(pix_[i]-mean);
00166 }
00167 io_stdev_ = io_stdev_ * 1.0f/(npts_ - 1.0f);
00168 io_stdev_ = vcl_sqrt(io_stdev_);
00169 return io_stdev_;
00170 }
00171
00172
00173
00174
00175 void vdgl_digital_region::InitPixelArrays()
00176 {
00177 assert(npts_ > 0);
00178 delete [] xp_; xp_ = new float[npts_];
00179 delete [] yp_; yp_ = new float[npts_];
00180 delete [] pix_; pix_ = new unsigned short[npts_];
00181 pix_index_ = 0;
00182 min_ = (unsigned short)(-1);
00183 max_ = 0;
00184 }
00185
00186
00187
00188 void vdgl_digital_region::InsertInPixelArrays(float x, float y,
00189 unsigned short pix)
00190 {
00191 assert(npts_ > 0);
00192 if (pix_index_<0||pix_index_>(int)npts_) return;
00193 xp_[pix_index_] = x; yp_[pix_index_] = y;
00194 pix_[pix_index_] = pix;
00195 if (pix<min_) min_ = pix;
00196 if (pix>max_) max_ = pix;
00197 ++pix_index_;
00198 }
00199
00200 float vdgl_digital_region::Xo() const
00201 {
00202 assert(npts_ > 0);
00203 return xo_/npts_;
00204 }
00205
00206 float vdgl_digital_region::Yo() const
00207 {
00208 assert(npts_ > 0);
00209 return yo_/npts_;
00210 }
00211
00212 float vdgl_digital_region::Io() const
00213 {
00214 assert(npts_ > 0);
00215 return io_/npts_;
00216 }
00217
00218 float vdgl_digital_region::Io_sd() const
00219 {
00220 assert(npts_ > 0);
00221 return io_stdev_;
00222 }
00223
00224
00225 double vdgl_digital_region::X2() const
00226 {
00227 if (!scatter_matrix_valid_)
00228 this->ComputeScatterMatrix();
00229 return X2_;
00230 }
00231
00232 double vdgl_digital_region::Y2() const
00233 {
00234 if (!scatter_matrix_valid_)
00235 this->ComputeScatterMatrix();
00236 return Y2_;
00237 }
00238
00239 double vdgl_digital_region::XY() const
00240 {
00241 if (!scatter_matrix_valid_)
00242 this->ComputeScatterMatrix();
00243 return XY_;
00244 }
00245
00246 double vdgl_digital_region::I2() const
00247 {
00248 if (!scatter_matrix_valid_)
00249 this->ComputeScatterMatrix();
00250 return I2_;
00251 }
00252
00253 double vdgl_digital_region::XI() const
00254 {
00255 if (!scatter_matrix_valid_)
00256 this->ComputeScatterMatrix();
00257 return XI_;
00258 }
00259
00260 double vdgl_digital_region::YI() const
00261 {
00262 if (!scatter_matrix_valid_)
00263 this->ComputeScatterMatrix();
00264 return YI_;
00265 }
00266
00267
00268
00269 float vdgl_digital_region::Diameter() const
00270 {
00271
00272 if (!scatter_matrix_valid_)
00273 this->ComputeScatterMatrix();
00274 if (this->Npix() < 4)
00275 return 1.0f;
00276
00277 vnl_matrix<double> s(2, 2, 0.0);
00278 for (int r = 1; r<=2; r++)
00279 for (int c = 1; c<=2; c++)
00280 s(r-1,c-1) = Si_(r,c);
00281
00282 vnl_svd<double> svd(s);
00283 if (svd.rank()!=2)
00284 return float(vcl_sqrt(this->area()));
00285
00286 double radius = 2*vcl_sqrt(vcl_fabs(svd.W(0))+ vcl_fabs(svd.W(1)));
00287 return float(2*radius);
00288 }
00289
00290
00291
00292 float vdgl_digital_region::AspectRatio() const
00293 {
00294
00295 if (!scatter_matrix_valid_)
00296 this->ComputeScatterMatrix();
00297 if (this->Npix() < 4)
00298 return 1.0f;
00299
00300 vnl_matrix<double> s(2, 2, 0.0);
00301 for (int r = 1; r<=2; r++)
00302 for (int c = 1; c<=2; c++)
00303 s(r-1,c-1) = Si_(r,c);
00304
00305 vnl_svd<double> svd(s);
00306 if (svd.rank()!=2)
00307 return 1.0f;
00308 return (float)vcl_sqrt(svd.W(0)/svd.W(1));
00309 }
00310
00311
00312
00313
00314 void vdgl_digital_region::PrincipalOrientation(vnl_float_2& major_axis)
00315 {
00316
00317 if (!scatter_matrix_valid_)
00318 this->ComputeScatterMatrix();
00319 if (this->Npix() < 4)
00320 {
00321 vcl_cout << "In vdgl_digital_region::PrincipalOrientation(..) Npts<4\n";
00322 major_axis[0]=1.0; major_axis[1]=0.0;
00323 return;
00324 }
00325
00326 vnl_matrix<double> s(2, 2, 0.0);
00327 for (int r = 1; r<=2; r++)
00328 for (int c = 1; c<=2; c++)
00329 s(r-1,c-1) = Si_(r,c);
00330
00331 vnl_svd<double> svd(s);
00332 if (svd.rank()!=2)
00333 {
00334 vcl_cout << "In vdgl_digital_region::PrincipalOrientation(..) Insufficient rank\n";
00335 major_axis[0]=1.0; major_axis[1]=0.0;
00336 return;
00337 }
00338 vnl_matrix<double> v = svd.V();
00339
00340 double radius = 2*vcl_sqrt(vcl_fabs(svd.W(0)));
00341 major_axis[0]=float(v(0,0)*radius);
00342 major_axis[1]=float(v(1,0)*radius);
00343 }
00344
00345 double vdgl_digital_region::Ix() const
00346 {
00347 if (!fit_valid_)
00348 this->DoPlaneFit();
00349 return Ix_;
00350 }
00351
00352 double vdgl_digital_region::Iy() const
00353 {
00354 if (!fit_valid_)
00355 this->DoPlaneFit();
00356 return Iy_;
00357 }
00358
00359
00360
00361
00362
00363
00364 void vdgl_digital_region::IncrByXYI(double x, double y, int intens) const
00365 {
00366 fit_valid_=false;
00367 scatter_matrix_valid_=false;
00368 double dbx = x - this->Xo(), dby = y - this->Yo();
00369 double dint = (double)intens- this->Io();
00370 X2_ += dbx*dbx; Y2_ += dby*dby; I2_ += dint*dint;
00371 XY_ += dbx*dby; XI_ += dbx*dint; YI_ += dby*dint;
00372 }
00373
00374
00375
00376 void vdgl_digital_region::ComputeScatterMatrix() const
00377 {
00378 if (!npts_)
00379 {
00380 vcl_cout << "In vdgl_digital_region::ComputeScatterMatrix() - no pixels\n";
00381 return;
00382 }
00383 X2_ = 0; Y2_ = 0; I2_ = 0;
00384 XY_ = 0; XI_ = 0; YI_ = 0;
00385
00386 for (this->reset(); this->next();)
00387 this->IncrByXYI(this->X(), this->Y(), this->I());
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 Si_(0,0) = I2_/npts_;
00401 Si_(1,0) = Si_(0,1) = XI_/npts_;
00402 Si_(2,0) = Si_(0,2) = YI_/npts_;
00403 Si_(1,1) = X2_/npts_;
00404 Si_(2,1) = Si_(1,2) = XY_/npts_;
00405 Si_(2,2) = Y2_/npts_;
00406 scatter_matrix_valid_ = true;
00407 }
00408
00409
00410
00411
00412 double vdgl_digital_region::ComputeSampleResidual() const
00413 {
00414 if (!fit_valid_)
00415 this->DoPlaneFit();
00416 return Si_(0,0) + Si_(1,1) + Si_(2,2);
00417 }
00418
00419
00420
00421 void vdgl_digital_region::DoPlaneFit() const
00422 {
00423 assert(npts_ >= 4);
00424 fit_valid_ = true;
00425
00426 if (!scatter_matrix_valid_)
00427 this->ComputeScatterMatrix();
00428
00429 double den = Si_(1,1)*Si_(2,2)
00430 - Si_(1,2)*Si_(2,1);
00431 if (near_zero(den))
00432 {
00433 vcl_cout << "In vdgl_digital_region::SolveForPlane(..) determinant near zero\n";
00434 Ix_ = Iy_ = 0;
00435 error_ = Si_(0,0);
00436 sigma_sq_ = Si_(0,0) + Si_(1,1) + Si_(2,2);
00437 return;
00438 }
00439 double adet = Si_(0,1)*Si_(2,2)
00440 - Si_(0,2)*Si_(2,1);
00441 double bdet = Si_(0,2)*Si_(1,1)
00442 - Si_(0,1)*Si_(1,2);
00443 Ix_ = adet/den;
00444 Iy_ = bdet/den;
00445 error_ = Si_(0,0) - 2*Ix_*Si_(0,1) - 2*Iy_*Si_(0,2)
00446 + Ix_*Ix_*Si_(1,1) + 2*Ix_*Iy_*Si_(1,2) + Iy_*Iy_*Si_(2,2);
00447 sigma_sq_ = this->ComputeSampleResidual();
00448 }
00449
00450
00451 void vdgl_digital_region::PrintFit() const
00452 {
00453 if (!fit_valid_)
00454 this->DoPlaneFit();
00455 vcl_cout << "IntensityFit(In Plane Coordinates): "
00456 << "Number of Points =" << npts_ << vcl_endl
00457 << "Scatter Matrix:\n"
00458 << "X2 Y2 I2 " << X2() << ' ' << Y2() << ' ' << I2() << vcl_endl
00459 << "XY XI YI = " << XY() << ' ' << XI() << ' ' << YI() << vcl_endl
00460 << "Xo Yo Io " << Xo() << ' ' << Yo() << ' ' << Io() << vcl_endl
00461 << "fitted Plane:\n"
00462 << "di/dx " << this->Ix() << vcl_endl
00463 << "di/dy " << this->Iy() << vcl_endl
00464 << "sample variance: " << this->Var()<< vcl_endl
00465 << "squared cost: " << error_ << vcl_endl
00466 << "average cost: " << vcl_sqrt(error_) << vcl_endl << vcl_endl;
00467 }
00468
00469 #if 0
00470
00471
00472
00473 IntensityCoef_ref vdgl_digital_region::GetIntCoef() const
00474 {
00475 if (!fit_valid_)
00476 this->DoPlaneFit();
00477 return new IntensityCoef(this->Npix(), float(this->Var()),
00478 float(this->Io()), float(this->Ix()),
00479 float(this->Iy()));
00480 }
00481 #endif
00482
00483
00484
00485 float vdgl_digital_region::Ir() const
00486 {
00487 if (pix_index_<0 || pix_index_ >= (int)npts_)
00488 return 0.0f;
00489 if (npts_<4)
00490 return 0.0f;
00491
00492 if (!fit_valid_)
00493 {
00494 int initial_pix_index = pix_index_;
00495 this->DoPlaneFit();
00496 pix_index_ = initial_pix_index;
00497 }
00498 float val = float(this->I());
00499 float io = this->Io(),
00500 ix = float(this->Ix()), x = this->X(), xo = this->Xo(),
00501 iy = float(this->Iy()), y = this->Y(), yo = this->Yo();
00502 float plane_int = io + ix*(x - xo) + iy*(y-yo);
00503
00504 return val - plane_int;
00505 }
00506
00507 bool vdgl_digital_region::transform(vnl_float_3x3 const& t)
00508 {
00509
00510 if (npts_ == 0)
00511 return false;
00512 for (unsigned int i=0; i<npts_; i++)
00513 {
00514 vnl_float_3 p = t * vnl_float_3(xp_[i], yp_[i], 1.0f);
00515 xp_[i]=p[0]/p[2];
00516 yp_[i]=p[1]/p[2];
00517 }
00518
00519 vnl_float_3 m = t * vnl_float_3(this->Xo(), this->Yo(), 1.0f);
00520 xo_ = m[0]/m[2]*npts_;
00521 yo_ = m[1]/m[2]*npts_;
00522 fit_valid_ = false;
00523 scatter_matrix_valid_=false;
00524 return true;
00525 }
00526
00527
00528
00529 vcl_vector<unsigned int> vdgl_digital_region::histogram(int nbins)
00530 {
00531 assert(nbins > 0);
00532 if (nbins == 1) return vcl_vector<unsigned int>(1, npts_);
00533 vcl_vector<unsigned int> hist(nbins, 0U);
00534 if (npts_ == 0) return hist;
00535 float res = max_-min_, step = res/nbins + 1e-6f;
00536 for (unsigned int i =0; i<npts_; ++i)
00537 ++hist[int((pix_[i]-min_)/step)];
00538 return hist;
00539 }
00540
00541 vcl_vector<unsigned int> vdgl_digital_region::residual_histogram(int nbins,
00542 float* min,
00543 float* max)
00544 {
00545 assert(nbins > 0);
00546 if (nbins == 1) return vcl_vector<unsigned int>(1, npts_);
00547 vcl_vector<unsigned int> hist(nbins, 0U);
00548 if (npts_ == 0) return hist;
00549 this->reset();
00550 float mini = this->Ir(), maxi=mini;
00551 while (this->next())
00552 {
00553 float ir = this->Ir();
00554 if (ir<mini) mini = ir;
00555 if (ir>maxi) maxi = ir;
00556 }
00557 if (min) *min = mini;
00558 if (max) *max = maxi;
00559 float res = maxi-mini, step = res/nbins + 1e-6f;
00560 for (this->reset(); this->next(); )
00561 ++hist[int((this->Ir()-mini)/step)];
00562 return hist;
00563 }