CV学习日志:CV开发之位姿变换器

1.本文要点说明

         介绍视觉定位导航中位姿变换的基础知识,包括:

                  (1)位姿变换模型

                  (2)左乘右乘法则

                  (3)模型几何解释

                  (4)基本运算公式

                  (5)旋转转换公式

2.实验测试代码

         依赖于OpenCV、Ceres和Spdlog,封装在类ModelRotation:

              (1)RVec2Quat、Quat2RMat、RVec2RMat、Euler2RMat

              (2)Quat2RVec、RMat2Quat、RMat2RVec、RMat2Euler

              (3)SolidPose:setPos、setRot、inv、mul、print

  1 #include <ceres/ceres.h>
  2 #include <ceres/rotation.h>
  3 #include <spdlog/spdlog.h>
  4 #include <opencv2/opencv.hpp>
  5 using namespace std;
  6 using namespace cv;
  7 
  8 class ModelRotation
  9 {
 10 public:
 11     static inline double L1EPS() { return 1E-12; }
 12     static inline double L2EPS() { return 1E-18; }
 13 
 14 public://RVec2Quat
 15     struct RVec2Quat
 16     {
 17         bool useCeres;
 18         RVec2Quat(bool useCeres0) : useCeres(useCeres0) {}
 19         template <typename tp> bool operator()(const tp* const src, tp* dst) const
 20         {
 21             if (useCeres) { ceres::AngleAxisToQuaternion(src, dst); return true; }
 22             tp theta2 = src[0] * src[0] + src[1] * src[1] + src[2] * src[2];
 23             if (theta2 > ModelRotation::L2EPS())
 24             {
 25                 tp theta = sqrt(theta2);
 26                 tp thetaa = theta * 0.5;
 27                 tp coeff = sin(thetaa) / theta;
 28                 dst[0] = cos(thetaa);
 29                 dst[1] = src[0] * coeff;
 30                 dst[2] = src[1] * coeff;
 31                 dst[3] = src[2] * coeff;
 32             }
 33             else //first order taylor
 34             {
 35                 dst[0] = tp(1.);
 36                 dst[1] = src[0] * 0.5;
 37                 dst[2] = src[1] * 0.5;
 38                 dst[3] = src[2] * 0.5;
 39             }
 40             return true;
 41         }
 42         static void TestMe(int argc = 0, char** argv = 0)
 43         {
 44             for (int k = 0; k < 999; ++k)
 45             {
 46                 //0.GenerateData
 47                 Matx31d r = r.randu(-999, 999);
 48 
 49                 //1.CalcByCeres
 50                 Vec4d q1;
 51                 Mat_<double> dqdr1(4, 3);
 52                 ceres::CostFunction* costFun1 = new ceres::AutoDiffCostFunction<RVec2Quat, 4, 3>(new RVec2Quat(true));
 53                 costFun1->Evaluate(vector<double*>{r.val}.data(), q1.val, vector<double*>{dqdr1.ptr<double>()}.data());
 54 
 55                 //2.CalcByManu
 56                 Vec4d q2;
 57                 Mat_<double> dqdr2(4, 3);
 58                 ceres::CostFunction* costFun2 = new ceres::AutoDiffCostFunction<RVec2Quat, 4, 3>(new RVec2Quat(false));
 59                 costFun2->Evaluate(vector<double*>{r.val}.data(), q2.val, vector<double*>{dqdr2.ptr<double>()}.data());
 60 
 61                 //3.AnalyzeError
 62                 double infq1q2 = cv::norm(q1, q2, NORM_INF);
 63                 double infdqdr1dqdr2 = cv::norm(dqdr1, dqdr2, NORM_INF);
 64 
 65                 //4.PrintError
 66                 cout << endl << "LoopCount: " << k << endl;
 67                 if (infq1q2 > 1E-12 || infdqdr1dqdr2 > 1E-12)
 68                 {
 69                     cout << endl << "infq1q2: " << infq1q2 << endl;
 70                     cout << endl << "infdqdr1dqdr2: " << infdqdr1dqdr2 << endl;
 71                     if (0)
 72                     {
 73                         cout << endl << "q1: " << q1 << endl;
 74                         cout << endl << "q2: " << q2 << endl;
 75                         cout << endl << "dqdr1: " << dqdr1 << endl;
 76                         cout << endl << "dqdr2: " << dqdr2 << endl;
 77                     }
 78                     cout << endl << "Press any key to continue" << endl; getchar();
 79                 }
 80             }
 81         }
 82     };
 83     struct Quat2RVec
 84     {
 85         bool useCeres;
 86         Quat2RVec(bool useCeres0) : useCeres(useCeres0) {}
 87         template <typename tp> bool operator()(const tp* const src, tp* dst) const
 88         {
 89             if (useCeres) { ceres::QuaternionToAngleAxis(src, dst); return true; }
 90             tp thetaa2 = src[1] * src[1] + src[2] * src[2] + src[3] * src[3];
 91             if (thetaa2 > ModelRotation::L2EPS())
 92             {
 93                 tp cs = src[0];
 94                 tp sn = sqrt(thetaa2);
 95                 tp theta = 2.0 * (cs < 0.0 ? atan2(-sn, -cs) : atan2(sn, cs));//refer to ceres comments
 96                 tp coeff = theta / sn;
 97                 dst[0] = src[1] * coeff;
 98                 dst[1] = src[2] * coeff;
 99                 dst[2] = src[3] * coeff;
100             }
101             else //first order taylor
102             {
103                 dst[0] = 2.0 * src[1];
104                 dst[1] = 2.0 * src[2];
105                 dst[2] = 2.0 * src[3];
106             }
107             return true;
108         }
109         static void TestMe(int argc = 0, char** argv = 0)
110         {
111             for (int k = 0; k < 999; ++k)
112             {
113                 //0.GenerateData
114                 Matx41d q = q.randu(-999, 999);
115 
116                 //1.CalcByCeres
117                 Matx33d r1;
118                 Mat_<double> drdq1(3, 4);
119                 ceres::CostFunction* costFun1 = new ceres::AutoDiffCostFunction<Quat2RVec, 3, 4>(new Quat2RVec(true));
120                 costFun1->Evaluate(vector<double*>{q.val}.data(), r1.val, vector<double*>{drdq1.ptr<double>()}.data());
121 
122                 //2.CalcByManu
123                 Matx33d r2;
124                 Mat_<double> drdq2(3, 4);
125                 ceres::CostFunction* costFun2 = new ceres::AutoDiffCostFunction<Quat2RVec, 3, 4>(new Quat2RVec(false));
126                 costFun2->Evaluate(vector<double*>{q.val}.data(), r2.val, vector<double*>{drdq2.ptr<double>()}.data());
127 
128                 //3.AnalyzeError
129                 double infr1r2 = cv::norm(r1, r2, NORM_INF);
130                 double infdrdq1drdq2 = cv::norm(drdq1, drdq2, NORM_INF);
131 
132                 //4.PrintError
133                 cout << endl << "LoopCount: " << k << endl;
134                 if (infr1r2 > 1E-12 || infdrdq1drdq2 > 1E-12)
135                 {
136                     cout << endl << "infr1r2: " << infr1r2 << endl;
137                     cout << endl << "infdrdq1drdq2: " << infdrdq1drdq2 << endl;
138                     if (0)
139                     {
140                         cout << endl << "r1: " << r1 << endl;
141                         cout << endl << "r2: " << r2 << endl;
142                         cout << endl << "drdq1: " << drdq1 << endl;
143                         cout << endl << "drdq2: " << drdq2 << endl;
144                     }
145                     cout << endl << "Press any key to continue" << endl; getchar();
146                 }
147             }
148         }
149     };
150 
151 public://Quat2RMat
152     struct Quat2RMat
153     {
154         bool useCeres;
155         Quat2RMat(bool useCeres0) : useCeres(useCeres0) {}
156         template <typename tp> bool operator()(const tp* const src, tp* dst) const
157         {
158             if (useCeres) { ceres::QuaternionToRotation(src, dst); return true; }
159             tp ww = src[0] * src[0];
160             tp wx = src[0] * src[1];
161             tp wy = src[0] * src[2];
162             tp wz = src[0] * src[3];
163 
164             tp xx = src[1] * src[1];
165             tp xy = src[1] * src[2];
166             tp xz = src[1] * src[3];
167 
168             tp yy = src[2] * src[2];
169             tp yz = src[2] * src[3];
170 
171             tp zz = src[3] * src[3];
172             tp L2 = ww + xx + yy + zz;
173             if (L2 < ModelRotation::L2EPS()) { dst[0] = dst[4] = dst[8] = tp(1.); dst[1] = dst[2] = dst[3] = dst[5] = dst[6] = dst[7] = tp(0.); return true; }
174             tp iL2 = 1. / L2;
175 
176             dst[0] = ww + xx - yy - zz; dst[1] = 2.0 * (xy - wz); dst[2] = 2.0 * (wy + xz);
177             dst[3] = 2.0 * (wz + xy); dst[4] = ww - xx + yy - zz; dst[5] = 2.0 * (yz - wx);
178             dst[6] = 2.0 * (xz - wy); dst[7] = 2.0 * (wx + yz); dst[8] = ww - xx - yy + zz;
179             for (int k = 0; k < 9; ++k) dst[k] = dst[k] * iL2;//for not unit quaternion
180 
181             return true;
182         }
183         static void TestMe(int argc = 0, char** argv = 0)
184         {
185             for (int k = 0; k < 999; ++k)
186             {
187                 //0.GenerateData
188                 Matx41d q = q.randu(-999, 999);
189 
190                 //1.CalcByCeres
191                 Matx33d R1;
192                 Mat_<double> dRdq1(9, 4);
193                 ceres::CostFunction* costFun1 = new ceres::AutoDiffCostFunction<Quat2RMat, 9, 4>(new Quat2RMat(true));
194                 costFun1->Evaluate(vector<double*>{q.val}.data(), R1.val, vector<double*>{dRdq1.ptr<double>()}.data());
195 
196                 //2.CalcByManu
197                 Matx33d R2;
198                 Mat_<double> dRdq2(9, 4);
199                 ceres::CostFunction* costFun2 = new ceres::AutoDiffCostFunction<Quat2RMat, 9, 4>(new Quat2RMat(false));
200                 costFun2->Evaluate(vector<double*>{q.val}.data(), R2.val, vector<double*>{dRdq2.ptr<double>()}.data());
201 
202                 //3.AnalyzeError
203                 double infR1R2 = cv::norm(R1, R2, NORM_INF);
204                 double infdRdq1dRdq2 = cv::norm(dRdq1, dRdq2, NORM_INF);
205 
206                 //4.PrintError
207                 cout << endl << "LoopCount: " << k << endl;
208                 if (infR1R2 > 1E-12 || infdRdq1dRdq2 > 1E-12)
209                 {
210                     cout << endl << "infR1R2: " << infR1R2 << endl;
211                     cout << endl << "infdRdq1dRdq2: " << infdRdq1dRdq2 << endl;
212                     if (0)
213                     {
214                         cout << endl << "R1: " << R1 << endl;
215                         cout << endl << "R2: " << R2 << endl;
216                         cout << endl << "dRdq1: " << dRdq1 << endl;
217                         cout << endl << "dRdq2: " << dRdq2 << endl;
218                     }
219                     cout << endl << "Press any key to continue" << endl; getchar();
220                 }
221             }
222         }
223     };
224     struct RMat2Quat
225     {
226         bool useCeres;
227         RMat2Quat(bool useCeres0) : useCeres(useCeres0) {}
228         template <typename tp> bool operator()(const tp* const src, tp* dst) const
229         {
230             if (useCeres) { ceres::RotationMatrixToQuaternion(ceres::RowMajorAdapter3x3(src), dst); return true; }
231             tp trace = src[0] + src[4] + src[8];//Strictly 1+trace>0 for rotation matrix. In ceres, This leads to different jacobians between ceres' rmat2rvec and cv::Rodrigues(rmat, rvec)
232             if (trace >= 0.0)
233             {
234                 tp trace1 = sqrt(1. + trace);
235                 dst[0] = 0.5 * trace1;
236                 tp itrace1 = 0.5 / trace1;
237                 dst[1] = (src[7] - src[5]) * itrace1;
238                 dst[2] = (src[2] - src[6]) * itrace1;
239                 dst[3] = (src[3] - src[1]) * itrace1;
240             }
241             else
242             {
243                 int a = 0;
244                 if (src[4] > src[0]) a = 1;
245                 if (src[8] > src[a * 3 + a]) a = 2;
246                 int b = (a + 1) % 3;
247                 int c = (b + 1) % 3;
248 
249                 tp trace1 = sqrt(1.0 + src[a * 3 + a] - src[b * 3 + b] - src[c * 3 + c]);
250                 dst[a + 1] = 0.5 * trace1;
251                 tp itrace1 = 0.5 / trace1;
252                 dst[0] = (src[c * 3 + b] - src[b * 3 + c]) * itrace1;
253                 dst[b + 1] = (src[b * 3 + a] + src[a * 3 + b]) * itrace1;
254                 dst[c + 1] = (src[c * 3 + a] + src[a * 3 + c]) * itrace1;
255             }
256             return true;
257         }
258         static void TestMe(int argc, char** argv)
259         {
260             for (int k = 0; k < 999; ++k)
261             {
262                 //0.GenerateData
263                 Matx33d R; ceres::EulerAnglesToRotationMatrix(Matx31d::randu(-180, 180).val, 0, R.val);
264 
265                 //1.CalcByCeres
266                 Vec4d q1;
267                 Mat_<double> dqdR1(4, 9);
268                 ceres::CostFunction* costFun1 = new ceres::AutoDiffCostFunction<RMat2Quat, 4, 9>(new RMat2Quat(true));
269                 costFun1->Evaluate(vector<double*>{R.val}.data(), q1.val, vector<double*>{dqdR1.ptr<double>()}.data());
270 
271                 //2.CalcByManu
272                 Vec4d q2;
273                 Mat_<double> dqdR2(4, 9);
274                 ceres::CostFunction* costFun2 = new ceres::AutoDiffCostFunction<RMat2Quat, 4, 9>(new RMat2Quat(false));
275                 costFun2->Evaluate(vector<double*>{R.val}.data(), q2.val, vector<double*>{dqdR2.ptr<double>()}.data());
276 
277                 //4.AnalyzeError
278                 double infq1q2 = cv::norm(q1, q2, NORM_INF);
279                 double infdqdR1dqdR2 = cv::norm(dqdR1, dqdR2, NORM_INF);
280 
281                 //5.PrintError
282                 cout << endl << "LoopCount: " << k << endl;
283                 if (infq1q2 > 1E-9 || infdqdR1dqdR2 > 1E-9)
284                 {
285                     cout << endl << "infq1q2: " << infq1q2 << endl;
286                     cout << endl << "infdqdR1dqdR2: " << infq1q2 << endl;
287                     if (0)
288                     {
289                         cout << endl << "q1:" << q1 << endl;
290                         cout << endl << "q2:" << q2 << endl;
291                         cout << endl << "dqdR1:" << dqdR1 << endl;
292                         cout << endl << "dqdR2:" << dqdR2 << endl;
293                     }
294                     cout << endl << "Press any key to continue" << endl; getchar();
295                 }
296             }
297         }
298     };
299 
300 public://RVec2RMat
301     struct RVec2RMat
302     {
303         bool useCeres;
304         RVec2RMat(bool useCeres0) : useCeres(useCeres0) {}
305         template <typename tp> bool operator()(const tp* const src, tp* dst) const
306         {
307             if (useCeres) { ceres::AngleAxisToRotationMatrix(src, ceres::RowMajorAdapter3x3(dst)); return true; }
308             tp theta2 = src[0] * src[0] + src[1] * src[1] + src[2] * src[2];
309             if (theta2 > ModelRotation::L2EPS())
310             {
311                 tp theta = sqrt(theta2);
312                 tp itheta = 1. / theta;
313                 tp cs = cos(theta);
314                 tp sn = sin(theta);
315                 tp nx = src[0] * itheta;
316                 tp ny = src[1] * itheta;
317                 tp nz = src[2] * itheta;
318 
319                 dst[0] = nx * nx * (1. - cs) + cs;
320                 dst[3] = nx * ny * (1. - cs) + nz * sn;
321                 dst[6] = nx * nz * (1. - cs) - ny * sn;
322 
323                 dst[1] = nx * ny * (1. - cs) - nz * sn;
324                 dst[4] = ny * ny * (1. - cs) + cs;
325                 dst[7] = ny * nz * (1. - cs) + nx * sn;
326 
327                 dst[2] = nx * nz * (1. - cs) + ny * sn;
328                 dst[5] = ny * nz * (1. - cs) - nx * sn;
329                 dst[8] = nz * nz * (1. - cs) + cs;
330             }
331             else //first order taylor
332             {
333                 dst[0] = tp(1.);
334                 dst[3] = src[2];
335                 dst[6] = -src[1];
336 
337                 dst[1] = -src[2];
338                 dst[4] = tp(1.);
339                 dst[7] = src[0];
340 
341                 dst[2] = src[1];
342                 dst[5] = -src[0];
343                 dst[8] = tp(1.);
344             }
345             return true;
346         }
347         static void TestMe(int argc = 0, char** argv = 0)
348         {
349             for (int k = 0; k < 999; ++k)
350             {
351                 //0.GenerateData
352                 Matx31d r = r.randu(-999, 999);
353 
354                 //1.CalcByCeres
355                 Matx33d R1;
356                 Mat_<double> dRdr1(9, 3);
357                 ceres::CostFunction* costFun1 = new ceres::AutoDiffCostFunction<RVec2RMat, 9, 3>(new RVec2RMat(true));
358                 costFun1->Evaluate(vector<double*>{r.val}.data(), R1.val, vector<double*>{dRdr1.ptr<double>()}.data());
359 
360                 //2.CalcByManu
361                 Matx33d R2;
362                 Mat_<double> dRdr2(9, 3);
363                 ceres::CostFunction* costFun2 = new ceres::AutoDiffCostFunction<RVec2RMat, 9, 3>(new RVec2RMat(false));
364                 costFun2->Evaluate(vector<double*>{r.val}.data(), R2.val, vector<double*>{dRdr2.ptr<double>()}.data());
365 
366                 //3.CalcByOpenCV
367                 Matx33d R3;
368                 Mat_<double> dRdr3;
369                 cv::Rodrigues(r, R3, dRdr3); dRdr3 = dRdr3.t();
370 
371                 //4.AnalyzeError
372                 double infR1R2 = cv::norm(R1, R2, NORM_INF);
373                 double infR1R3 = cv::norm(R1, R3, NORM_INF);
374                 double infdRdr1dRdr2 = cv::norm(dRdr1, dRdr2, NORM_INF);
375                 double infdRdr1dRdr3 = cv::norm(dRdr1, dRdr3, NORM_INF);
376 
377                 //5.PrintError
378                 cout << endl << "LoopCount: " << k << endl;
379                 if (infR1R2 > 1E-12 || infR1R3 > 1E-12 || infdRdr1dRdr2 > 1E-12 || infdRdr1dRdr3 > 1E-12)
380                 {
381                     cout << endl << "infR1R2: " << infR1R2 << endl;
382                     cout << endl << "infR1R3: " << infR1R3 << endl;
383                     cout << endl << "infdRdr3dRdr1: " << infdRdr1dRdr2 << endl;
384                     cout << endl << "infdRdr3dRdr2: " << infdRdr1dRdr3 << endl;
385                     if (0)
386                     {
387                         cout << endl << "R1: " << R1 << endl;
388                         cout << endl << "R2: " << R2 << endl;
389                         cout << endl << "R3: " << R3 << endl;
390                         cout << endl << "dRdr1: " << dRdr1 << endl;
391                         cout << endl << "dRdr2: " << dRdr2 << endl;
392                         cout << endl << "dRdr3: " << dRdr3 << endl;
393                     }
394                     cout << endl << "Press any key to continue" << endl; getchar();
395                 }
396             }
397         }
398     };
399     struct RMat2RVec
400     {
401         bool useCeres;
402         RMat2RVec(bool useCeres0) : useCeres(useCeres0) {}
403         template <typename tp> bool operator()(const tp* const src, tp* dst) const
404         {
405             if (useCeres) { ceres::RotationMatrixToAngleAxis(ceres::RowMajorAdapter3x3(src), dst); return true; }
406             tp quat[4];
407             RMat2Quat(false)(src, quat);
408             Quat2RVec(false)(quat, dst);
409             return true;
410         }
411         static void TestMe(int argc, char** argv)
412         {
413             for (int k = 0; k < 999; ++k)
414             {
415                 //0.GenerateData
416                 Matx33d R; ceres::EulerAnglesToRotationMatrix(Matx31d::randu(-180, 180).val, 0, R.val);
417 
418                 //1.CalcByCeres
419                 Vec3d r1;
420                 Mat_<double> drdR1(3, 9);
421                 ceres::CostFunction* costFun1 = new ceres::AutoDiffCostFunction<RMat2RVec, 3, 9>(new RMat2RVec(true));
422                 costFun1->Evaluate(vector<double*>{R.val}.data(), r1.val, vector<double*>{drdR1.ptr<double>()}.data());
423 
424                 //2.CalcByManu
425                 Vec3d r2;
426                 Mat_<double> drdR2(3, 9);
427                 ceres::CostFunction* costFun2 = new ceres::AutoDiffCostFunction<RMat2RVec, 3, 9>(new RMat2RVec(false));
428                 costFun2->Evaluate(vector<double*>{R.val}.data(), r2.val, vector<double*>{drdR2.ptr<double>()}.data());
429 
430                 //3.AnalyzeError
431                 double infr1r2 = cv::norm(r1, r2, NORM_INF);
432                 double infdrdR1drdR2 = cv::norm(drdR1, drdR2, NORM_INF);
433 
434                 //5.PrintError
435                 cout << endl << "LoopCount: " << k << endl;
436                 if (infr1r2 > 1E-9 || infdrdR1drdR2 > 1E-9)
437                 {
438                     cout << endl << "infr1r2: " << infr1r2 << endl;
439                     cout << endl << "infdrdR1drdR2: " << infdrdR1drdR2 << endl;
440                     if (0)
441                     {
442                         cout << endl << "r1:" << r1 << endl;
443                         cout << endl << "r2:" << r2 << endl;
444                         cout << endl << "drdR1:" << drdR1 << endl;
445                         cout << endl << "drdR2:" << drdR2 << endl;
446                     }
447                     cout << endl << "Press any key to continue" << endl; getchar();
448                 }
449             }
450         }
451     };
452 
453 public://Euler2RMat
454     struct Euler2RMat
455     {
456         bool useCeres;
457         Euler2RMat(bool useCeres0) : useCeres(useCeres0) {}
458         template <typename tp> bool operator()(const tp* const src, tp* dst) const
459         {
460             //RPY indicates: first Yaw aroundZ, second Pitch aroundY, third Roll aroundX
461             if (useCeres) { ceres::EulerAnglesToRotationMatrix(src, 0, dst); return true; }
462             const double deg2rad = 3.14159265358979323846 * 0.0055555555555555556;
463             tp sinR = sin(src[0] * deg2rad);
464             tp sinP = sin(src[1] * deg2rad);
465             tp sinY = sin(src[2] * deg2rad);
466             tp cosR = cos(src[0] * deg2rad);
467             tp cosP = cos(src[1] * deg2rad);
468             tp cosY = cos(src[2] * deg2rad);
469 
470             dst[0] = cosY * cosP; dst[1] = cosY * sinP * sinR - sinY * cosR; dst[2] = cosY * sinP * cosR + sinY * sinR;
471             dst[3] = sinY * cosP; dst[4] = sinY * sinP * sinR + cosY * cosR; dst[5] = sinY * sinP * cosR - cosY * sinR;
472             dst[6] = -sinP;       dst[7] = cosP * sinR;                      dst[8] = cosP * cosR;
473             return true;
474         }
475         static void TestMe(int argc = 0, char** argv = 0)
476         {
477             for (int k = 0; k < 999; ++k)
478             {
479                 //0.GenerateData
480                 Matx31d e = e.randu(-999, 999);
481 
482                 //1.CalcByCeres
483                 Matx33d R1;
484                 Mat_<double> dRde1(9, 3);
485                 ceres::CostFunction* costFun1 = new ceres::AutoDiffCostFunction<Euler2RMat, 9, 3>(new Euler2RMat(true));
486                 costFun1->Evaluate(vector<double*>{e.val}.data(), R1.val, vector<double*>{dRde1.ptr<double>()}.data());
487 
488                 //2.CalcByManu
489                 Matx33d R2;
490                 Mat_<double> dRde2(9, 3);
491                 ceres::CostFunction* costFun2 = new ceres::AutoDiffCostFunction<Euler2RMat, 9, 3>(new Euler2RMat(false));
492                 costFun2->Evaluate(vector<double*>{e.val}.data(), R2.val, vector<double*>{dRde2.ptr<double>()}.data());
493 
494                 //3.AnalyzeError
495                 double infR1R2 = cv::norm(R1, R2, NORM_INF);
496                 double infdRde1dRde2 = cv::norm(dRde1, dRde2, NORM_INF);
497 
498                 //4.PrintError
499                 cout << endl << "LoopCount: " << k << endl;
500                 if (infR1R2 > 1E-12 || infdRde1dRde2 > 1E-12)
501                 {
502                     cout << endl << "infR1R2: " << infR1R2 << endl;
503                     cout << endl << "infdRde2dRde1: " << infdRde1dRde2 << endl;
504                     if (0)
505                     {
506                         cout << endl << "R1: " << R1 << endl;
507                         cout << endl << "R2: " << R2 << endl;
508                         cout << endl << "dRde1: " << dRde1 << endl;
509                         cout << endl << "dRde2: " << dRde2 << endl;
510                     }
511                     cout << endl << "Press any key to continue" << endl; getchar();
512                 }
513             }
514         }
515     };
516     struct RMat2Euler
517     {
518         bool useCeres;
519         RMat2Euler(bool useCeres0) : useCeres(useCeres0) {}
520         template <typename tp> bool operator()(const tp* const src, tp* dst) const
521         {
522             //RPY indicates: first Yaw aroundZ, second Pitch aroundY, third Roll aroundX
523             if (useCeres) { ceres::RotationMatrixToEulerAngles(src, dst); return true; }
524             const double rad2deg = 180 * 0.3183098861837906715;
525             tp bound1 = abs(src[6] - 1.);
526             tp bound2 = abs(src[6] + 1.);
527             if (bound1 > ModelRotation::L1EPS() && bound2 > ModelRotation::L1EPS())
528             {
529                 dst[2] = atan2(src[3], src[0]); //Yaw aroundZ
530                 dst[1] = asin(-src[6]);//Pitch aroundY
531                 dst[0] = atan2(src[7], src[8]); //Roll aroundX
532             }
533             else if (bound2 <= ModelRotation::L1EPS())
534             {
535                 dst[2] = tp(0.); //Yaw aroundZ
536                 dst[1] = tp(3.14159265358979323846 * 0.5);//Pitch aroundY
537                 dst[0] = dst[2] + atan2(src[1], src[2]); //Roll aroundX
538             }
539             else
540             {
541                 dst[2] = tp(0.); //Yaw aroundZ
542                 dst[1] = tp(-3.14159265358979323846 * 0.5);//Pitch aroundY
543                 dst[0] = -dst[2] + atan2(-src[1], -src[2]); //Roll aroundX
544             }
545             dst[0] *= rad2deg; dst[1] *= rad2deg; dst[2] *= rad2deg;
546             return true;
547         }
548         static void TestMe(int argc, char** argv)
549         {
550             for (int k = 0; k < 999; ++k)
551             {
552                 //0.GenerateData
553                 Vec3d e0(Matx31d::randu(-180, 180).val);
554                 Matx33d R; ceres::EulerAnglesToRotationMatrix(e0.val, 0, R.val);
555 
556                 //1.CalcByCeres
557                 Vec3d e1;
558                 Mat_<double> dedR1(3, 9);
559                 ceres::CostFunction* costFun1 = new ceres::AutoDiffCostFunction<RMat2Euler, 3, 9>(new RMat2Euler(true));
560                 costFun1->Evaluate(vector<double*>{R.val}.data(), e1.val, vector<double*>{dedR1.ptr<double>()}.data());
561 
562                 //2.CalcByManu
563                 Vec3d e2;
564                 Mat_<double> dedR2(3, 9);
565                 ceres::CostFunction* costFun2 = new ceres::AutoDiffCostFunction<RMat2Euler, 3, 9>(new RMat2Euler(false));
566                 costFun2->Evaluate(vector<double*>{R.val}.data(), e2.val, vector<double*>{dedR2.ptr<double>()}.data());
567 
568                 //3.CalcByOpenCV
569                 Vec3d e3;
570                 Mat_<double> dedR3(3, 9);
571                 e3 = cv::RQDecomp3x3(R, Matx33d(), Matx33d());
572 
573                 //4.AnalyzeError
574                 double infe0e1 = min(cv::norm(e0, e1, NORM_INF), cv::norm(cv::abs(Mat_<double>(3, 1, e0.val)) + cv::abs(Mat_<double>(3, 1, e1.val)), Vec3d(180, 180, 180), NORM_INF));
575                 double infe0e2 = min(cv::norm(e0, e2, NORM_INF), cv::norm(cv::abs(Mat_<double>(3, 1, e0.val)) + cv::abs(Mat_<double>(3, 1, e2.val)), Vec3d(180, 180, 180), NORM_INF));
576                 double infe0e3 = min(cv::norm(e0, e3, NORM_INF), cv::norm(cv::abs(Mat_<double>(3, 1, e0.val)) + cv::abs(Mat_<double>(3, 1, e3.val)), Vec3d(180, 180, 180), NORM_INF));
577 
578                 //5.PrintError
579                 cout << endl << "LoopCount: " << k << endl;
580                 if (infe0e1 > 1E-9 || infe0e2 > 1E-9 || infe0e3 > 1E-9)
581                 {
582                     cout << endl << "infe0e1: " << infe0e1 << endl;
583                     cout << endl << "infe0e2: " << infe0e2 << endl;
584                     cout << endl << "infe0e3: " << infe0e3 << endl;
585                     if (0)
586                     {
587                         cout << endl << "e0: " << e0 << endl;
588                         cout << endl << "e1: " << e1 << endl;
589                         cout << endl << "e2: " << e2 << endl;
590                         cout << endl << "e3: " << e3 << endl;
591                     }
592                     cout << endl << "Press any key to continue" << endl; getchar();
593                 }
594             }
595         }
596     };
597 
598 public:
599     struct SolidPose
600     {
601         double data[22] = { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 };
602         double* vdata = data; //Mat_<double> rvec = Mat_<double>(3, 1, vdata);
603         double* tdata = vdata + 3; //Mat_<double> tvec = Mat_<double>(3, 1, tdata);
604         double* qdata = tdata + 3; //Mat_<double> quat = Mat_<double>(4, 1, qdata);
605         double* mdata = qdata + 4; //Mat_<double> rmat = Mat_<double>(3, 3, mdata);
606         double* edata = mdata + 9; //Mat_<double> euler = Mat_<double>(3, 1, edata);
607         SolidPose() {}
608         SolidPose(const SolidPose& other) { memcpy(data, other.data, sizeof(data)); }
609         void setPos(double* xyz) { memcpy(tdata, xyz, 3 * sizeof(double)); }
610         void setRot(double* rot, int n = 0/*0 3 4 9 for euler rvec quat rmat*/)
611         {
612             if (n == 0)
613             {
614                 memcpy(edata, rot, 3 * sizeof(double));
615                 ceres::EulerAnglesToRotationMatrix(rot, 0, mdata);
616                 ceres::RotationMatrixToQuaternion(ceres::RowMajorAdapter3x3((const double*)(mdata)), qdata);
617                 ceres::QuaternionToAngleAxis(qdata, vdata);//rmat->quat->rvec in ceres
618             }
619             else if (n == 3)
620             {
621                 memcpy(vdata, rot, 3 * sizeof(double));
622                 ceres::AngleAxisToQuaternion(vdata, qdata);
623                 ceres::AngleAxisToRotationMatrix(vdata, ceres::RowMajorAdapter3x3(mdata));
624                 ceres::RotationMatrixToEulerAngles(mdata, edata);
625             }
626             else if (n == 4)
627             {
628                 memcpy(qdata, rot, 4 * sizeof(double));
629                 ceres::QuaternionToAngleAxis(qdata, vdata);
630                 ceres::QuaternionToRotation(qdata, mdata);
631                 ceres::RotationMatrixToEulerAngles(mdata, edata);
632             }
633             else if (n == 9)
634             {
635                 memcpy(mdata, rot, 9 * sizeof(double));
636                 ceres::RotationMatrixToQuaternion(ceres::RowMajorAdapter3x3((const double*)(mdata)), qdata);
637                 ceres::QuaternionToAngleAxis(qdata, vdata);//rmat->quat->rvec in ceres
638                 ceres::RotationMatrixToEulerAngles(mdata, edata);
639             }
640         }
641         SolidPose inv()
642         {
643             SolidPose dst;
644             dst.vdata[0] = -vdata[0]; dst.vdata[1] = -vdata[1]; dst.vdata[2] = -vdata[2];
645             dst.qdata[0] = qdata[0]; dst.qdata[1] = -qdata[1]; dst.qdata[2] = -qdata[2]; dst.qdata[3] = -qdata[3];
646             dst.mdata[0] = mdata[0]; dst.mdata[1] = mdata[3]; dst.mdata[2] = mdata[6];
647             dst.mdata[3] = mdata[1]; dst.mdata[4] = mdata[4]; dst.mdata[5] = mdata[7];
648             dst.mdata[6] = mdata[2]; dst.mdata[7] = mdata[5]; dst.mdata[8] = mdata[8];
649             ceres::RotationMatrixToEulerAngles(dst.mdata, dst.edata);//no euler inversion operation
650             dst.tdata[0] = -(dst.mdata[0] * tdata[0] + dst.mdata[1] * tdata[1] + dst.mdata[2] * tdata[2]);
651             dst.tdata[1] = -(dst.mdata[3] * tdata[0] + dst.mdata[4] * tdata[1] + dst.mdata[5] * tdata[2]);
652             dst.tdata[2] = -(dst.mdata[6] * tdata[0] + dst.mdata[7] * tdata[1] + dst.mdata[8] * tdata[2]);
653             return dst;
654         }
655         SolidPose mul(SolidPose& other)
656         {
657             SolidPose dst;
658             ceres::QuaternionProduct(qdata, other.qdata, dst.qdata);
659             memcpy(dst.mdata, (Matx33d(mdata) * Matx33d(other.mdata)).val, 9 * sizeof(double));
660             ceres::QuaternionToAngleAxis(dst.qdata, dst.vdata);//no rvec multiplication operation
661             ceres::RotationMatrixToEulerAngles(dst.mdata, dst.edata);//no euler multiplication operation
662             memcpy(dst.tdata, (Matx33d(mdata) * Matx31d(other.tdata) + Matx31d(tdata)).val, 3 * sizeof(double));
663             return dst;
664         }
665         string print()
666         {
667             string str;
668             str += fmt::format("rvec: [ {}, {}, {} ]
", vdata[0], vdata[1], vdata[2]);
669             str += fmt::format("tvec: [ {}, {}, {} ]
", tdata[0], tdata[1], tdata[2]);
670             str += fmt::format("quat: [ {}, {}, {}, {} ]
", qdata[0], qdata[1], qdata[2], qdata[3]);
671             str += fmt::format("rmat: [ {}, {}, {}, {}, {}, {}, {}, {}, {} ]
", mdata[0], mdata[1], mdata[2], mdata[3], mdata[4], mdata[5], mdata[6], mdata[7], mdata[8]);
672             str += fmt::format("euler: [ {}, {}, {} ]
", edata[0], edata[1], edata[2]);
673             return str;
674         }
675     };
676 };
677 
678 #if 0
679 int main(int argc, char** argv)
680 {
681     ModelRotation::RVec2Quat::TestMe(argc, argv);
682     ModelRotation::Quat2RVec::TestMe(argc, argv);
683 
684     ModelRotation::Quat2RMat::TestMe(argc, argv);
685     ModelRotation::RMat2Quat::TestMe(argc, argv);
686 
687     ModelRotation::RVec2RMat::TestMe(argc, argv);
688     ModelRotation::RMat2RVec::TestMe(argc, argv);
689 
690     ModelRotation::Euler2RMat::TestMe(argc, argv);
691     ModelRotation::RMat2Euler::TestMe(argc, argv);
692     return 0;
693 }
694 int main1(int argc, char** argv) { ModelRotation::RVec2Quat::TestMe(argc, argv); return 0; }
695 int main2(int argc, char** argv) { ModelRotation::RVec2RMat::TestMe(argc, argv); return 0; }
696 int main3(int argc, char** argv) { ModelRotation::Quat2RMat::TestMe(argc, argv); return 0; }
697 int main7(int argc, char** argv) { ModelRotation::Euler2RMat::TestMe(argc, argv); return 0; }
698 int main8(int argc, char** argv) { ModelRotation::RMat2Euler::TestMe(argc, argv); return 0; }
699 #endif
View Code


 

原文地址:https://www.cnblogs.com/dzyBK/p/14311062.html