$search
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 //#define DEBUG 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 /************************************* PRIVATE ***************************************/ 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.); //for lines: inl = alpha [°] 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 //set inlier points 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 //set inlier lines 00159 double HT[9]; 00160 Transpose33(H, HT); 00161 00162 double thrAng = cos(thrAngle * M_PI/180.); //for lines: inl = alpha [°] 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 // determine A's rank 00218 unsigned z; 00219 for(z=0; z<9; z++) 00220 if(IsZero(cvmGet(W,z,z))) break; // remaining singular values are smaller than this 00221 00222 if(z<8) 00223 return false; //A should have rank n-1 00224 00225 // last is smallest singular value 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; //x 00347 t2 = lns1[i].y; //y 00348 t3 = lns2[i].x; //u 00349 t4 = lns2[i].y; //v 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); // tmp = T2 * H 00382 Mul33(tmp, T1_1, nH); // nH = T2 * H * T1^-1 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); // tmp = T2^-1 * nH 00395 Mul33(tmp, T1, H); // H = T2^-1 * nH * T1 00396 } 00397 00398 00399 00400 00401 00402 00403 00404 00405 00406 /************************************* PUBLIC ****************************************/ 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 //double T1[9], invT[9]; 00475 00476 if (T1==0) T1 = new double[9]; 00477 if (invT==0) invT = new double[9]; 00478 00479 // compute mapping of four (a) points to a unit square 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 // compute mapping of a unit square to four points 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 // compute mapping four points (a) to four points (b) 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 //calculation of the affine parameter 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 //init 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 //ransac 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 //solve least squares 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