epnp求解
1、理论部分
2、代码部分(作者牛pi)
PnPsolver::PnPsolver(const Frame &F, const vector<MapPoint*> &vpMapPointMatches):
pws(0), us(0), alphas(0), pcs(0), maximum_number_of_correspondences(0), number_of_correspondences(0), mnInliersi(0),
mnIterations(0), mnBestInliers(0), N(0)
{
mvpMapPointMatches = vpMapPointMatches;
mvP2D.reserve(F.mvpMapPoints.size());
mvSigma2.reserve(F.mvpMapPoints.size());
mvP3Dw.reserve(F.mvpMapPoints.size());
mvKeyPointIndices.reserve(F.mvpMapPoints.size());
mvAllIndices.reserve(F.mvpMapPoints.size());
int idx=0;
for(size_t i=0, iend=vpMapPointMatches.size(); i<iend; i++)
{
MapPoint* pMP = vpMapPointMatches[i];
if(pMP)
{
if(!pMP->isBad())
{
const cv::KeyPoint &kp = F.mvKeysUn[i];
mvP2D.push_back(kp.pt);
mvSigma2.push_back(F.mvLevelSigma2[kp.octave]);
cv::Mat Pos = pMP->GetWorldPos();
mvP3Dw.push_back(cv::Point3f(Pos.at<float>(0),Pos.at<float>(1), Pos.at<float>(2)));
mvKeyPointIndices.push_back(i);
mvAllIndices.push_back(idx);
idx++;
}
}
}
fu = F.fx;
fv = F.fy;
uc = F.cx;
vc = F.cy;
SetRansacParameters();
}
PnPsolver::~PnPsolver()
{
delete [] pws;
delete [] us;
delete [] alphas;
delete [] pcs;
}
void PnPsolver::SetRansacParameters(double probability, int minInliers, int maxIterations, int minSet, float epsilon, float th2)
{
mRansacProb = probability;
mRansacMinInliers = minInliers;
mRansacMaxIts = maxIterations;
mRansacEpsilon = epsilon;
mRansacMinSet = minSet;
N = mvP2D.size();
mvbInliersi.resize(N);
int nMinInliers = N*mRansacEpsilon;
if(nMinInliers<mRansacMinInliers)
nMinInliers=mRansacMinInliers;
if(nMinInliers<minSet)
nMinInliers=minSet;
mRansacMinInliers = nMinInliers;
if(mRansacEpsilon<(float)mRansacMinInliers/N)
mRansacEpsilon=(float)mRansacMinInliers/N;
int nIterations;
if(mRansacMinInliers==N)
nIterations=1;
else
nIterations = ceil(log(1-mRansacProb)/log(1-pow(mRansacEpsilon,3)));
mRansacMaxIts = max(1,min(nIterations,mRansacMaxIts));
mvMaxError.resize(mvSigma2.size());
for(size_t i=0; i<mvSigma2.size(); i++)
mvMaxError[i] = mvSigma2[i]*th2;
}
cv::Mat PnPsolver::find(vector<bool> &vbInliers, int &nInliers)
{
bool bFlag;
return iterate(mRansacMaxIts,bFlag,vbInliers,nInliers);
}
cv::Mat PnPsolver::iterate(int nIterations, bool &bNoMore, vector<bool> &vbInliers, int &nInliers)
{
bNoMore = false;
vbInliers.clear();
nInliers=0;
set_maximum_number_of_correspondences(mRansacMinSet);
if(N<mRansacMinInliers)
{
bNoMore = true;
return cv::Mat();
}
vector<size_t> vAvailableIndices;
int nCurrentIterations = 0;
while(mnIterations<mRansacMaxIts || nCurrentIterations<nIterations)
{
nCurrentIterations++;
mnIterations++;
reset_correspondences();
vAvailableIndices = mvAllIndices;
for(short i = 0; i < mRansacMinSet; ++i)
{
int randi = DUtils::Random::RandomInt(0, vAvailableIndices.size()-1);
int idx = vAvailableIndices[randi];
add_correspondence(mvP3Dw[idx].x,mvP3Dw[idx].y,mvP3Dw[idx].z,mvP2D[idx].x,mvP2D[idx].y);
vAvailableIndices[randi] = vAvailableIndices.back();
vAvailableIndices.pop_back();
}
compute_pose(mRi, mti);
CheckInliers();
if(mnInliersi>=mRansacMinInliers)
{
if(mnInliersi>mnBestInliers)
{
mvbBestInliers = mvbInliersi;
mnBestInliers = mnInliersi;
cv::Mat Rcw(3,3,CV_64F,mRi);
cv::Mat tcw(3,1,CV_64F,mti);
Rcw.convertTo(Rcw,CV_32F);
tcw.convertTo(tcw,CV_32F);
mBestTcw = cv::Mat::eye(4,4,CV_32F);
Rcw.copyTo(mBestTcw.rowRange(0,3).colRange(0,3));
tcw.copyTo(mBestTcw.rowRange(0,3).col(3));
}
if(Refine())
{
nInliers = mnRefinedInliers;
vbInliers = vector<bool>(mvpMapPointMatches.size(),false);
for(int i=0; i<N; i++)
{
if(mvbRefinedInliers[i])
vbInliers[mvKeyPointIndices[i]] = true;
}
return mRefinedTcw.clone();
}
}
}
if(mnIterations>=mRansacMaxIts)
{
bNoMore=true;
if(mnBestInliers>=mRansacMinInliers)
{
nInliers=mnBestInliers;
vbInliers = vector<bool>(mvpMapPointMatches.size(),false);
for(int i=0; i<N; i++)
{
if(mvbBestInliers[i])
vbInliers[mvKeyPointIndices[i]] = true;
}
return mBestTcw.clone();
}
}
return cv::Mat();
}
bool PnPsolver::Refine()
{
vector<int> vIndices;
vIndices.reserve(mvbBestInliers.size());
for(size_t i=0; i<mvbBestInliers.size(); i++)
{
if(mvbBestInliers[i])
{
vIndices.push_back(i);
}
}
set_maximum_number_of_correspondences(vIndices.size());
reset_correspondences();
for(size_t i=0; i<vIndices.size(); i++)
{
int idx = vIndices[i];
add_correspondence(mvP3Dw[idx].x,mvP3Dw[idx].y,mvP3Dw[idx].z,mvP2D[idx].x,mvP2D[idx].y);
}
compute_pose(mRi, mti);
CheckInliers();
mnRefinedInliers =mnInliersi;
mvbRefinedInliers = mvbInliersi;
if(mnInliersi>mRansacMinInliers)
{
cv::Mat Rcw(3,3,CV_64F,mRi);
cv::Mat tcw(3,1,CV_64F,mti);
Rcw.convertTo(Rcw,CV_32F);
tcw.convertTo(tcw,CV_32F);
mRefinedTcw = cv::Mat::eye(4,4,CV_32F);
Rcw.copyTo(mRefinedTcw.rowRange(0,3).colRange(0,3));
tcw.copyTo(mRefinedTcw.rowRange(0,3).col(3));
return true;
}
return false;
}
void PnPsolver::CheckInliers()
{
mnInliersi=0;
for(int i=0; i<N; i++)
{
cv::Point3f P3Dw = mvP3Dw[i];
cv::Point2f P2D = mvP2D[i];
float Xc = mRi[0][0]*P3Dw.x+mRi[0][1]*P3Dw.y+mRi[0][2]*P3Dw.z+mti[0];
float Yc = mRi[1][0]*P3Dw.x+mRi[1][1]*P3Dw.y+mRi[1][2]*P3Dw.z+mti[1];
float invZc = 1/(mRi[2][0]*P3Dw.x+mRi[2][1]*P3Dw.y+mRi[2][2]*P3Dw.z+mti[2]);
double ue = uc + fu * Xc * invZc;
double ve = vc + fv * Yc * invZc;
float distX = P2D.x-ue;
float distY = P2D.y-ve;
float error2 = distX*distX+distY*distY;
if(error2<mvMaxError[i])
{
mvbInliersi[i]=true;
mnInliersi++;
}
else
{
mvbInliersi[i]=false;
}
}
}
void PnPsolver::set_maximum_number_of_correspondences(int n)
{
if (maximum_number_of_correspondences < n) {
if (pws != 0) delete [] pws;
if (us != 0) delete [] us;
if (alphas != 0) delete [] alphas;
if (pcs != 0) delete [] pcs;
maximum_number_of_correspondences = n;
pws = new double[3 * maximum_number_of_correspondences];
us = new double[2 * maximum_number_of_correspondences];
alphas = new double[4 * maximum_number_of_correspondences];
pcs = new double[3 * maximum_number_of_correspondences];
}
}
void PnPsolver::reset_correspondences(void)
{
number_of_correspondences = 0;
}
void PnPsolver::add_correspondence(double X, double Y, double Z, double u, double v)
{
pws[3 * number_of_correspondences ] = X;
pws[3 * number_of_correspondences + 1] = Y;
pws[3 * number_of_correspondences + 2] = Z;
us[2 * number_of_correspondences ] = u;
us[2 * number_of_correspondences + 1] = v;
number_of_correspondences++;
}
void PnPsolver::choose_control_points(void)
{
cws[0][0] = cws[0][1] = cws[0][2] = 0;
for(int i = 0; i < number_of_correspondences; i++)
for(int j = 0; j < 3; j++)
cws[0][j] += pws[3 * i + j];
for(int j = 0; j < 3; j++)
cws[0][j] /= number_of_correspondences;
CvMat * PW0 = cvCreateMat(number_of_correspondences, 3, CV_64F);
double pw0tpw0[3 * 3], dc[3], uct[3 * 3];
CvMat PW0tPW0 = cvMat(3, 3, CV_64F, pw0tpw0);
CvMat DC = cvMat(3, 1, CV_64F, dc);
CvMat UCt = cvMat(3, 3, CV_64F, uct);
for(int i = 0; i < number_of_correspondences; i++)
for(int j = 0; j < 3; j++)
PW0->data.db[3 * i + j] = pws[3 * i + j] - cws[0][j];
cvMulTransposed(PW0, &PW0tPW0, 1);
cvSVD(&PW0tPW0, &DC, &UCt, 0, CV_SVD_MODIFY_A | CV_SVD_U_T);
cvReleaseMat(&PW0);
for(int i = 1; i < 4; i++) {
double k = sqrt(dc[i - 1] / number_of_correspondences);
for(int j = 0; j < 3; j++)
cws[i][j] = cws[0][j] + k * uct[3 * (i - 1) + j];
}
}
void PnPsolver::compute_barycentric_coordinates(void)
{
double cc[3 * 3], cc_inv[3 * 3];
CvMat CC = cvMat(3, 3, CV_64F, cc);
CvMat CC_inv = cvMat(3, 3, CV_64F, cc_inv);
for(int i = 0; i < 3; i++)
for(int j = 1; j < 4; j++)
cc[3 * i + j - 1] = cws[j][i] - cws[0][i];
cvInvert(&CC, &CC_inv, CV_SVD);
double * ci = cc_inv;
for(int i = 0; i < number_of_correspondences; i++) {
double * pi = pws + 3 * i;
double * a = alphas + 4 * i;
for(int j = 0; j < 3; j++)
a[1 + j] =
ci[3 * j ] * (pi[0] - cws[0][0]) +
ci[3 * j + 1] * (pi[1] - cws[0][1]) +
ci[3 * j + 2] * (pi[2] - cws[0][2]);
a[0] = 1.0f - a[1] - a[2] - a[3];
}
}