00001
00008 #include <blort/Recognizer3D/Homography.hh>
00009
00010
00011 #ifndef M_SQRT2
00012 #define M_SQRT2 1.41421356237309504880 // sqrt(2)
00013 #endif
00014
00015
00016 #define HOM_RANSAC_ETA0 0.01 //0.01
00017 #define HOM_MAX_RANSAC_TRIALS 10000
00018
00019 namespace P
00020 {
00021
00022 Homography::Homography()
00023 : lastPt(0), lastLn(0), T1(0), invT(0)
00024 {
00025 }
00026
00027 Homography::Homography(unsigned nbPoints, unsigned nbLines)
00028 : lastPt(0), lastLn(0), T1(0), invT(0)
00029 {
00030 if (nbPoints>0)
00031 {
00032 pts1.Resize(nbPoints);
00033 pts2.Resize(nbPoints);
00034 }
00035 if (nbLines>0)
00036 {
00037 lns1.Resize(nbLines);
00038 lns2.Resize(nbLines);
00039 }
00040 }
00041
00042 Homography::~Homography()
00043 {
00044 if (T1!=0) delete[] T1;
00045 if (invT!=0) delete[] invT;
00046 }
00047
00048
00052 void Homography::GetRandIdx(unsigned size, unsigned num, P::Array<unsigned> &idx)
00053 {
00054 unsigned temp;
00055 idx.Clear();
00056 for (unsigned i=0; i<num; i++)
00057 {
00058 do{
00059 temp = rand()%size;
00060 }while(idx.Contains(temp));
00061 idx.PushBack(temp);
00062 }
00063 }
00064
00068 void Homography::CountInlierPts(double H[9], double thr, int &inl)
00069 {
00070 Vector2 p;
00071
00072 for (unsigned i=0; i<lastPt; i++)
00073 {
00074 MapPoint(&pts1[i].x, H, &p.x);
00075
00076 if (Distance(p,pts2[i]) < thr)
00077 inl++;
00078 }
00079 }
00080
00084 void Homography::CountInlierLns(double H[9], double thr, double thrAngle, int &inl)
00085 {
00086 double HT[9];
00087 Transpose33(H, HT);
00088
00089 double thrAng = cos(thrAngle * M_PI/180.);
00090
00091 double k1, d1, k2, d2, dist1, dist2;
00092 Vector2 l2, dir1, dir2;
00093 Vector2 p1, p2, p0 = Vector2(0.,0.);
00094
00095 for (unsigned i=0; i<lastLn; i++)
00096 {
00097 MapPoint(&lns2[i].x, HT, &l2.x);
00098
00099 k1 = -lns1[i].x/lns1[i].y;
00100 d1 = -1./lns1[i].y;
00101 dir1.y = d1;
00102 dir1.x = 1.;
00103 dir1.Normalise();
00104
00105 k2 = -l2.x/l2.y;
00106 d2 = -1./l2.y;
00107 dir2.y = d2;
00108 dir2.x = 1.;
00109 dir2.Normalise();
00110
00111 p1.x = 1.;
00112 p1.y = k1+d1;
00113 p2.x = 1.;
00114 p2.y = k2+d2;
00115
00116 dist1 = AbsDistPointToLine(p0, p1, dir1);
00117 dist2 = AbsDistPointToLine(p0, p2, dir2);
00118
00119 if (fabs(dist1-dist2) < thr)
00120 {
00121 if (fabs(Dot(dir1,dir2)) > thrAng)
00122 {
00123 inl++;
00124 }
00125 }
00126 }
00127
00128 }
00129
00133 void Homography::SetDataMatrix(double *d, double H[9], double thr, double thrAngle, int &numInl)
00134 {
00135 numInl=0;
00136
00137
00138 Vector2 p;
00139
00140 outl.Resize(lastPt);
00141 outl.Set(0);
00142
00143 for (unsigned i=0; i<lastPt; i++)
00144 {
00145 MapPoint(&pts1[i].x, H, &p.x);
00146
00147 if (Distance(p,pts2[i]) < thr)
00148 {
00149 InsertPointCoeff(pts1[i], pts2[i], &d[numInl*18]);
00150 numInl++;
00151 }
00152 else
00153 {
00154 outl[i] = 1;
00155 }
00156 }
00157
00158
00159 double HT[9];
00160 Transpose33(H, HT);
00161
00162 double thrAng = cos(thrAngle * M_PI/180.);
00163
00164 double k1, d1, k2, d2, dist1, dist2;
00165 Vector2 l2, dir1, dir2;
00166 Vector2 p1, p2, p0 = Vector2(0.,0.);
00167
00168 outlLns.Resize(lastLn);
00169 outlLns.Set(0);
00170 for (unsigned i=0; i<lastLn; i++)
00171 {
00172 MapPoint(&lns2[i].x, HT, &l2.x);
00173
00174 k1 = -lns1[i].x/lns1[i].y;
00175 d1 = -1./lns1[i].y;
00176 dir1.y = d1;
00177 dir1.x = 1.;
00178 dir1.Normalise();
00179
00180 k2 = -l2.x/l2.y;
00181 d2 = -1./l2.y;
00182 dir2.y = d1;
00183 dir2.x = 1.;
00184 dir2.Normalise();
00185
00186 p1.x = 1.;
00187 p1.y = k1+d1;
00188 p2.x = 1.;
00189 p2.y = k2+d2;
00190
00191 dist1 = AbsDistPointToLine(p0, p1, dir1);
00192 dist2 = AbsDistPointToLine(p0, p2, dir2);
00193
00194 if (fabs(dist1-dist2) < thr)
00195 {
00196 if (fabs(Dot(dir1, dir2)) > thrAng)
00197 {
00198 InsertLineCoeff(lns1[i], lns2[i], &d[numInl*18]);
00199 numInl++;
00200 }
00201 else
00202 outlLns[i] = 1;
00203 }
00204 else
00205 outlLns[i] = 1;
00206 }
00207
00208 }
00209
00213 bool Homography::SolveHomography(CvMat *A, CvMat *W, CvMat *Ut, CvMat *Vt, double H[9])
00214 {
00215 cvSVD( A, W, Ut, Vt, CV_SVD_MODIFY_A);
00216
00217
00218 unsigned z;
00219 for(z=0; z<9; z++)
00220 if(IsZero(cvmGet(W,z,z))) break;
00221
00222 if(z<8)
00223 return false;
00224
00225
00226 for (unsigned i=0; i<9; i++)
00227 H[i] = cvmGet(Vt,i,8);
00228
00229 return true;
00230 }
00231
00235 void Homography::NormalizePts(Array<Vector2> &in, unsigned numPts, Array<Vector2> &out, double T[9])
00236 {
00237 if (numPts==0)
00238 return;
00239
00240 double centx=0., centy=0.;
00241 double dist, scale;
00242
00243 for(unsigned i=0; i<numPts; i++)
00244 {
00245 centx+=in[i].x;
00246 centy+=in[i].y;
00247 }
00248
00249 centx/=(double)(numPts);
00250 centy/=(double)(numPts);
00251
00252 out.Resize(numPts);
00253 for(unsigned i=0; i<numPts; i++)
00254 {
00255 out[i].x = in[i].x-centx;
00256 out[i].y = in[i].y-centy;
00257 }
00258
00259 dist=0.0;
00260 for(unsigned i=0; i<numPts; i++)
00261 dist += Length(out[i]);
00262
00263 dist/=(double)(numPts);
00264 scale = M_SQRT2/dist;
00265
00266 for (unsigned i=0; i<numPts; i++)
00267 out[i]*=scale;
00268
00269 T[0]=scale; T[1]=0.0; T[2]=-centx*scale;
00270 T[3]=0.0; T[4]=scale; T[5]=-centy*scale;
00271 T[6]=0.0; T[7]=0.0; T[8]=1.0;
00272 }
00273
00274
00278 void Homography::NormalizeLns(double T[9], Array<Vector2> &in, unsigned numLns, Array<Vector2> &out)
00279 {
00280 if (numLns==0)
00281 return;
00282
00283 double t;
00284 out.Resize(numLns);
00285
00286 for (unsigned i=0; i<numLns; i++)
00287 {
00288 t = 1./(T[0] + T[2]*in[i].x + T[5]*in[i].y);
00289 out[i].x = in[i].x*t;
00290 out[i].y = in[i].y*t;
00291 }
00292 }
00293
00297 void Homography::SetDataMatrixPts(Array<Vector2> &pts1, Array<Vector2> &pts2, unsigned numPts, unsigned start, CvMat *A)
00298 {
00299 if (numPts==0)
00300 return;
00301
00302 double t1, t2, t3, t4;
00303 double *d = A->data.db + (start*2)*A->cols;
00304
00305 for (unsigned i=0; i<numPts; i++,d+=18)
00306 {
00307 t1 = pts1[i].x;
00308 t2 = pts1[i].y;
00309 t3 = pts2[i].x;
00310 t4 = pts2[i].y;
00311
00312 d[0] = -t1;
00313 d[1] = -t2;
00314 d[2] = -1.0;
00315 d[3] = 0.0;
00316 d[4] = 0.0;
00317 d[5] = 0.0;
00318 d[6] = t3*t1;
00319 d[7] = t2*t3;
00320 d[8] = t3;
00321 d[9] = 0.0;
00322 d[10] = 0.0;
00323 d[11] = 0.0;
00324 d[12] = d[0];
00325 d[13] = d[1];
00326 d[14] = -1.0;
00327 d[15] = t4*t1;
00328 d[16] = t4*t2;
00329 d[17] = t4;
00330 }
00331 }
00332
00336 void Homography::SetDataMatrixLns(Array<Vector2> &lns1, Array<Vector2> &lns2, unsigned numLns, unsigned start, CvMat *A)
00337 {
00338 if (numLns==0)
00339 return;
00340
00341 double t1, t2, t3, t4;
00342 double *d = A->data.db + (start*2)*A->cols;
00343
00344 for (unsigned i=0; i<numLns; i++,d+=18)
00345 {
00346 t1 = lns1[i].x;
00347 t2 = lns1[i].y;
00348 t3 = lns2[i].x;
00349 t4 = lns2[i].y;
00350
00351 d[0] = -t3;
00352 d[1] = 0.;
00353 d[2] = t3*t1;
00354 d[3] = -t4;
00355 d[4] = 0.;
00356 d[5] = t4*t1;
00357 d[6] = -1;
00358 d[7] = 0.;
00359 d[8] = t1;
00360 d[9] = 0.;
00361 d[10] = -t3;
00362 d[11] = t3*t2;
00363 d[12] = 0.;
00364 d[13] = -t4;
00365 d[14] = t4*t2;
00366 d[15] = 0.;
00367 d[16] = -1;
00368 d[17] = t2;
00369 }
00370 }
00371
00376 void Homography::NormalizeH(double H[9], double T1[9], double T2[9], double nH[9])
00377 {
00378 double T1_1[9], tmp[9];
00379
00380 Inv33(T1, T1_1);
00381 Mul33(T2, H, tmp);
00382 Mul33(tmp, T1_1, nH);
00383 }
00384
00389 void Homography::DenormalizeH(double nH[9], double T1[9], double T2[9], double H[9])
00390 {
00391 double T2_1[9], tmp[9];
00392
00393 Inv33(T2, T2_1);
00394 Mul33(T2_1, nH, tmp);
00395 Mul33(tmp, T1, H);
00396 }
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00414 bool Homography::EstimateHom(double H[9], int &nbOutliers, double inlPcent, bool returnOutl, int normalize, int NLrefine, int verbose)
00415 {
00416 int err;
00417
00418 if (!returnOutl)
00419 {
00420 err = homest((double (*)[2])(&pts1[0]), (double (*)[2])(&pts2[0]), lastPt, inlPcent, H,
00421 normalize, NLrefine, 0, &nbOutliers, verbose);
00422 }
00423 else
00424 {
00425 Array<int> tmpOutl(pts1.Size());
00426 err = homest((double (*)[2])(&pts1[0]), (double (*)[2])(&pts2[0]), lastPt, inlPcent, H,
00427 normalize, NLrefine, &tmpOutl[0], &nbOutliers, verbose);
00428
00429 outl.Resize(pts1.Size());
00430 outl.Set(0);
00431 for (int i=0; i<nbOutliers; i++)
00432 {
00433 outl[tmpOutl[i]] = 1;
00434 }
00435 }
00436
00437 if (err==HOMEST_ERR)
00438 return false;
00439 return true;
00440 }
00441
00446 bool Homography::EstimateAff(double H[9], int &nbOutliers, double inlPcent, bool returnOutl, int normalize, int verbose)
00447 {
00448 int err;
00449
00450 if (!returnOutl)
00451 {
00452 err = homestaff((double (*)[2])(&pts1[0]), (double (*)[2])(&pts2[0]), lastPt, inlPcent, H,
00453 normalize, 0, &nbOutliers, verbose);
00454 }
00455 else
00456 {
00457 outl.Resize(pts1.Size());
00458 err = homestaff((double (*)[2])(&pts1[0]), (double (*)[2])(&pts2[0]), lastPt, inlPcent, H,
00459 normalize, &outl[0], &nbOutliers, verbose);
00460 }
00461
00462 if (err==HOMEST_ERR)
00463 return false;
00464 return true;
00465 }
00466
00470 bool Homography::ComputeHom(double a1[2], double a2[2], double a3[2], double a4[2],
00471 double b1[2], double b2[2], double b3[2], double b4[2],
00472 double H[9])
00473 {
00474
00475
00476 if (T1==0) T1 = new double[9];
00477 if (invT==0) invT = new double[9];
00478
00479
00480 double s = (a2[0]-a3[0]) * (a4[1]-a3[1]) - (a4[0]-a3[0]) * (a2[1]-a3[1]);
00481
00482 if (IsZero(s)) return false;
00483
00484 T1[6] = ((a1[0]-a2[0]+a3[0]-a4[0])*(a4[1]-a3[1]) -
00485 (a1[1]-a2[1]+a3[1]-a4[1])*(a4[0]-a3[0])) / s;
00486 T1[7] = ((a1[1]-a2[1]+a3[1]-a4[1])*(a2[0]-a3[0]) -
00487 (a1[0]-a2[0]+a3[0]-a4[0])*(a2[1]-a3[1])) / s;
00488 T1[8] = 1.;
00489
00490 T1[0] = a2[0]-a1[0] + T1[6]*a2[0]; T1[1] = a4[0]-a1[0] + T1[7]*a4[0]; T1[2] = a1[0];
00491 T1[3] = a2[1]-a1[1] + T1[6]*a2[1]; T1[4] = a4[1]-a1[1] + T1[7]*a4[1]; T1[5] = a1[1];
00492
00493 if (!Inv33(T1, invT)) return false;
00494
00495
00496 s = (b2[0]-b3[0]) * (b4[1]-b3[1]) - (b4[0]-b3[0]) * (b2[1]-b3[1]);
00497
00498 if (IsZero(s)) return false;
00499
00500 T1[6] = ((b1[0]-b2[0]+b3[0]-b4[0])*(b4[1]-b3[1]) -
00501 (b1[1]-b2[1]+b3[1]-b4[1])*(b4[0]-b3[0])) / s;
00502 T1[7] = ((b1[1]-b2[1]+b3[1]-b4[1])*(b2[0]-b3[0]) -
00503 (b1[0]-b2[0]+b3[0]-b4[0])*(b2[1]-b3[1])) / s;
00504 T1[8] = 1.;
00505
00506 T1[0] = b2[0]-b1[0] + T1[6]*b2[0]; T1[1] = b4[0]-b1[0] + T1[7]*b4[0]; T1[2] = b1[0];
00507 T1[3] = b2[1]-b1[1] + T1[6]*b2[1]; T1[4] = b4[1]-b1[1] + T1[7]*b4[1]; T1[5] = b1[1];
00508
00509
00510 Mul33(T1,invT,H);
00511
00512 if (IsZero(H[8]))
00513 return false;
00514
00515 Mul33(H, 1./H[8], H);
00516
00517 return true;
00518 }
00519
00523 bool Homography::ComputeAff(double a1[2], double a2[2], double a3[2],
00524 double b1[2], double b2[2], double b3[2],
00525 double H[9])
00526 {
00527 double S;
00528
00529 S = a1[0]*(a3[1]-a2[1]) +
00530 a2[0]*(a1[1]-a3[1]) +
00531 a3[0]*(a2[1]-a1[1]);
00532
00533 if (IsZero(S)) return false;
00534
00535 S=1/S;
00536
00537
00538 H[0] = S * (a1[1]*(b2[0]-b3[0]) + a2[1]*(b3[0]-b1[0])+ a3[1]*(b1[0]-b2[0]));
00539 H[1] = S * (a1[0]*(b3[0]-b2[0]) + a2[0]*(b1[0]-b3[0])+ a3[0]*(b2[0]-b1[0]));
00540 H[3] = S * (a1[1]*(b2[1]-b3[1]) + a2[1]*(b3[1]-b1[1])+ a3[1]*(b1[1]-b2[1]));
00541 H[4] = S * (a1[0]*(b3[1]-b2[1]) + a2[0]*(b1[1]-b3[1])+ a3[0]*(b2[1]-b1[1]));
00542 H[2] = S * (a1[0]*(a3[1]*b2[0]-a2[1]*b3[0])+
00543 a2[0]*(a1[1]*b3[0]-a3[1]*b1[0])+
00544 a3[0]*(a2[1]*b1[0]-a1[1]*b2[0]));
00545 H[5] = S * (a1[0]*(a3[1]*b2[1]-a2[1]*b3[1])+
00546 a2[0]*(a1[1]*b3[1]-a3[1]*b1[1])+
00547 a3[0]*(a2[1]*b1[1]-a1[1]*b2[1]));
00548 H[6] = 0;
00549 H[7] = 0;
00550 H[8] = 1;
00551
00552 return true;
00553 }
00554
00555
00560 bool Homography::ComputeHomLS(double H[9], bool normalize)
00561 {
00562 if ((normalize && lastPt<2) || lastPt+lastLn < 5)
00563 return false;
00564
00565 bool ok;
00566 unsigned size = 2*(lastPt+lastLn);
00567
00568 CvMat *A = cvCreateMat(size, 9, CV_64F);
00569 CvMat *W = cvCreateMat(9, 9, CV_64F);
00570 CvMat *Ut = cvCreateMat(size,9, CV_64F);
00571 CvMat *Vt = cvCreateMat(9, 9, CV_64F);
00572 double T1[9], T2[9];
00573
00574 if (normalize)
00575 {
00576 Array<Vector2> npts1, npts2;
00577 Array<Vector2> nlns1, nlns2;
00578
00579 NormalizePts(pts1, lastPt, npts1, T1);
00580 NormalizePts(pts2, lastPt, npts2, T2);
00581 NormalizeLns(T1, lns1, lastLn, nlns1);
00582 NormalizeLns(T2, lns2, lastLn, nlns2);
00583
00584 SetDataMatrixPts(npts1,npts2, lastPt, 0, A);
00585 SetDataMatrixLns(nlns1,nlns2, lastLn, lastPt, A);
00586 }
00587 else
00588 {
00589 SetDataMatrixPts(pts1, pts2, lastPt, 0, A);
00590 SetDataMatrixLns(lns1, lns2, lastLn, lastPt, A);
00591 }
00592
00593 ok = SolveHomography(A, W, Ut, Vt, H);
00594
00595 if (ok)
00596 {
00597 if (normalize)
00598 DenormalizeH(H, T1, T2, H);
00599
00600 Mul33(H,1./H[8],H);
00601 }
00602
00603 cvReleaseMat(&A);
00604 cvReleaseMat(&W);
00605 cvReleaseMat(&Ut);
00606 cvReleaseMat(&Vt);
00607
00608 return ok;
00609 }
00610
00615 bool Homography::ComputeHomRobustLS(double H[9], bool normalize, double thrInlier, double thrAngle)
00616 {
00617 if ((normalize && lastPt<2) || lastPt+lastLn < 5)
00618 return false;
00619
00620
00621 bool ok;
00622 unsigned size = 2*(lastPt+lastLn);
00623
00624 double dA[size*9];
00625 double dW[9*9];
00626 double dUt[size*9];
00627 double dVt[9*9];
00628 double T1[9], T2[9];
00629
00630 double thr;
00631
00632 CvMat A, W, Ut, Vt;
00633 cvInitMatHeader(&A, 10, 9, CV_64F, &dA);
00634 cvInitMatHeader(&W, 9, 9, CV_64F, &dW);
00635 cvInitMatHeader(&Ut, 10, 9, CV_64F, &dUt);
00636 cvInitMatHeader(&Vt, 9, 9, CV_64F, &dVt);
00637
00638 if (normalize)
00639 {
00640 NormalizePts(pts1, lastPt, pts1, T1);
00641 NormalizePts(pts2, lastPt, pts2, T2);
00642 NormalizeLns(T1, lns1, lastLn, lns1);
00643 NormalizeLns(T2, lns2, lastLn, lns2);
00644 thr = T2[0];
00645 }
00646 else
00647 {
00648 thr = thrInlier;
00649 }
00650
00651
00652 int numLines, k=0, num = lastPt+lastLn;
00653 double eps = 4./(double)num;
00654 int inl, inls = 0;
00655 Array<unsigned> idx;
00656 double Ht[9];
00657 srand(time(NULL));
00658
00659 while (pow(1. - pow(eps,4),k) >= HOM_RANSAC_ETA0 && k<HOM_MAX_RANSAC_TRIALS)
00660 {
00661 do{
00662 GetRandIdx(num, 5, idx);
00663
00664 numLines=0;
00665 for (unsigned i=0; i<5; i++)
00666 if (idx[i]<lastPt)
00667 numLines++;
00668
00669 }while(numLines < 2);
00670
00671 for (unsigned i=0; i<5; i++)
00672 {
00673 if (idx[i]<lastPt)
00674 InsertPointCoeff(pts1[idx[i]], pts2[idx[i]], &dA[i*18]);
00675 else
00676 InsertLineCoeff(lns1[idx[i]-lastPt], lns2[idx[i]-lastPt], &dA[i*18]);
00677 }
00678
00679 if (SolveHomography(&A, &W, &Ut, &Vt, Ht))
00680 {
00681 inl=0;
00682 CountInlierPts(Ht, thr, inl);
00683 CountInlierLns(Ht, thr,thrAngle, inl);
00684
00685 if (inl > inls)
00686 {
00687 inls = inl;
00688 eps = (double)inls / (double)num;
00689 for (unsigned i=0; i<9; i++)
00690 H[i] = Ht[i];
00691 }
00692 }
00693
00694 k++;
00695 }
00696 #ifdef DEBUG
00697 cout<<"ComputeHomRobustLS: Number of RANSAC trials: "<<k
00698 <<", Number of inlier: "<<inls<<"("<<lastLn+lastPt<<")"<<endl;
00699 #endif
00700
00701
00702 int numInl;
00703 SetDataMatrix(dA, H, thr,thrAngle, numInl);
00704
00705 if (numInl<5)
00706 return false;
00707
00708 cvInitMatHeader(&A, numInl*2, 9, CV_64F, &dA);
00709 cvInitMatHeader(&Ut, numInl*2, 9, CV_64F, &dUt);
00710
00711 ok = SolveHomography(&A, &W, &Ut, &Vt, H);
00712
00713 if (ok && normalize)
00714 {
00715 DenormalizeH(H, T1, T2, H);
00716 }
00717
00718 if (!ok || pow(1. - pow(eps,4),k) >= HOM_RANSAC_ETA0)
00719 return false;
00720
00721 return true;
00722 }
00723
00724
00725
00726
00727
00728 }
00729