Skip to content

Add solvePnPRefineLM and solvePnPRefineVVS #14431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 2, 2019

Conversation

catree
Copy link
Contributor

@catree catree commented Apr 26, 2019

related #14181

This is a draft to see how adding a separate function to refine a pose after solvePnP would look:

  • solvePnPRefineLM the classical Levenberg-Marquardt iterative minimization process
  • solvePnPRefineVVS minimize the projection error using a virtual visual servoing scheme

LMSolver should be compared to the C implementation code for the Levenberg-Marquardt:

// refine extrinsic parameters using iterative algorithm
CvLevMarq solver( 6, count*2, cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,max_iter,FLT_EPSILON), true);
cvCopy( &_param, solver.param );
for(;;)
{
CvMat *matJ = 0, *_err = 0;
const CvMat *__param = 0;
bool proceed = solver.update( __param, matJ, _err );
cvCopy( __param, &_param );
if( !proceed || !_err )
break;
cvReshape( _err, _err, 2, 1 );
if( matJ )
{
cvGetCols( matJ, &_dpdr, 0, 3 );
cvGetCols( matJ, &_dpdt, 3, 6 );
cvProjectPoints2( matM, &_r, &_t, &matA, distCoeffs,
_err, &_dpdr, &_dpdt, 0, 0, 0 );
}
else
{
cvProjectPoints2( matM, &_r, &_t, &matA, distCoeffs,
_err, 0, 0, 0, 0, 0 );
}
cvSub(_err, _m, _err);
cvReshape( _err, _err, 1, 2*count );
}

Also, I have added the possibility to set the epsilon in the LM implementation.

Copy link
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution!

SolvePnP() with SOLVEPNP_ITERATIVE should use Levenberg-Marquardt too.

Mat opoints, ipoints;
opoints_.convertTo(opoints, CV_64F);
ipoints_.convertTo(ipoints, CV_64F);
int npoints = std::max(opoints.checkVector(3, CV_32F), opoints.checkVector(3, CV_64F));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After opoints_.convertTo(opoints, CV_64F); this check should always fail: opoints.checkVector(3, CV_32F)

double theta = sqrt(wx*wx + wy*wy + wz*wz);
double sinc = abs(theta) < 1e-8 ? 1 : sin(theta) / theta;
double mcosc = (abs(theta) < 1e-8) ? 0.5 : (1-cos(theta)) / (theta*theta);
double msinc = (abs(theta) < 1e-8) ? (1/6.0) : (1-sinc) / (theta*theta);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using of std::fabs() instead of abs()

double wy = twist.at<double>(4,0);
double wz = twist.at<double>(5,0);

Mat rvec = (Mat_<double>(3,1) << wx, wy, wz);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Matx31d rvec(wx, wy, wz);

@catree catree force-pushed the feat_solvePnPRefine branch from e8c2160 to b66aaa3 Compare April 29, 2019 18:10
@catree
Copy link
Contributor Author

catree commented Apr 29, 2019

@alalek
Yes, there are two Levenberg-Marquardt implementations:

In the future, it would be good to drop the C-version and use LMSolver instead if:

  • they provide the same results
  • it is a one-to-one replacement (same features available) or implement the missing features

Related #5206

…rdt iterative minimization process. Add solvePnPRefineVVS to refine a pose using a virtual visual servoing scheme.
@catree catree force-pushed the feat_solvePnPRefine branch from b66aaa3 to dac31e8 Compare April 30, 2019 12:33
@catree catree marked this pull request as ready for review April 30, 2019 12:34
@catree
Copy link
Contributor Author

catree commented May 2, 2019

For me solvePnPRefineLM and solvePnPRefineVVS are fine but I am wondering if solve prefix could be misleading (these functions need an initial solution and are not a combination of solvePnP followed by a refinement method) for some users?
Otherwise refinePnPLM / refinePnPWithLM and refinePnPVVS / refinePnPWithVVS maybe?
With the class approach counterpart, PnPSolver and PnPRefiner are non-ambiguous and clear for me.

Copy link
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Thank you 👍

@opencv-pushbot opencv-pushbot merged commit dac31e8 into opencv:3.4 May 2, 2019
@tobycollins
Copy link
Contributor

I think the class approach is the good way to go. PnPSolver and PnPRefiner are clear names in my opinion.

@alalek alalek mentioned this pull request May 7, 2019
@tobycollins tobycollins mentioned this pull request Oct 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants