2 #include <opencv2/imgproc/imgproc.hpp> 3 #include <opencv2/calib3d/calib3d.hpp> 11 cv::Mat
getRTMatrix(
const cv::Mat &R_,
const cv::Mat &T_,
int forceType) {
16 if (R.type() == CV_64F) {
17 assert(T.type() == CV_64F);
18 cv::Mat Matrix = cv::Mat::eye(4, 4, CV_64FC1);
20 cv::Mat R33 = cv::Mat(Matrix, cv::Rect(0, 0, 3, 3));
22 cv::Rodrigues(R, R33);
23 }
else if (R.total() == 9) {
25 R.convertTo(R64, CV_64F);
28 for (
int i = 0; i < 3; i++)
29 Matrix.at<
double >(i, 3) = T.ptr<
double >(0)[i];
31 }
else if (R.depth() == CV_32F) {
32 cv::Mat Matrix = cv::Mat::eye(4, 4, CV_32FC1);
33 cv::Mat R33 = cv::Mat(Matrix, cv::Rect(0, 0, 3, 3));
35 cv::Rodrigues(R, R33);
36 }
else if (R.total() == 9) {
38 R.convertTo(R32, CV_32F);
42 for (
int i = 0; i < 3; i++)
43 Matrix.at<
float >(i, 3) = T.ptr<
float >(0)[i];
51 M.convertTo(MTyped, forceType);
55 vector<cv::Mat>
IPPE::solvePnP(
const vector<cv::Point3f> &objPoints,
const std::vector<cv::Point2f>&imgPoints, cv::InputArray cameraMatrix, cv::InputArray distCoeffs)
59 float markerLength = cv::norm(objPoints[1]-objPoints[0]);
60 float reprojErr1, reprojErr2;
67 std::vector<std::pair<cv::Mat,double> >
IPPE::solvePnP_(
const std::vector<cv::Point3f> &objPoints,
const std::vector<cv::Point2f> &imgPoints, cv::InputArray cameraMatrix, cv::InputArray distCoeffs){
69 float markerLength = cv::norm(objPoints[1]-objPoints[0]);
70 float reprojErr1, reprojErr2;
74 return {make_pair(
getRTMatrix(Rvec,Tvec,CV_32F),reprojErr1), make_pair(
getRTMatrix(Rvec2,Tvec2,CV_32F),reprojErr2) } ;
79 OutputArray _rvec1, OutputArray _tvec1,
float & reprojErr1, OutputArray _rvec2, OutputArray _tvec2,
float & reprojErr2)
82 cv::Mat undistortedPoints;
83 cv::Mat modelPoints(4, 1, CV_32FC3);
85 modelPoints.ptr< Vec3f >(0)[0] = Vec3f(-squareLength / 2.0
f, squareLength / 2.0
f, 0);
86 modelPoints.ptr< Vec3f >(0)[1] = Vec3f(squareLength / 2.0
f, squareLength / 2.0
f, 0);
87 modelPoints.ptr< Vec3f >(0)[2] = Vec3f(squareLength / 2.0
f, -squareLength / 2.0
f, 0);
88 modelPoints.ptr< Vec3f >(0)[3] = Vec3f(-squareLength / 2.0
f, -squareLength / 2.0
f, 0);
91 _rvec1.create(3,1,CV_64FC1);
92 _tvec1.create(3,1,CV_64FC1);
93 _rvec2.create(3,1,CV_64FC1);
94 _tvec2.create(3,1,CV_64FC1);
96 cv::Mat H,Ra,Rb,ta,tb;
97 cv::Mat tvec1 = _tvec1.getMat();
98 cv::Mat rvec1 = _rvec1.getMat();
99 cv::Mat tvec2 = _tvec2.getMat();
100 cv::Mat rvec2 = _rvec2.getMat();
104 undistortPoints(imagePoints,undistortedPoints,cameraMatrix,distCoeffs);
110 double j00, j01, j10,j11, v0,v1;
112 j00 = H.at<
double>(0,0)-H.at<
double>(2,0)*H.at<
double>(0,2);
113 j01 = H.at<
double>(0,1)-H.at<
double>(2,1)*H.at<
double>(0,2);
114 j10 = H.at<
double>(1,0)-H.at<
double>(2,0)*H.at<
double>(1,2);
115 j11 = H.at<
double>(1,1)-H.at<
double>(2,1)*H.at<
double>(1,2);
118 v0 = H.at<
double>(0,2);
119 v1 = H.at<
double>(1,2);
132 if (reprojErra < reprojErrb)
134 tvec1.at<
double>(0) = ta.at<
double>(0);
135 tvec1.at<
double>(1) = ta.at<
double>(1);
136 tvec1.at<
double>(2) = ta.at<
double>(2);
139 tvec2.at<
double>(0) = tb.at<
double>(0);
140 tvec2.at<
double>(1) = tb.at<
double>(1);
141 tvec2.at<
double>(2) = tb.at<
double>(2);
144 reprojErr1 = reprojErra;
145 reprojErr2 = reprojErrb;
149 tvec1.at<
double>(0) = tb.at<
double>(0);
150 tvec1.at<
double>(1) = tb.at<
double>(1);
151 tvec1.at<
double>(2) = tb.at<
double>(2);
154 tvec2.at<
double>(0) = ta.at<
double>(0);
155 tvec2.at<
double>(1) = ta.at<
double>(1);
156 tvec2.at<
double>(2) = ta.at<
double>(2);
159 reprojErr1 = reprojErrb;
160 reprojErr2 = reprojErra;
167 int IPPE::IPPEvalBestPose(InputArray _R1, InputArray _R2, InputArray _t1, InputArray _t2, InputArray _objectPoints, InputArray _undistortedPoints)
169 cv::Mat modelPoints = _objectPoints.getMat();
170 cv::Mat imgPoints = _undistortedPoints.getMat();
172 cv::Mat R1 = _R1.getMat();
173 cv::Mat t1 = _t1.getMat();
175 cv::Mat R2 = _R2.getMat();
176 cv::Mat t2 = _t2.getMat();
178 int numPts = modelPoints.rows;
182 float reprojError1 = 0;
183 float reprojError2 = 0;
186 for (
int i=0;i<numPts;i++)
190 px = R1.at<
double>(0,0)*modelPoints.at<Vec3f>(i)(0) + R1.at<
double>(0,1)*modelPoints.at<Vec3f>(i)(1) + R1.at<
double>(0,2)*modelPoints.at<Vec3f>(i)(2) + t1.at<
double>(0);
191 py = R1.at<
double>(1,0)*modelPoints.at<Vec3f>(i)(0) + R1.at<
double>(1,1)*modelPoints.at<Vec3f>(i)(1) + R1.at<
double>(1,2)*modelPoints.at<Vec3f>(i)(2) + t1.at<
double>(1);
192 pz = R1.at<
double>(2,0)*modelPoints.at<Vec3f>(i)(0) + R1.at<
double>(2,1)*modelPoints.at<Vec3f>(i)(1) + R1.at<
double>(2,2)*modelPoints.at<Vec3f>(i)(2) + t1.at<
double>(2);
194 dx = px/pz - imgPoints.at<Vec2f>(i)(0);
195 dy = py/pz - imgPoints.at<Vec2f>(i)(1);
197 reprojError1 = reprojError1 +
sqrt(dx*dx + dy*dy);
200 px = R2.at<
double>(0,0)*modelPoints.at<Vec3f>(i)(0) + R2.at<
double>(0,1)*modelPoints.at<Vec3f>(i)(1) + R2.at<
double>(0,2)*modelPoints.at<Vec3f>(i)(2) + t2.at<
double>(0);
201 py = R2.at<
double>(1,0)*modelPoints.at<Vec3f>(i)(0) + R2.at<
double>(1,1)*modelPoints.at<Vec3f>(i)(1) + R2.at<
double>(1,2)*modelPoints.at<Vec3f>(i)(2) + t2.at<
double>(1);
202 pz = R2.at<
double>(2,0)*modelPoints.at<Vec3f>(i)(0) + R2.at<
double>(2,1)*modelPoints.at<Vec3f>(i)(1) + R2.at<
double>(2,2)*modelPoints.at<Vec3f>(i)(2) + t2.at<
double>(2);
204 dx = px/pz - imgPoints.at<Vec2f>(i)(0);
205 dy = py/pz - imgPoints.at<Vec2f>(i)(1);
207 reprojError2 = reprojError2 +
sqrt(dx*dx + dy*dy);
210 if (reprojError1<reprojError2)
223 cv::Mat modelPoints = _objectPoints.getMat();
224 cv::Mat imgPoints = _undistortedPoints.getMat();
226 cv::Mat R = _R.getMat();
227 cv::Mat t = _t.getMat();
229 int numPts = modelPoints.rows;
231 float reprojError = 0;
234 for (
int i=0;i<numPts;i++)
237 px = R.at<
double>(0,0)*modelPoints.at<Vec3f>(i)(0) + R.at<
double>(0,1)*modelPoints.at<Vec3f>(i)(1) + R.at<
double>(0,2)*modelPoints.at<Vec3f>(i)(2) + t.at<
double>(0);
238 py = R.at<
double>(1,0)*modelPoints.at<Vec3f>(i)(0) + R.at<
double>(1,1)*modelPoints.at<Vec3f>(i)(1) + R.at<
double>(1,2)*modelPoints.at<Vec3f>(i)(2) + t.at<
double>(1);
239 pz = R.at<
double>(2,0)*modelPoints.at<Vec3f>(i)(0) + R.at<
double>(2,1)*modelPoints.at<Vec3f>(i)(1) + R.at<
double>(2,2)*modelPoints.at<Vec3f>(i)(2) + t.at<
double>(2);
241 dx = px/pz - imgPoints.at<Vec2f>(i)(0);
242 dy = py/pz - imgPoints.at<Vec2f>(i)(1);
244 reprojError = reprojError +
sqrt(dx*dx + dy*dy);
253 cv::Mat R = _R.getMat();
254 cv::Mat rvec = _r.getMat();
255 double trace = R.at<
double>(0,0) + R.at<
double>(1,1) + R.at<
double>(2,2);
256 double w_norm =
acos((trace-1.0)/2.0);
258 double eps = std::numeric_limits<double>::epsilon();
259 double d = 1/(2*
sin(w_norm))*w_norm;
266 c0 = R.at<
double>(2,1)-R.at<
double>(1,2);
267 c1 = R.at<
double>(0,2)-R.at<
double>(2,0);
268 c2 = R.at<
double>(1,0)-R.at<
double>(0,1);
269 rvec.at<
double>(0) = d*c0;
270 rvec.at<
double>(1) = d*c1;
271 rvec.at<
double>(2) = d*c2;
280 cv::Mat modelPoints = _objectPoints.getMat();
281 cv::Mat imgPoints = _imgPoints.getMat();
282 int numPts = modelPoints.rows;
284 _t.create(3,1,CV_64FC1);
286 cv::Mat R = _R.getMat();
289 double ATA00 = numPts;
291 double ATA11 = numPts;
305 double S00, S01, S02;
306 double S10, S11, S12;
307 double S20, S21, S22;
315 for (
int i=0;i<numPts;i++)
317 rx = R.at<
double>(0,0)*modelPoints.at<Vec3f>(i)(0) + R.at<
double>(0,1)*modelPoints.at<Vec3f>(i)(1) + R.at<
double>(0,2)*modelPoints.at<Vec3f>(i)(2);
318 ry = R.at<
double>(1,0)*modelPoints.at<Vec3f>(i)(0) + R.at<
double>(1,1)*modelPoints.at<Vec3f>(i)(1) + R.at<
double>(1,2)*modelPoints.at<Vec3f>(i)(2);
319 rz = R.at<
double>(2,0)*modelPoints.at<Vec3f>(i)(0) + R.at<
double>(2,1)*modelPoints.at<Vec3f>(i)(1) + R.at<
double>(2,2)*modelPoints.at<Vec3f>(i)(2);
320 a2 = -imgPoints.at<Vec2f>(i)(0);
321 b2 = -imgPoints.at<Vec2f>(i)(1);
326 ATA22 = ATA22 + a2*a2 + b2*b2;
327 bx = (imgPoints.at<Vec2f>(i)(0))*rz - rx;
328 by = (imgPoints.at<Vec2f>(i)(1))*rz - ry;
331 ATb2 = ATb2 + a2*bx + b2*by;
334 double detAInv = 1.0/(ATA00*ATA11*ATA22 - ATA00*ATA12*ATA21 - ATA02*ATA11*ATA20);
337 S00 = ATA11*ATA22 - ATA12*ATA21;
341 S11 = ATA00*ATA22 - ATA02*ATA20;
349 t.at<
double>(0) = detAInv*(S00*ATb0 + S01*ATb1 + S02*ATb2);
350 t.at<
double>(1) = detAInv*(S10*ATb0 + S11*ATb1 + S12*ATb2);
351 t.at<
double>(2) = detAInv*(S20*ATb0 + S21*ATb1 + S22*ATb2);
355 void IPPE::IPPComputeRotations(
double j00,
double j01,
double j10,
double j11,
double p,
double q, OutputArray _R1, OutputArray _R2)
358 _R1.create(3,3,CV_64FC1);
359 _R2.create(3,3,CV_64FC1);
362 double a00, a01, a10,a11, ata00, ata01,ata11,b00, b01, b10,b11,binv00, binv01, binv10,binv11;
363 double rv00, rv01, rv02,rv10, rv11, rv12,rv20, rv21, rv22;
364 double rtilde00, rtilde01, rtilde10, rtilde11;
365 double rtilde00_2, rtilde01_2, rtilde10_2, rtilde11_2;
366 double b0, b1 ,gamma,dtinv;
367 double s,t,sp,krs0,krs1,krs0_2, krs1_2,costh,sinth;
369 s =
sqrt(p*p + q*q + 1);
372 sinth =
sqrt(1-1/(s*s));
379 rv00= (costh - 1)*krs0_2 + 1;
380 rv01 = krs0*krs1*(costh - 1);
382 rv10 = krs0*krs1*(costh - 1);
383 rv11 = (costh - 1)*krs1_2 + 1;
387 rv22 = (costh - 1)*(krs0_2 + krs1_2) + 1;
395 dtinv = 1.0/((b00*b11 - b01*b10));
402 a00 = binv00*j00 + binv01*j10;
403 a01 = binv00*j01 + binv01*j11;
404 a10 = binv10*j00 + binv11*j10;
405 a11 = binv10*j01 + binv11*j11;
408 ata00 = a00*a00 + a01*a01;
409 ata01 = a00*a10 + a01*a11;
410 ata11 =a10*a10 + a11*a11;
412 gamma =
sqrt(0.5*(ata00 +ata11 +
sqrt((ata00-ata11)*(ata00-ata11) + 4.0*ata01*ata01)));
415 rtilde00 = a00/gamma;
416 rtilde01 = a01/gamma;
417 rtilde10 = a10/gamma;
418 rtilde11 = a11/gamma;
420 rtilde00_2 = rtilde00*rtilde00;
421 rtilde01_2 = rtilde01*rtilde01;
422 rtilde10_2 = rtilde10*rtilde10;
423 rtilde11_2 = rtilde11*rtilde11;
425 b0 =
sqrt(- rtilde00_2 - rtilde10_2 + 1);
426 b1 =
sqrt(- rtilde01_2 - rtilde11_2 + 1);
427 sp = (- rtilde00*rtilde01 - rtilde10*rtilde11);
435 Mat R1 = _R1.getMat();
436 Mat R2 = _R2.getMat();
438 R1.at<
double>(0,0) = (rtilde00)*rv00 + (rtilde10)*rv01 + (b0)*rv02;
439 R1.at<
double>(0,1) = (rtilde01)*rv00 + (rtilde11)*rv01 + (b1)*rv02;
440 R1.at<
double>(0,2) = (b1*rtilde10 - b0*rtilde11)*rv00 + (b0*rtilde01 - b1*rtilde00)*rv01 + (rtilde00*rtilde11 - rtilde01*rtilde10)*rv02;
441 R1.at<
double>(1,0) = (rtilde00)*rv10 + (rtilde10)*rv11 + (b0)*rv12;
442 R1.at<
double>(1,1) = (rtilde01)*rv10 + (rtilde11)*rv11 + (b1)*rv12;
443 R1.at<
double>(1,2) = (b1*rtilde10 - b0*rtilde11)*rv10 + (b0*rtilde01 - b1*rtilde00)*rv11 + (rtilde00*rtilde11 - rtilde01*rtilde10)*rv12;
444 R1.at<
double>(2,0) = (rtilde00)*rv20 + (rtilde10)*rv21 + (b0)*rv22;
445 R1.at<
double>(2,1) = (rtilde01)*rv20 + (rtilde11)*rv21 + (b1)*rv22;
446 R1.at<
double>(2,2) = (b1*rtilde10 - b0*rtilde11)*rv20 + (b0*rtilde01 - b1*rtilde00)*rv21 + (rtilde00*rtilde11 - rtilde01*rtilde10)*rv22;
448 R2.at<
double>(0,0) = (rtilde00)*rv00 + (rtilde10)*rv01 + (-b0)*rv02;
449 R2.at<
double>(0,1) = (rtilde01)*rv00 + (rtilde11)*rv01 + (-b1)*rv02;
450 R2.at<
double>(0,2) = (b0*rtilde11 - b1*rtilde10)*rv00 + (b1*rtilde00 - b0*rtilde01)*rv01 + (rtilde00*rtilde11 - rtilde01*rtilde10)*rv02;
451 R2.at<
double>(1,0) = (rtilde00)*rv10 + (rtilde10)*rv11 + (-b0)*rv12;
452 R2.at<
double>(1,1) = (rtilde01)*rv10 + (rtilde11)*rv11 + (-b1)*rv12;
453 R2.at<
double>(1,2) = (b0*rtilde11 - b1*rtilde10)*rv10 + (b1*rtilde00 - b0*rtilde01)*rv11 + (rtilde00*rtilde11 - rtilde01*rtilde10)*rv12;
454 R2.at<
double>(2,0) = (rtilde00)*rv20 + (rtilde10)*rv21 + (-b0)*rv22;
455 R2.at<
double>(2,1) = (rtilde01)*rv20 + (rtilde11)*rv21 + (-b1)*rv22;
456 R2.at<
double>(2,2) = (b0*rtilde11 - b1*rtilde10)*rv20 + (b1*rtilde00 - b0*rtilde01)*rv21 + (rtilde00*rtilde11 - rtilde01*rtilde10)*rv22;
463 cv::Mat pts = _targetPts.getMat();
464 H_.create(3,3,CV_64FC1);
467 double p1x = -pts.at<Vec2f>(0)(0);
468 double p1y = -pts.at<Vec2f>(0)(1);
470 double p2x = -pts.at<Vec2f>(1)(0);
471 double p2y = -pts.at<Vec2f>(1)(1);
473 double p3x = -pts.at<Vec2f>(2)(0);
474 double p3y = -pts.at<Vec2f>(2)(1);
476 double p4x = -pts.at<Vec2f>(3)(0);
477 double p4y = -pts.at<Vec2f>(3)(1);
481 double detsInv = -1/(halfLength*(p1x*p2y - p2x*p1y - p1x*p4y + p2x*p3y - p3x*p2y + p4x*p1y + p3x*p4y - p4x*p3y));
483 H.at<
double>(0,0) = detsInv*(p1x*p3x*p2y - p2x*p3x*p1y - p1x*p4x*p2y + p2x*p4x*p1y - p1x*p3x*p4y + p1x*p4x*p3y + p2x*p3x*p4y - p2x*p4x*p3y);
484 H.at<
double>(0,1) = detsInv*(p1x*p2x*p3y - p1x*p3x*p2y - p1x*p2x*p4y + p2x*p4x*p1y + p1x*p3x*p4y - p3x*p4x*p1y - p2x*p4x*p3y + p3x*p4x*p2y);
485 H.at<
double>(0,2) = detsInv*halfLength*(p1x*p2x*p3y - p2x*p3x*p1y - p1x*p2x*p4y + p1x*p4x*p2y - p1x*p4x*p3y + p3x*p4x*p1y + p2x*p3x*p4y - p3x*p4x*p2y);
486 H.at<
double>(1,0) = detsInv*(p1x*p2y*p3y - p2x*p1y*p3y - p1x*p2y*p4y + p2x*p1y*p4y - p3x*p1y*p4y + p4x*p1y*p3y + p3x*p2y*p4y - p4x*p2y*p3y);
487 H.at<
double>(1,1) = detsInv*(p2x*p1y*p3y - p3x*p1y*p2y - p1x*p2y*p4y + p4x*p1y*p2y + p1x*p3y*p4y - p4x*p1y*p3y - p2x*p3y*p4y + p3x*p2y*p4y);
488 H.at<
double>(1,2) = detsInv*halfLength*(p1x*p2y*p3y - p3x*p1y*p2y - p2x*p1y*p4y + p4x*p1y*p2y - p1x*p3y*p4y + p3x*p1y*p4y + p2x*p3y*p4y - p4x*p2y*p3y);
489 H.at<
double>(2,0) = -detsInv*(p1x*p3y - p3x*p1y - p1x*p4y - p2x*p3y + p3x*p2y + p4x*p1y + p2x*p4y - p4x*p2y);
490 H.at<
double>(2,1) = detsInv*(p1x*p2y - p2x*p1y - p1x*p3y + p3x*p1y + p2x*p4y - p4x*p2y - p3x*p4y + p4x*p3y);
491 H.at<
double>(2,2) = 1.0;
std::vector< cv::Mat > solvePnP(const std::vector< cv::Point3f > &objPoints, const std::vector< cv::Point2f > &imgPoints, cv::InputArray cameraMatrix, cv::InputArray distCoeffs)
void IPPERot2vec(cv::InputArray _R, cv::OutputArray _r)
Fast conversion from a rotation matrix to a rotation vector using Rodrigues' formula.
void homographyFromSquarePoints(cv::InputArray _targetPts, double halfLength, cv::OutputArray _H)
Closed-form solution for the homography mapping with four corner correspondences of a square (it maps...
void solvePoseOfCentredSquare(float squareLength, cv::InputArray imagePoints, cv::InputArray cameraMatrix, cv::InputArray distCoeffs, cv::OutputArray _rvec1, cv::OutputArray _tvec1, float &reprojErr1, cv::OutputArray _rvec2, cv::OutputArray _tvec2, float &reprojErr2)
Finds the two possible poses of a square planar object given its four corner correspondences in an im...
int IPPEvalBestPose(cv::InputArray _R1, cv::InputArray _R2, cv::InputArray _t1, cv::InputArray _t2, cv::InputArray _objectPoints, cv::InputArray _undistortedPoints)
Determines which of the two pose solutions from IPPE has the lowest reprojection error.
cv::Mat getRTMatrix(const cv::Mat &R_, const cv::Mat &T_, int forceType)
const CwiseUnaryOp< internal::scalar_sin_op< Scalar >, const Derived > sin() const
float IPPEvalReprojectionError(cv::InputArray _R, cv::InputArray _t, cv::InputArray _objectPoints, cv::InputArray _undistortedPoints)
Determines the reprojection error of a pose solution.
void IPPComputeTranslation(cv::InputArray _objectPoints, cv::InputArray _imgPoints, cv::InputArray _R, cv::OutputArray _t)
Computes the translation solution for a given rotation solution.
void IPPComputeRotations(double j00, double j01, double j10, double j11, double p, double q, cv::OutputArray _R1, cv::OutputArray _R2)
Computes the two rotation solutions from the Jacobian of a homography matrix H. For highest accuracy ...
std::vector< std::pair< cv::Mat, double > > solvePnP_(const std::vector< cv::Point3f > &objPoints, const std::vector< cv::Point2f > &imgPoints, cv::InputArray cameraMatrix, cv::InputArray distCoeffs)
const CwiseUnaryOp< internal::scalar_sqrt_op< Scalar >, const Derived > sqrt() const
const CwiseUnaryOp< internal::scalar_acos_op< Scalar >, const Derived > acos() const