ippe.cpp
Go to the documentation of this file.
1 #include "ippe.h"
2 #include <opencv2/imgproc/imgproc.hpp>
3 #include <opencv2/calib3d/calib3d.hpp>
4 using namespace cv;
5 using namespace std;
6 
7 /******
8  *
9  */
10 
11 cv::Mat getRTMatrix(const cv::Mat &R_, const cv::Mat &T_, int forceType) {
12  cv::Mat M;
13  cv::Mat R, T;
14  R_.copyTo(R);
15  T_.copyTo(T);
16  if (R.type() == CV_64F) {
17  assert(T.type() == CV_64F);
18  cv::Mat Matrix = cv::Mat::eye(4, 4, CV_64FC1);
19 
20  cv::Mat R33 = cv::Mat(Matrix, cv::Rect(0, 0, 3, 3));
21  if (R.total() == 3) {
22  cv::Rodrigues(R, R33);
23  } else if (R.total() == 9) {
24  cv::Mat R64;
25  R.convertTo(R64, CV_64F);
26  R.copyTo(R33);
27  }
28  for (int i = 0; i < 3; i++)
29  Matrix.at< double >(i, 3) = T.ptr< double >(0)[i];
30  M = Matrix;
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));
34  if (R.total() == 3) {
35  cv::Rodrigues(R, R33);
36  } else if (R.total() == 9) {
37  cv::Mat R32;
38  R.convertTo(R32, CV_32F);
39  R.copyTo(R33);
40  }
41 
42  for (int i = 0; i < 3; i++)
43  Matrix.at< float >(i, 3) = T.ptr< float >(0)[i];
44  M = Matrix;
45  }
46 
47  if (forceType == -1)
48  return M;
49  else {
50  cv::Mat MTyped;
51  M.convertTo(MTyped, forceType);
52  return MTyped;
53  }
54 }
55 vector<cv::Mat> IPPE::solvePnP(const vector<cv::Point3f> &objPoints,const std::vector<cv::Point2f>&imgPoints, cv::InputArray cameraMatrix, cv::InputArray distCoeffs)
56 {
57 
58  cv::Mat Rvec, Tvec;
59  float markerLength = cv::norm(objPoints[1]-objPoints[0]);
60  float reprojErr1, reprojErr2;
61  cv::Mat Rvec2,Tvec2;
62 
63  IPPE::solvePoseOfCentredSquare(markerLength, imgPoints, cameraMatrix, distCoeffs, Rvec, Tvec,reprojErr1,Rvec2,Tvec2,reprojErr2);
64  return {getRTMatrix(Rvec,Tvec,CV_32F),getRTMatrix(Rvec2,Tvec2,CV_32F) } ;
65 }
66 
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){
68  cv::Mat Rvec, Tvec;
69  float markerLength = cv::norm(objPoints[1]-objPoints[0]);
70  float reprojErr1, reprojErr2;
71  cv::Mat Rvec2,Tvec2;
72 
73  IPPE::solvePoseOfCentredSquare(markerLength, imgPoints, cameraMatrix, distCoeffs, Rvec, Tvec,reprojErr1,Rvec2,Tvec2,reprojErr2);
74  return {make_pair(getRTMatrix(Rvec,Tvec,CV_32F),reprojErr1), make_pair(getRTMatrix(Rvec2,Tvec2,CV_32F),reprojErr2) } ;
75 
76 }
77 
78 void IPPE::solvePoseOfCentredSquare(float squareLength, InputArray imagePoints, InputArray cameraMatrix, InputArray distCoeffs,
79  OutputArray _rvec1, OutputArray _tvec1, float & reprojErr1, OutputArray _rvec2, OutputArray _tvec2, float & reprojErr2)
80 {
81 
82  cv::Mat undistortedPoints; //undistored version of imagePoints
83  cv::Mat modelPoints(4, 1, CV_32FC3);
84  // set coordinate system in the middle of the marker, with Z pointing out
85  modelPoints.ptr< Vec3f >(0)[0] = Vec3f(-squareLength / 2.0f, squareLength / 2.0f, 0);
86  modelPoints.ptr< Vec3f >(0)[1] = Vec3f(squareLength / 2.0f, squareLength / 2.0f, 0);
87  modelPoints.ptr< Vec3f >(0)[2] = Vec3f(squareLength / 2.0f, -squareLength / 2.0f, 0);
88  modelPoints.ptr< Vec3f >(0)[3] = Vec3f(-squareLength / 2.0f, -squareLength / 2.0f, 0);
89 
90  //(Ra,ta), (Rb,tb) are the two pose solutions from IPPE.
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);
95 
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();
101 
102 
103  //undistort the image points (i.e. put them in normalized pixel coordinates).
104  undistortPoints(imagePoints,undistortedPoints,cameraMatrix,distCoeffs);
105 
106  //compute the homography mapping the model's four corners to undistortedPoints
107  homographyFromSquarePoints(undistortedPoints,squareLength/2.0f,H);
108 
109  //Compute the Jacobian J of the homography at (0,0):
110  double j00, j01, j10,j11, v0,v1;
111 
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);
116 
117  //Compute the transformation of (0,0) into the image:
118  v0 = H.at<double>(0,2);
119  v1 = H.at<double>(1,2);
120 
121  //compute the two rotation solutions:
122  IPPComputeRotations(j00, j01, j10,j11,v0,v1,Ra,Rb);
123 
124  //for each rotation solution, compute the corresponding translation solution:
125  IPPComputeTranslation(modelPoints,undistortedPoints,Ra,ta);
126  IPPComputeTranslation(modelPoints,undistortedPoints,Rb,tb);
127 
128  float reprojErra = IPPEvalReprojectionError(Ra,ta,modelPoints,undistortedPoints);
129  float reprojErrb = IPPEvalReprojectionError(Rb,tb,modelPoints,undistortedPoints);
130 
131 
132  if (reprojErra < reprojErrb)
133  {
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);
137  IPPERot2vec(Ra,rvec1);
138 
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);
142  IPPERot2vec(Rb,rvec2);
143 
144  reprojErr1 = reprojErra;
145  reprojErr2 = reprojErrb;
146  }
147  else
148  {
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);
152  IPPERot2vec(Rb,rvec1);
153 
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);
157  IPPERot2vec(Ra,rvec2);
158 
159  reprojErr1 = reprojErrb;
160  reprojErr2 = reprojErra;
161  }
162 }
163 
164 
165 
166 
167 int IPPE::IPPEvalBestPose(InputArray _R1, InputArray _R2, InputArray _t1, InputArray _t2, InputArray _objectPoints, InputArray _undistortedPoints)
168 {
169  cv::Mat modelPoints = _objectPoints.getMat();
170  cv::Mat imgPoints = _undistortedPoints.getMat();
171 
172  cv::Mat R1 = _R1.getMat();
173  cv::Mat t1 = _t1.getMat();
174 
175  cv::Mat R2 = _R2.getMat();
176  cv::Mat t2 = _t2.getMat();
177 
178  int numPts = modelPoints.rows;
179 
180  //now loop over each correspondence and compute the reprojection error of both pose solution
181  float px,py,pz;
182  float reprojError1 = 0; //reprojection error of pose 1
183  float reprojError2 = 0; //reprojection error of pose 2
184 
185  float dx,dy; //residual reprojection error with respect to x and y coordinates
186  for (int i=0;i<numPts;i++)
187  {
188 
189  //projection with first pose solution:
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);
193 
194  dx = px/pz - imgPoints.at<Vec2f>(i)(0);
195  dy = py/pz - imgPoints.at<Vec2f>(i)(1);
196 
197  reprojError1 = reprojError1 + sqrt(dx*dx + dy*dy);
198 
199  //projection with second pose solution:
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);
203 
204  dx = px/pz - imgPoints.at<Vec2f>(i)(0);
205  dy = py/pz - imgPoints.at<Vec2f>(i)(1);
206 
207  reprojError2 = reprojError2 + sqrt(dx*dx + dy*dy);
208 
209  }
210  if (reprojError1<reprojError2)
211  {
212  return 1;
213  }
214  else
215  {
216  return 2;
217  }
218 
219 }
220 
221 float IPPE::IPPEvalReprojectionError(InputArray _R, InputArray _t, InputArray _objectPoints, InputArray _undistortedPoints)
222 {
223  cv::Mat modelPoints = _objectPoints.getMat();
224  cv::Mat imgPoints = _undistortedPoints.getMat();
225 
226  cv::Mat R = _R.getMat();
227  cv::Mat t = _t.getMat();
228 
229  int numPts = modelPoints.rows;
230  float px,py,pz;
231  float reprojError = 0;
232  float dx,dy; //residual reprojection error with respect to x and y coordinates
233  //now loop over each correspondence and compute the reprojection error
234  for (int i=0;i<numPts;i++)
235  {
236 
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);
240 
241  dx = px/pz - imgPoints.at<Vec2f>(i)(0);
242  dy = py/pz - imgPoints.at<Vec2f>(i)(1);
243 
244  reprojError = reprojError + sqrt(dx*dx + dy*dy);
245 
246  }
247  return reprojError;
248 
249 }
250 
251 void IPPE::IPPERot2vec(InputArray _R, OutputArray _r)
252 {
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);
257  double c0,c1,c2;
258  double eps = std::numeric_limits<double>::epsilon();
259  double d = 1/(2*sin(w_norm))*w_norm;
260  if (w_norm < eps) //rotation is the identity
261  {
262  rvec.setTo(0);
263  }
264  else
265  {
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;
272  }
273 }
274 
275 void IPPE::IPPComputeTranslation(InputArray _objectPoints, InputArray _imgPoints, InputArray _R, OutputArray _t)
276 {
277  //This is solved by building the linear system At = b, where t corresponds to the (unknown) translation.
278  //This is then inverted with the associated normal equations to give t = inv(transpose(A)*A)*transpose(A)*b
279  //For efficiency we only store the coefficients of (transpose(A)*A) and (transpose(A)*b)
280  cv::Mat modelPoints = _objectPoints.getMat();
281  cv::Mat imgPoints = _imgPoints.getMat();
282  int numPts = modelPoints.rows;
283 
284  _t.create(3,1,CV_64FC1);
285 
286  cv::Mat R = _R.getMat();
287 
288  //coefficients of (transpose(A)*A)
289  double ATA00 = numPts;
290  double ATA02 = 0;
291  double ATA11 = numPts;
292  double ATA12 = 0;
293  double ATA20 = 0;
294  double ATA21 = 0;
295  double ATA22 = 0;
296 
297 
298  //coefficients of (transpose(A)*b)
299  double ATb0 = 0;
300  double ATb1 = 0;
301  double ATb2 = 0;
302 
303 
304  //S gives inv(transpose(A)*A)/det(A)^2
305  double S00, S01, S02;
306  double S10, S11, S12;
307  double S20, S21, S22;
308 
309  double rx, ry,rz;
310  double a2;
311  double b2;
312  double bx,by;
313 
314  //now loop through each point and increment the coefficients:
315  for (int i=0;i<numPts;i++)
316  {
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);
322  ATA02 = ATA02 + a2;
323  ATA12 = ATA12+ b2;
324  ATA20 = ATA20 + a2;
325  ATA21 = ATA21 + b2;
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;
329  ATb0 = ATb0 + bx;
330  ATb1 = ATb1 + by;
331  ATb2 = ATb2 + a2*bx + b2*by;
332  }
333 
334  double detAInv = 1.0/(ATA00*ATA11*ATA22 - ATA00*ATA12*ATA21 - ATA02*ATA11*ATA20);
335 
336  //construct S:
337  S00 = ATA11*ATA22 - ATA12*ATA21;
338  S01 = ATA02*ATA21;
339  S02 = - ATA02*ATA11;
340  S10 = ATA12*ATA20;
341  S11 = ATA00*ATA22 - ATA02*ATA20;
342  S12 = - ATA00*ATA12;
343  S20 = - ATA11*ATA20;
344  S21 = - ATA00*ATA21;
345  S22 = ATA00*ATA11;
346 
347  //solve t:
348  Mat t = _t.getMat();
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);
352 
353 }
354 
355 void IPPE::IPPComputeRotations(double j00, double j01, double j10, double j11, double p, double q, OutputArray _R1, OutputArray _R2)
356 {
357  //Note that it is very hard to understand what is going on here from the code, so if you want to have a clear explanation then please refer to the IPPE paper (Algorithm 1 and its description).
358  _R1.create(3,3,CV_64FC1);
359  _R2.create(3,3,CV_64FC1);
360 
361 
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;
368 
369  s = sqrt(p*p + q*q + 1);
370  t = sqrt(p*p + q*q);
371  costh = 1/s;
372  sinth = sqrt(1-1/(s*s));
373 
374  krs0 = p/t;
375  krs1 = q/t;
376  krs0_2 = krs0*krs0;
377  krs1_2 = krs1*krs1;
378 
379  rv00= (costh - 1)*krs0_2 + 1;
380  rv01 = krs0*krs1*(costh - 1);
381  rv02 = krs0*sinth;
382  rv10 = krs0*krs1*(costh - 1);
383  rv11 = (costh - 1)*krs1_2 + 1;
384  rv12 = krs1*sinth;
385  rv20 = -krs0*sinth;
386  rv21 = -krs1*sinth;
387  rv22 = (costh - 1)*(krs0_2 + krs1_2) + 1;
388 
389  //setup the 2x2 SVD decomposition:
390  b00 = rv00 - p*rv20;
391  b01 = rv01 - p*rv21;
392  b10 = rv10 - q*rv20;
393  b11 = rv11 - q*rv21;
394 
395  dtinv = 1.0/((b00*b11 - b01*b10));
396 
397  binv00 = dtinv*b11;
398  binv01 = -dtinv*b01;
399  binv10 = -dtinv*b10;
400  binv11 = dtinv*b00;
401 
402  a00 = binv00*j00 + binv01*j10;
403  a01 = binv00*j01 + binv01*j11;
404  a10 = binv10*j00 + binv11*j10;
405  a11 = binv10*j01 + binv11*j11;
406 
407  //compute the largest singular value of A:
408  ata00 = a00*a00 + a01*a01;
409  ata01 = a00*a10 + a01*a11;
410  ata11 =a10*a10 + a11*a11;
411 
412  gamma = sqrt(0.5*(ata00 +ata11 + sqrt((ata00-ata11)*(ata00-ata11) + 4.0*ata01*ata01)));
413 
414  //reconstruct the full rotation matrices:
415  rtilde00 = a00/gamma;
416  rtilde01 = a01/gamma;
417  rtilde10 = a10/gamma;
418  rtilde11 = a11/gamma;
419 
420  rtilde00_2 = rtilde00*rtilde00;
421  rtilde01_2 = rtilde01*rtilde01;
422  rtilde10_2 = rtilde10*rtilde10;
423  rtilde11_2 = rtilde11*rtilde11;
424 
425  b0 = sqrt(- rtilde00_2 - rtilde10_2 + 1);
426  b1 = sqrt(- rtilde01_2 - rtilde11_2 + 1);
427  sp = (- rtilde00*rtilde01 - rtilde10*rtilde11);
428 
429  if (sp<0)
430  {
431  b1 = -b1;
432  }
433 
434  //save results:
435  Mat R1 = _R1.getMat();
436  Mat R2 = _R2.getMat();
437 
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;
447 
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;
457 
458 }
459 
460 void IPPE::homographyFromSquarePoints(InputArray _targetPts, double halfLength, OutputArray H_)
461 {
462 
463  cv::Mat pts = _targetPts.getMat();
464  H_.create(3,3,CV_64FC1);
465  Mat H = H_.getMat();
466 
467  double p1x = -pts.at<Vec2f>(0)(0);
468  double p1y = -pts.at<Vec2f>(0)(1);
469 
470  double p2x = -pts.at<Vec2f>(1)(0);
471  double p2y = -pts.at<Vec2f>(1)(1);
472 
473  double p3x = -pts.at<Vec2f>(2)(0);
474  double p3y = -pts.at<Vec2f>(2)(1);
475 
476  double p4x = -pts.at<Vec2f>(3)(0);
477  double p4y = -pts.at<Vec2f>(3)(1);
478 
479 
480  //analytic solution:
481  double detsInv = -1/(halfLength*(p1x*p2y - p2x*p1y - p1x*p4y + p2x*p3y - p3x*p2y + p4x*p1y + p3x*p4y - p4x*p3y));
482 
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;
492 
493 }
d
std::vector< cv::Mat > solvePnP(const std::vector< cv::Point3f > &objPoints, const std::vector< cv::Point2f > &imgPoints, cv::InputArray cameraMatrix, cv::InputArray distCoeffs)
Definition: ippe.cpp:55
void IPPERot2vec(cv::InputArray _R, cv::OutputArray _r)
Fast conversion from a rotation matrix to a rotation vector using Rodrigues&#39; 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...
f
XmlRpcServer s
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)
Definition: ippe.cpp:11
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)
Definition: ippe.cpp:67
const CwiseUnaryOp< internal::scalar_sqrt_op< Scalar >, const Derived > sqrt() const
const CwiseUnaryOp< internal::scalar_acos_op< Scalar >, const Derived > acos() const


tuw_aruco
Author(s): Lukas Pfeifhofer
autogenerated on Mon Jun 10 2019 15:40:51