00001
00059
00060
00061
00062
00063
00064
00065
00066 #ifndef MODEL_H_
00067 #define MODEL_H_
00068
00069 namespace intern {
00070
00072 template<int Degree2>
00073 inline float _intersect(const float mx, const float my, const typename Param<Degree2>::VectorU &p) {
00074 Eigen::Matrix<float, Degree2+1, 1> _p;
00075
00076 int n = 0;
00077 _p.fill(0);
00078 _p(1) = -1.f;
00079 for(int i=0; i<=Degree2; i++)
00080 for(int j=0; j<=i; j++) {
00081 _p(i) += p(i*(i+1)/2+j)*std::pow(mx,j)*std::pow(my,i-j);
00082 if(std::abs(_p(i))>0.000001f) n=i;
00083 }
00084
00085 std::vector<double> realRoots;
00086 if(n==Degree2) {
00087 Eigen::PolynomialSolver<float, Degree2> ps(_p);
00088 ps.realRoots( realRoots );
00089 }
00090 else if(n==0)
00091 return _p(0);
00092 else if(n==1)
00093 return -_p(0)/_p(1);
00094 else {
00095 Eigen::PolynomialSolver<float, Eigen::Dynamic> ps(_p.head(n+1));
00096 ps.realRoots( realRoots );
00097 }
00098
00099 for(size_t i=0; i<realRoots.size(); i++)
00100 if(realRoots[i]>0) return realRoots[i];
00101
00102 return 0.f;
00103 }
00104
00106 template<>
00107 inline float _intersect<1>(const float mx, const float my, const typename Param<1>::VectorU &p) {
00108 return -p(0)/(my*p(1)+mx*p(2)-1);
00109 }
00110 }
00111
00112
00116 template <int Degree>
00117 struct Model {
00118 typedef Eigen::Matrix<float, 2*Degree+1, 1> VectorU1D;
00119 typedef Eigen::Matrix<float, 2*Degree+1, 2*Degree+1> MatrixU1D;
00120
00121 Param<Degree> param;
00122 typename Param<Degree>::VectorU p;
00123
00124 Model() {p.fill(0.f);}
00125 Model(const Param<Degree> &pa) {p.fill(0.f); *this+=pa;}
00126
00128 inline VectorU1D transformation_1D(const Eigen::Vector2f &dir, const Eigen::Vector2f &off, const Eigen::Vector3f &at) {
00129 Eigen::Matrix<float, Degree+1, 1> t; t.fill(0);
00130 typename Param<Degree>::VectorU pp = p;
00131 pp(0) -= at(2);
00132
00133 for(int i=0; i<=Degree; i++)
00134 for(int j=0; j<=i; j++)
00135 for(int k=0; k<=j; k++)
00136 for(int kk=0; kk<=i-j; kk++)
00137 t(k+kk) += pp(i*(i+1)/2+j)*
00138 boost::math::binomial_coefficient<float>(j, k)* std::pow(dir(0),k)* std::pow(off(0),j-k)*
00139 boost::math::binomial_coefficient<float>(i-j, kk)*std::pow(dir(1),kk)*std::pow(off(1),i-j-kk);
00140
00141 const Eigen::Matrix<float, Degree+1, Degree+1> M = t*t.transpose();
00142 VectorU1D r;
00143 r.fill(0);
00144
00145 for(int i=0; i<=Degree; i++)
00146 for(int ii=0; ii<=Degree; ii++)
00147 r(i+ii) += M(i, ii);
00148
00149 const float x0=off(0)-at(0), y0=off(1)-at(1);
00150 r(0) += x0*x0 + y0*y0;
00151 r(1) += 2*x0*dir(0) + 2*y0*dir(1);
00152 r(2) += dir(0)*dir(0) + dir(1)*dir(1);
00153
00154 return r;
00155 }
00156
00160
00161
00162
00163
00164
00168 bool isLinearAndTo()
00169 {
00170 if(Degree==1) return true;
00171
00172
00173 const float Vx = x();
00174 const float Vy = y();
00175
00176 if(Vx<0.001f && Vy<0.001f)
00177 {
00178
00179 return false;
00180 }
00181
00182 Model temp=*this;
00183 temp.getLinear2();
00184
00185
00186 const float error2 = (temp.param.z_ - temp.param.model_*temp.p).norm();
00187 const float d=temp.param.z_(0)/temp.param.model_(0,0);
00188
00189 float delta = 0.f;
00190 for(int i=3; i<p.cols(); i++)
00191 delta += std::abs(p(i));
00192
00193 if(
00194 (error2 > (temp.param.model_(0,0)*temp.param.model_(0,0))/(1<<13)*d*d || (delta)/(std::abs(p(1))+std::abs(p(2)))>1.f))
00195 {
00196
00197 return false;
00198 }
00199
00200 *this = temp;
00201
00202
00203
00204 return true;
00205 }
00206
00210 inline float get_max_gradient(const Param<Degree> ¶) const {
00211 const float x = this->x();
00212 const float y = this->y();
00213 float dx=0.f, dy=0.f;
00214 for(int i=1; i<=Degree; i++)
00215 for(int j=0; j<=i; j++) {
00216 if(i!=j) dy += (i-j)* p(i*(i+1)/2+j)*std::pow(x,j) * std::pow(y,i-j-1);
00217 if(j!=0) dx += j* p(i*(i+1)/2+j)*std::pow(y,i-j) * std::pow(x,j-1);
00218 }
00219
00220 return std::abs(dx) + std::abs(dy);
00221 }
00222
00226 inline bool check_tangent(const Param<Degree> ¶, const float thr) const {
00227 const float t=(para.z_(0)-(para.model_.row(0)*p)(0))/para.model_(0,0);
00228
00229 const float x = this->x();
00230 const float y = this->y();
00231 float dx=0.f, dy=0.f;
00232 for(int i=1; i<=Degree; i++)
00233 for(int j=0; j<=i; j++) {
00234
00235
00236
00237 if(i!=j) dy += (i-j)*p(i*(i+1)/2+j)*std::pow(x,j) * std::pow(y,i-j-1);
00238 if(j!=0) dx += i*p(i*(i+1)/2+j)*std::pow(y,i-j) * std::pow(x,j-1);
00239 }
00240
00241 Eigen::Vector3f r;
00242 r(0)=dx;
00243 r(1)=dy;
00244 r(2)=1.f;
00245
00246 return t*t<thr*thr*r.squaredNorm();
00247 }
00248
00252 float model(const float x, const float y) const {
00253 float r=0.f;
00254 for(int i=0; i<=Degree; i++)
00255 for(int j=0; j<=i; j++)
00256 r += p(i*(i+1)/2+j)*std::pow(x,j)*std::pow(y,i-j);
00257 return r;
00258 }
00259
00264 void get() {
00265 if(param.model_(0,0)==0) {
00266 p.fill(0.f);
00267 }
00268 else {
00269 p.head(Param<Degree>::NUM)=param.model_.topLeftCorner(Param<Degree>::NUM,Param<Degree>::NUM).fullPivLu().solve(param.z_.head(Param<Degree>::NUM));
00270
00271 if(!pcl_isfinite(p(1))) {
00272 p.head(Param<Degree>::NUM)=param.model_.topLeftCorner(Param<Degree>::NUM,Param<Degree>::NUM).ldlt().solve(param.z_.head(Param<Degree>::NUM));
00273
00274 if(!pcl_isfinite(p(1))) {
00275 ROS_ERROR("failure 0x0176");
00276 std::cerr<<param.model_<<"\n";
00277 std::cerr<<param.z_<<"\n";
00278 }
00279 }
00280
00281 }
00282 }
00283
00285 Eigen::Vector3f getLinear() const {
00286 Eigen::Vector3f r;
00287
00288 if(param.model_(0,0)!=0) {
00289 Eigen::Matrix3f M = param.model_.topLeftCorner(3,3);
00290 Eigen::Vector3f z = param.z_.head(3);
00291 r=M.fullPivLu().solve(z);
00292 }
00293 else r.fill(0);
00294
00295 return r;
00296 }
00297
00299 void getLinear2()
00300 {
00301 Eigen::Vector3f r=getLinear();
00302 p.fill(0);
00303 p(0)=r(0);
00304 p(1)=r(1);
00305 p(2)=r(2);
00306 }
00307
00309 Eigen::Vector3f getNormal_(const float x, const float y) const {
00310 Eigen::Vector3f n;
00311 n(2)=1;
00312 n(0)=n(1)=0;
00313 for(int i=1; i<=Degree; i++)
00314 for(int j=0; j<=i; j++) {
00315 if(i!=j) n(1) -= (i-j)* p(i*(i+1)/2+j)*std::pow(x,j) * std::pow(y,i-j-1);
00316 if(j!=0) n(0) -= j* p(i*(i+1)/2+j)*std::pow(y,i-j) * std::pow(x,j-1);
00317 }
00318 return n;
00319 }
00320
00322 Eigen::Vector3f getNormal(const float x, const float y) const {
00323 Eigen::Vector3f n = getNormal_(x,y);
00324 n.normalize();
00325 return n;
00326 }
00327
00329 void operator+=(const Model &m) {
00330 param+=m.param;
00331 }
00332
00334 void operator+=(const Param<Degree> &m) {
00335 param+=m;
00336 }
00337
00339 inline float intersect(const float mx, const float my) const {
00340 return intern::_intersect<Degree>(mx,my,p);
00341 }
00342
00344 inline float x() const {return param.model_(0,2)/param.model_(0,0);}
00346 inline float y() const {return param.model_(0,1)/param.model_(0,0);}
00348 inline float z() const {return param.z_(0)/param.model_(0,0);}
00349 };
00350
00351 #ifdef QPPF_SPECIALIZATION_2
00352
00355 template <>
00356 struct Model<2> {
00357 Param<2> param;
00358 typename Param<2>::VectorU p;
00359
00360 Model() {p.fill(0.f);}
00361 Model(const Param<2> &pa) {p.fill(0.f); *this+=pa;}
00362
00366 inline bool checkZ(const Param<2> ¶, const float thr) const {
00367 float d=std::abs((para.model_.row(0)*p)(0)-para.z_(0));
00368 return d<thr*para.model_(0,0);
00369 }
00370
00374 bool isLinearAndTo()
00375 {
00376
00377 const float Vx = (param.model_(1,1)-param.model_(0,1)*param.model_(0,1)/param.model_(0,0))/param.model_(0,0);
00378 const float Vy = (param.model_(3,3)-param.model_(0,3)*param.model_(0,3)/param.model_(0,0))/param.model_(0,0);
00379
00380 if(Vx<0.001f && Vy<0.001f)
00381 {
00382
00383 return false;
00384 }
00385
00386 Model temp=*this;
00387 temp.getLinear2();
00388
00389
00390 const float error2 = (temp.param.z_ - temp.param.model_*temp.p).norm();
00391 const float d=temp.param.z_(0)/temp.param.model_(0,0);
00392
00393 if(
00394 (error2 > (temp.param.model_(0,0)*temp.param.model_(0,0))/(1<<13)*d*d || (std::abs(p(2))+std::abs(p(4))+std::abs(p(5)))/(std::abs(p(1))+std::abs(p(3)))>1.f))
00395 {
00396
00397 return false;
00398 }
00399
00400 *this = temp;
00401
00402
00403
00404 return true;
00405 }
00406
00410 inline float get_max_gradient(const Param<2> ¶) const {
00411 return
00412 std::abs(2.f*para.model_(0,1)/para.model_(0,0)*p(2)+p(1)+para.model_(0,3)/para.model_(0,0)*p(5))
00413 + std::abs(2.f*para.model_(0,3)/para.model_(0,0)*p(4)+p(3)+para.model_(0,1)/para.model_(0,0)*p(5));
00414 }
00415
00419 inline bool check_tangent(const Param<2> ¶, const float thr) const {
00420 const float t=(para.z_(0)-(para.model_.row(0)*p)(0))/para.model_(0,0);
00421
00422 Eigen::Vector3f r;
00423 r(0)=2.f*para.model_(0,1)/para.model_(0,0)*p(2)+p(1)+para.model_(0,3)/para.model_(0,0)*p(5);
00424 r(1)=2.f*para.model_(0,3)/para.model_(0,0)*p(4)+p(3)+para.model_(0,1)/para.model_(0,0)*p(5);
00425 r(2)=1.f;
00426
00427 return t*t<thr*thr*r.squaredNorm();
00428 }
00429
00433
00434
00435
00436
00437
00441 float model(const float x, const float y) const {
00442 return p(0)+p(1)*x+p(2)*x*x+p(3)*y+p(4)*y*y+p(5)*x*y;
00443 }
00444
00445 float getCorrelation() const {
00446 return (
00447 param.model_(1,3)-param.model_(0,1)*param.model_(0,3)/param.model_(0,0)
00448 )
00449 /sqrtf(
00450 (param.model_(1,1)-param.model_(0,1)*param.model_(0,1)/param.model_(0,0))*
00451 (param.model_(3,3)-param.model_(0,3)*param.model_(0,3)/param.model_(0,0))
00452 );
00453 }
00454
00459 void get() {
00460 if(param.model_(0,0)==0) {
00461 p.fill(0.f);
00462 }
00463
00464
00465
00466
00467 else {
00468
00469 p.head<Param<2>::NUM>()=param.model_.topLeftCorner<Param<2>::NUM,Param<2>::NUM>().fullPivLu().solve(param.z_.head<Param<2>::NUM>());
00470
00471 if(!pcl_isfinite(p(1))) {
00472 p.head<Param<2>::NUM>()=param.model_.topLeftCorner<Param<2>::NUM,Param<2>::NUM>().ldlt().solve(param.z_.head<Param<2>::NUM>());
00473
00474 if(!pcl_isfinite(p(1))) {
00475 ROS_ERROR("failure 0x0176");
00476 std::cerr<<param.model_<<"\n";
00477 std::cerr<<param.z_<<"\n";
00478 }
00479 }
00480
00481 }
00482 }
00483
00484 Eigen::Matrix3f getLinearMatrix() const {
00485 Eigen::Matrix3f M;
00486 for(int i=0; i<3; i++)
00487 for(int j=0; j<3; j++)
00488 M(i,j)=param.model_(i>1?3:i, j>1?3:j);
00489 return M;
00490 }
00491
00492 Eigen::Vector3f getLinear() const {
00493 Eigen::Vector3f r;
00494 r.fill(0);
00495 if(param.model_(0,0)!=0) {
00496 Eigen::Matrix3f M;
00497 Eigen::Vector3f z;
00498 z(0)=param.z_(0);
00499 z(1)=param.z_(1);
00500 z(2)=param.z_(3);
00501 for(int i=0; i<3; i++)
00502 for(int j=0; j<3; j++)
00503 M(i,j)=param.model_(i>1?3:i, j>1?3:j);
00504
00505 r=M.fullPivLu().solve(z);
00506
00507
00508 }
00509
00510 return r;
00511 }
00512
00513 void getLinear2()
00514 {
00515 Eigen::Vector3f r=getLinear();
00516 p(0)=r(0);
00517 p(1)=r(1);
00518 p(2)=0;
00519 p(3)=r(2);
00520 p(4)=0;
00521 p(5)=0;
00522 }
00523
00524 Eigen::Vector3f getLinearNormal() {
00525 Eigen::Vector3f n,t=getLinear();
00526 n(2)=1;
00527 n(0)=t(1);
00528 n(1)=t(2);
00529 n.normalize();
00530 return n;
00531 }
00532
00533 Eigen::Vector3f getNormal(const float x, const float y) const {
00534 Eigen::Vector3f n;
00535 n(2)=1;
00536 n(0)=-(p(1)+2*x*p(2)+p(5)*y);
00537 n(1)=-(p(3)+2*x*p(4)+p(5)*x);
00538 n.normalize();
00539 return n;
00540 }
00541
00542 void operator+=(const Model &m) {
00543 param+=m.param;
00544 }
00545 void operator+=(const Param<2> &m) {
00546 param+=m;
00547 }
00548
00549 float intersect(const float mx, const float my) const {
00550 float a=mx*mx*p(2) + my*my*p(4) + mx*my*p(5);
00551 float b=mx*p(1) + my*p(3) - 1;
00552
00553 if(std::abs(a)<0.00001f) {
00554 return -p(0)/b;
00555 }
00556
00557 float t,z2;
00558
00559
00560 t=b*b-4*a*p(0);
00561 z2=(-b-sqrtf(t))/(2*a);
00562
00563
00564
00565
00566
00567
00568 #if DEBUG_LEVEL >70
00569 if(!pcl_isfinite(z2)) {
00570 std::cerr<<"t: "<<t<<"\n";
00571 std::cerr<<"a: "<<a<<"\n";
00572 }
00573 #endif
00574
00575
00576
00577
00578
00579
00580
00581
00582 return z2;
00583 }
00584
00585 inline float x() const {return param.model_(0,1)/param.model_(0,0);}
00586 inline float y() const {return param.model_(0,3)/param.model_(0,0);}
00587 inline float z() const {return param.z_(0)/param.model_(0,0);}
00588 };
00589 #endif
00590
00591 #endif