导航

CV学习日志:CV开发之平面仿真器

Posted on 2020-01-31 23:27  dzyBK  阅读(437)  评论(0编辑  收藏  举报

1.本文要点说明

         基于之前介绍的视觉成像器,对平面世界进行成像仿真,对世界系进行位姿变换以用于模型解算。

              (0)关于基准参数(不能重设):物理尺度10cm基准,畸变范围±0.2。

              (1)关于坐标系统(不能重设):相机系采用Z轴向前的右手系,世界系亦同。

              (2)关于世界目标(不能重设):创建m*n=11*10目标,Z坐标=0,Y坐标=10*I(I=0~n),X坐标=10*J(J=0~m),令世界短长边分别为MinLen=min(10*m-10, 10*n-10)和MaxLen=max(10*m-10, 10*n-10)。

              (3)关于世界位姿(不能重设):创建a*b*c=2*5*9位姿,Z坐标=z1和z2,XY坐标=±s1和±s2及0,RPY=除两个零X零Y位姿外分别绕X轴和Y轴旋转旋转±e(e=15,30或10,20)。

                            1)RTCM&&FOV100&&Size1280*800: z1=1.2*MinLen, z2=1.6*MinLen, z1=0.2*MinLen, z2=0.4*MinLen

                            2)KBCM&&FOV160&&Size1200*1200: z1=0.8*MinLen, z2=1.2*MinLen, z1=0.4*MinLen, z2=0.6*MinLen      cv::fisheye::calibrate在世界越往边界平移及畸变越大越容易发生易常???

                            3)MUCM&&FOV240&&Size1600*1600: z1=*MinLen, z2=*MinLen, z1=*MinLen, z2=*MinLen

              (4)关于相机位姿(提供重设):创建d=9个相机,Z坐标=randu(-MinLen, MinLen),Y坐标=randu(-MinLen, MinLen),X坐标=I*MinLen(I=0~9), RPY=randu(-15, 15)。

              (5)关于相机内参(提供重设):基于给定的FOV随机生成,所有相机成像模型一样。

              (6)关于随机化设置:可设置(调用cv::setRNGSeed(clock())实现)是否使用随机种子(默认不使用),若需要每次启动都得到不同的仿真数据,则设置为使用。

              (7)关于可视化操作:启动可视化后,按空格可逐次可视化每次观察,当到达最后一次观察后则返回第一次观察,按所提示的功能键可调整世界位置,用于内参修改时调试世界位置,以获取足够的可用的视图数。

2.实验测试代码

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

              (0)Tool2D:splitStr、globPaths、pathProps、serialPath、renamePath、comparePath、copyPath

              (1)MotionBases:SolidPose、VisionCM、CamSolid、CamObservation

              (2)BoardMotion:initMotion、resetBoardPose、resetCamKDAB、resetCamPose、createRawMotion、refineRawMotion、createDstMotion

              (3)VisMotion:VisRTCM、VisKBCM、VisMUCM

              (4)TestCalib:CalibMono、CalibBino

         关于BoardMotion:

              (1)initMotion:设置成像模型、所有相机内参、所有相机位姿(与世界不同每个相机固定不动)、世界的所有位姿(与相机不同世界仅一个且对每个相机而言该世界都按相同的路径运动)及世界目标。

              (2)resetBoardPose:对每个成像模型而言,世界位姿都是经调试后得到的,本不提供更改世界位姿的接口,但为visMotion能进行调试可行的世界位姿,提供了此接口。

              (3)resetCamKDAB:重设指定相机内参。

              (4)resetCamPose:设置指定相机的位姿。

              (5)createRawMotion:用指定相机观察世界的运动。

              (6)refineRawMotion:决策指定相机中的无效观察。

              (7)createDstMotion:提取指定相机的有效观察。

         仿真来源:RTCM&MUCM来源OpenCV,KBCM&EUCM&DSCM来源basalt。

         测试结果:可视化全正常、OpenCV透视标定通过、OpenCV等距标定不通过、OpenCV全向标定不算通过、CamOdoCal标定全通过。

         遗留问题:全向模型尚未实现基于输入的视场角计算内参、全向模型仅实现第二模型参数为1的情况、双球模型所有功能都尚未实现。

  1 #ifndef __Motion2D_h__
  2 #define __Motion2D_h__
  3 
  4 #include <cscv/ModelCamera.h>
  5 #include <opencv2/core/utils/filesystem.hpp>
  6 #include <opencv2/viz.hpp>
  7 
  8 #ifndef TOOL2D
  9 #define TOOL2D
 10 struct Tool2D
 11 {
 12     static string cvarr2str(InputArray v)
 13     {
 14         Ptr<Formatted> fmtd = cv::format(v, Formatter::FMT_DEFAULT);
 15         string dstm; fmtd->reset();
 16         for (const char* str = fmtd->next(); str; str = fmtd->next()) dstm += string(str);
 17         return dstm;
 18     }
 19     static vector<string> splitStr(string str, char sep)
 20     {
 21         size_t ind0 = -1, ind = 0;
 22         vector<string> rets;
 23         while (1)
 24         {
 25             ++ind0;
 26             ind = str.find_first_of(sep, ind0);
 27             if (ind == string::npos) { if (ind0 != str.size()) rets.push_back(str.substr(ind0, str.size() - ind0)); break; }
 28             else if (ind != ind0) { rets.push_back(str.substr(ind0, ind - ind0)); ind0 = ind; }
 29         }
 30         return rets;
 31     }
 32     static vector<string> globPaths(string dir, string pattern = "*", int type = 0/*0=file 1=dir 2=all*/, bool recursive = false)
 33     {
 34         //0.FormatInput
 35         if (utils::fs::exists(dir) == false) return vector<string>();
 36 
 37         //1.RecurPaths
 38         vector<string> srcPaths;
 39         utils::fs::glob(dir, pattern, srcPaths, recursive, true);
 40         for (size_t k = 0, pos = 0; k < srcPaths.size(); ++k)
 41             for (size_t ind = 0; ; ++ind)
 42             {
 43                 ind = srcPaths[k].find('\\', ind);
 44                 if (ind != string::npos) srcPaths[k].replace(ind, 1, "/");
 45                 else break;
 46             }
 47 
 48         //2.ClassifyPaths
 49         vector<string> dirPaths, filePaths;
 50         for (size_t k = 0; k < srcPaths.size(); ++k) utils::fs::isDirectory(srcPaths[k]) ? dirPaths.push_back(srcPaths[k]) : filePaths.push_back(srcPaths[k]);
 51 
 52         //3.SortPaths
 53         if (dirPaths.size() > 1) stable_sort(dirPaths.begin(), dirPaths.end(), less<string>());
 54         if (dirPaths.size() > 1) stable_sort(dirPaths.begin(), dirPaths.end(), [](string str1, string str2)->bool {return str1.length() < str2.length(); });
 55         if (filePaths.size() > 1) stable_sort(filePaths.begin(), filePaths.end(), less<string>());
 56         if (filePaths.size() > 1) stable_sort(filePaths.begin(), filePaths.end(), [](string str1, string str2)->bool {return str1.length() < str2.length(); });
 57 
 58         //4.CollectPaths
 59         if (type == 0) return filePaths;
 60         if (type == 1) return dirPaths;
 61         if (type == 2) for (size_t k = 0; k < dirPaths.size(); ++k) filePaths.push_back(dirPaths[k]);
 62         return filePaths;
 63     }
 64     static vector<string> pathProps(string path/*0=dir 1=basename 2=extname 3=dir+basename 4=filename*/)
 65     {
 66         vector<string> props(5);
 67         int ind1 = int(path.find_last_of('/'));
 68         int ind2 = int(path.find_last_of('.'));
 69         props[0] = path.substr(0, ind1);
 70         props[1] = path.substr(ind1 + 1, ind2 - ind1 - 1);
 71         props[2] = path.substr(ind2 + 1);
 72         props[3] = path.substr(0, ind2);
 73         props[4] = path.substr(ind1 + 1);
 74         return props;
 75     }
 76     static string serialPath(string dir, string basename, string extname = ""/*empty for directory*/, int64 firstId = -1/*negtive for maximum*/)
 77     {
 78         if (firstId >= 0)
 79         {
 80             string fullPath;
 81             do
 82             {
 83                 fullPath = fmt::format("{}/{}{}{}", dir, basename, firstId, (extname.empty() ? extname : "." + extname));
 84                 if (utils::fs::exists(fullPath) == false) break;
 85             } while (++firstId);
 86             return fullPath;
 87         }
 88         else
 89         {
 90             vector<string> paths = globPaths(dir, basename + "*", extname.empty() ? 1 : 0, false);
 91             if (paths.empty()) return fmt::format("{}/{}{}{}", dir, basename, 0, (extname.empty() ? extname : "." + extname));
 92             if (extname.empty())
 93             {
 94                 int64 ind = paths[paths.size() - 1].find(basename) + basename.length();
 95                 int64 id = atoll(paths[paths.size() - 1].substr(ind).c_str()) + 1;
 96                 return fmt::format("{}/{}{}", dir, basename, id);
 97             }
 98             else
 99             {
100                 int64 ind1 = paths[paths.size() - 1].find(basename) + basename.length();
101                 int64 ind2 = paths[paths.size() - 1].find_last_of(".");
102                 int64 id = atoll(paths[paths.size() - 1].substr(ind1, ind2 - ind1).c_str()) + 1;
103                 return fmt::format("{}/{}{}.{}", dir, basename, id, extname);
104             }
105         }
106     }
107     static string renamePath(string path, string value, int mode = 0/*0filename_1extname_2basename_3suffix_4prefix*/, bool doMove = true)
108     {
109         string path1;
110         int ind1 = int(path.find_last_of('/'));
111         int ind2 = int(path.find_last_of('.'));
112         if (mode == 0) path1 = fmt::format("{}/{}", path.substr(0, ind1), value);
113         else if (mode == 1) path1 = fmt::format("{}.{}", path.substr(0, ind2), value);
114         else if (mode == 2) path1 = fmt::format("{}/{}.{}", path.substr(0, ind1), value, path.substr(ind2 + 1));
115         else if (mode == 3) path1 = fmt::format("{}{}.{}", path.substr(0, ind2), value, path.substr(ind2 + 1));
116         else if (mode == 4) path1 = fmt::format("{}/{}{}", path.substr(0, ind1), value, path.substr(ind1 + 1));
117         if (doMove) rename(path.c_str(), path1.c_str());
118     }
119     static bool compareFile(string path1, string path2)
120     {
121         FILE* file1 = fopen(path1.c_str(), "rb"); if (file1 == 0) return false;
122         FILE* file2 = fopen(path2.c_str(), "rb"); if (file2 == 0) { fclose(file1); return false; }
123         if (fseek(file1, 0, SEEK_END) != 0) { fclose(file1); fclose(file2); return false; }
124         if (fseek(file2, 0, SEEK_END) != 0) { fclose(file1); fclose(file2); return false; }
125         long size1 = ftell(file1), size2 = ftell(file2);
126         if (size1 != size2) { fclose(file1); fclose(file2); return false; }
127         vector<char> data1(size1, 1), data2(size2, 2);
128         if (fseek(file1, 0, SEEK_SET) != 0) { fclose(file1); fclose(file2); return false; }
129         if (fseek(file2, 0, SEEK_SET) != 0) { fclose(file1); fclose(file2); return false; }
130         if (fread(data1.data(), 1, size1, file1) != size1) { fclose(file1); fclose(file2); return false; }
131         if (fread(data2.data(), 1, size2, file2) != size2) { fclose(file1); fclose(file2); return false; }
132         fclose(file1); fclose(file2);
133         return (data1 == data2);
134     }
135     static bool copyFile(string srcPath, string dstPath)
136     {
137         FILE* srcFile = fopen(srcPath.c_str(), "rb"); if (srcFile == 0) return false;
138         if (fseek(srcFile, 0, SEEK_END) != 0) { fclose(srcFile); return false; }
139         long size = ftell(srcFile);
140         if (fseek(srcFile, 0, SEEK_SET) != 0) { fclose(srcFile); return false; }
141         void* data = malloc(size);
142         if (fread(data, 1, size, srcFile) != size) { fclose(srcFile); return false; }
143         fclose(srcFile);
144 
145         FILE* dstFile = fopen(dstPath.c_str(), "wb"); if (dstFile == 0) return false;
146         if (fwrite(data, 1, size, dstFile) != size) { fclose(dstFile); return false; }
147         fclose(dstFile);
148         free(data);
149     }
150 };
151 #endif
152 
153 class Motion2D
154 {
155 public://MotionBases
156     using SolidPose = ModelRotation::SolidPose;
157     using VisionCM = ModelCamera::VisionCM;
158     using CamSolid = ModelCamera::CamSolid;
159     using CamObservation = ModelCamera::CamObservation;
160 
161 public://BoardMotion
162     class BoardMotion
163     {
164     public://Cameras
165         static const int ncamera = 9;
166         CamSolid cams[ncamera];//support multiple cameras
167         SolidPose camPoses[ncamera]; //all poses for each camera
168         CamObservation rawObs[ncamera];//all views for each camera
169         CamObservation dstObs[ncamera];//workable views for each camera
170         int imaRows;
171         int imaCols;
172         const float maxDist = 0.2f;
173 
174     public://BoardProps
175         vector<Point3f> corner3D;
176         const int nVerCorner = 10;
177         const int nHorCorner = 11;
178         const float cmSquareSide = 10;
179         const float cmBoardWidth = (nHorCorner - 1) * cmSquareSide;
180         const float cmBoardHeight = (nVerCorner - 1) * cmSquareSide;
181         const float cmBoardMinSide = min(cmBoardWidth, cmBoardHeight);
182         const float cmBoardMaxSide = max(cmBoardWidth, cmBoardHeight);
183 
184     public://BoardPoses
185         static const int nmodel = 5;
186         static const int ntrans = 10;
187         static const int nrotat = 9;
188         static const int nboard = ntrans * nrotat;
189         SolidPose boardPoses[nmodel][nboard];
190         Vec<double, nmodel> vecZ1 = Vec<double, nmodel>(cmBoardMinSide * 1.2, cmBoardMinSide * 0.8, cmBoardMinSide * 0.4, 0, 0);
191         Vec<double, nmodel> vecZ2 = Vec<double, nmodel>(cmBoardMinSide * 1.6, cmBoardMinSide * 1.2, cmBoardMinSide * 0.8, 0, 0);
192         Vec<double, nmodel> vecS1 = Vec<double, nmodel>(cmBoardMinSide * 0.2, cmBoardMinSide * 0.4, cmBoardMinSide * 0.6, 0, 0);
193         Vec<double, nmodel> vecS2 = Vec<double, nmodel>(cmBoardMinSide * 0.4, cmBoardMinSide * 0.6, cmBoardMinSide * 1.0, 0, 0);
194         const Vec<int, nmodel> vecRows = Vec<int, nmodel>(800, 1200, 1600, 0, 0);
195         const Vec<int, nmodel> vecCols = Vec<int, nmodel>(1280, 1200, 1600, 0, 0);
196         const Vec<int, nmodel> vecFOV = Vec<int, nmodel>(100, 160, 240, 0, 0);
197         const Vec<int, nmodel> euler1 = Vec<int, nmodel>(15, 15, 10, 0, 0);
198         const Vec<int, nmodel> euler2 = Vec<int, nmodel>(30, 30, 20, 0, 0);
199 
200     public://Process
201         void initMotion(short nDist0, short camModel0, short simPin0, bool rndSeed = false)
202         {
203             //1.CamModel
204             for (int k = 0; k < ncamera; ++k)
205             {
206                 cams[k].nDist = nDist0;
207                 cams[k].simPin = simPin0;
208                 cams[k].camModel = camModel0;
209                 if (cams[k].camModel == VisionCM::RTCM) { cams[k].nModel = 0; imaRows = vecRows[0]; imaCols = vecCols[0]; }
210                 if (cams[k].camModel == VisionCM::KBCM) { cams[k].nModel = 0; imaRows = vecRows[1]; imaCols = vecCols[1]; }
211                 if (cams[k].camModel == VisionCM::MUCM) { cams[k].nModel = 1; imaRows = vecRows[2]; imaCols = vecCols[2]; }
212                 if (cams[k].camModel == VisionCM::EUCM) { cams[k].nModel = 2; imaRows = vecRows[2]; imaCols = vecCols[2]; }
213                 if (cams[k].camModel == VisionCM::DSCM) { cams[k].nModel = 2; imaRows = vecRows[3]; imaCols = vecCols[3]; }
214             }
215 
216             //2.CamParams
217             if (rndSeed) cv::setRNGSeed(clock());
218             for (int k = 0; k < ncamera; ++k) resetCamKDAB(k);
219 
220             //3.CameraPoses
221             for (int k = 0; k < ncamera; ++k)
222             {
223                 if (k != 0) camPoses[k].setPos(Matx31d::randu(-cmSquareSide, cmSquareSide).val); camPoses[k].tdata[0] = k * cmSquareSide;
224                 if (k != 0) camPoses[k].setRot(Matx31d::randu(-15 * deg2rad, 15 * deg2rad).val, 3);
225             }
226 
227             //4.BoardData
228             for (int i = 0; i < nVerCorner; ++i)
229                 for (int j = 0; j < nHorCorner; ++j)
230                     corner3D.push_back(Point3f(j * cmSquareSide - cmBoardWidth / 2, i * cmSquareSide - cmBoardHeight / 2, 0));
231 
232             //5.BoardPoses
233             resetBoardPose();
234             //for (int k = 0; k < ncamera; ++k) cout << endl << fmt::format("##########Camera{} information##########\n{}{}", k, cams[k].print(), camPoses[k].print());
235             //for (int i = 0; i < nmodel; ++i) for (int j = 0; j < nboard; ++j) cout << endl << fmt::format("##########CamModel{}-BoardPose{}##########\n{}", j, i, boardPoses[i][j].print());
236         }
237         void resetBoardPose(/*Only for visMotion to test approapriate board poses*/)
238         {
239             for (int whichModel = 0; whichModel < nmodel; ++whichModel)
240             {
241                 double z1 = vecZ1[whichModel], z2 = vecZ2[whichModel];
242                 double s1 = vecS1[whichModel], s2 = vecS2[whichModel];
243                 double e1 = euler1[whichModel], e2 = euler2[whichModel];
244                 Vec3d boardTVec[ntrans] =
245                 {
246                     Vec3d(0, 0, z1), Vec3d(s1, 0, z1), Vec3d(-s1, 0, z1), Vec3d(0, s1, z1), Vec3d(0, -s1, z1),
247                     Vec3d(0, 0, z2), Vec3d(s2, 0, z2), Vec3d(-s2, 0, z2), Vec3d(0, s2, z2), Vec3d(0, -s2, z2)
248                 };
249                 Vec3d boardRVec[nrotat] =
250                 {
251                     Vec3d(0, 0, 0),
252                     Vec3d(e1 * deg2rad, 0, 0), Vec3d(e2 * deg2rad, 0, 0), Vec3d(-e1 * deg2rad, 0, 0), Vec3d(-e2 * deg2rad, 0, 0),
253                     Vec3d(0, e1 * deg2rad, 0), Vec3d(0, e2 * deg2rad, 0), Vec3d(0, -e1 * deg2rad, 0),  Vec3d(0, -e2 * deg2rad, 0)
254                 };
255                 for (int i = 0, k = 0; i < ntrans; ++i)
256                     for (int j = 0; j < nrotat; ++j, ++k)
257                     {
258                         boardPoses[whichModel][k].setPos(boardTVec[i].val);
259                         boardPoses[whichModel][k].setRot(boardRVec[j].val, 3);
260                     }
261             }
262         }
263 
264         void resetCamKDAB(int camInd = 0)
265         {
266             //1.ModelParams
267             if (cams[camInd].camModel == VisionCM::RTCM || cams[camInd].camModel == VisionCM::KBCM) { cams[camInd].ab[0] = 0; cams[camInd].ab[1] = 1; }
268             else if (cams[camInd].camModel == VisionCM::MUCM || cams[camInd].camModel == VisionCM::EUCM)
269             {
270                 cams[camInd].ab[1] = cams[camInd].camModel == VisionCM::MUCM ? 1. : Vec2d::randu(0, 9.99)(0);
271                 cams[camInd].ab[0] = sqrt(cams[camInd].ab[1] / pow(tan(((vecFOV[cams[camInd].camModel] < 200 ? 200 : vecFOV[cams[camInd].camModel] > 300 ? 330 : vecFOV[cams[camInd].camModel] + 30) * 0.5 - 90) * deg2rad), 2) + 1);
272             }
273             else if (cams[camInd].camModel == VisionCM::DSCM)
274             {
275                 cams[camInd].ab[1] = Vec2d::randu(-9.99, 9.99)(0);
276                 cams[camInd].ab[0] = -1. / cos((vecFOV[cams[camInd].camModel] < 200 ? 200 : vecFOV[cams[camInd].camModel] > 300 ? 330 : vecFOV[cams[camInd].camModel] + 30) * 0.5 * deg2rad);
277             }
278             if (cams[camInd].simPin == 1) cams[camInd].ab[0] = cams[camInd].ab[0] / (1 + cams[camInd].ab[0]);
279 
280             //2.CameraParams
281             cams[camInd].K[2] = imaCols * (0.5 + Vec2d::randu(-0.08, 0.08)(0));
282             cams[camInd].K[3] = imaRows * (0.5 + Vec2d::randu(-0.08, 0.08)(0));
283             if (cams[camInd].camModel == VisionCM::RTCM)
284             {
285                 double halfFOV = vecFOV[0] / 2 * deg2rad;
286                 cams[camInd].K[0] = cams[camInd].K[1] = (imaCols + imaRows) / tan(halfFOV) / 4;
287                 cams[camInd].K[0] *= (1 + Vec2d::randu(-0.02, 0.02)(0));
288                 cams[camInd].K[1] *= (1 + Vec2d::randu(-0.02, 0.02)(0));
289             }
290             else if (cams[camInd].camModel == VisionCM::KBCM)
291             {
292                 double halfFOV = vecFOV[1] / 2 * deg2rad;
293                 cams[camInd].K[0] = cams[camInd].K[1] = (imaCols + imaRows) / halfFOV / 4;
294                 cams[camInd].K[0] *= (1 + Vec2d::randu(-0.01, 0.04)(0));
295                 cams[camInd].K[1] *= (1 + Vec2d::randu(-0.01, 0.04)(0));
296             }
297             else if (cams[camInd].camModel == VisionCM::MUCM || cams[camInd].camModel == VisionCM::EUCM)
298             {
299                 //if (cams[camInd].simPin == false);
300                 double halfFOV = vecFOV[2] / 2 * deg2rad;
301                 if (0)
302                 {
303                     double A = cams[camInd].simPin ? cams[camInd].ab[0] / (1 - cams[camInd].ab[0]) : cams[camInd].ab[0], A2 = A * A, A3 = A * A2, A4 = A2 * A2;
304                     double b = cams[camInd].ab[1], b2 = b * b;
305                     double e = tan(abs(halfFOV - pi / 2)), e2 = e * e;
306 
307                     vector<double> coeffs = { e2 * b - e2 * b * A2 - b2 * A2, 2 * e * b * A, e2 * A2 + b * A2 - b * A4 - e2 * A4, 2 * e * A3, A4 };
308                     vector<double> coeffs1 = { A4, 2 * e * A3, e2 * A2 + b * A2 - b * A4 - e2 * A4, 2 * e * b * A, e2 * b - e2 * b * A2 - b2 * A2 };
309                     Mat_<double> Fs; cv::solvePoly(coeffs, Fs);
310                     cout << endl << Fs << endl; getchar();
311                 }
312                 cams[camInd].K[0] = cams[camInd].K[1] = (cams[camInd].K[2] + cams[camInd].K[3]) * 0.66;
313                 cams[camInd].K[0] *= (1 + Vec2d::randu(-0.01, 0.01)(0));
314                 cams[camInd].K[1] *= (1 + Vec2d::randu(-0.01, 0.01)(0));
315             }
316             else if (cams[camInd].camModel == VisionCM::DSCM) {}
317 
318             //3.DistortionParams
319             memset(cams[camInd].D, 0, sizeof(cams[camInd].D)); cv::randu(Mat_<double>(cams[camInd].nDist, 1, cams[camInd].D), -maxDist, maxDist);
320             stable_sort(cams[camInd].D, cams[camInd].D + cams[camInd].nDist, [](double a, double b)->bool { return abs(a) > abs(b); });
321         }
322         void resetCamPose(double* rvec, double* tvec, int camInd = 0)
323         {
324             camPoses[camInd].setPos(tvec);
325             camPoses[camInd].setRot(rvec, 3);
326         }
327 
328         void createRawMotion(int step = 1, int camInd = 0)
329         {
330             rawObs[camInd].clear();
331             for (int k = 0; k < nboard; k += step)
332             {
333                 //2.1 GetPose
334                 SolidPose viewPose = camPoses[camInd].inv().mul(boardPoses[cams[camInd].camModel][k]);
335 
336                 //2.2 ProjectPoints
337                 vector<Point2f> corner2D;
338                 if (cams[camInd].camModel == VisionCM::RTCM)
339                     projectPoints(corner3D, Vec3d(viewPose.vdata), Vec3d(viewPose.tdata), Matx33d(cams[camInd].K[0], 0, cams[camInd].K[2], 0, cams[camInd].K[1], cams[camInd].K[3], 0, 0, 1), Mat_<double>(cams[camInd].nDist, 1, cams[camInd].D), corner2D);
340                 else if (cams[camInd].camModel == VisionCM::KBCM)
341                     fisheye::projectPoints(corner3D, corner2D, Vec3d(viewPose.vdata), Vec3d(viewPose.tdata), Matx33d(cams[camInd].K[0], 0, cams[camInd].K[2], 0, cams[camInd].K[1], cams[camInd].K[3], 0, 0, 1), Mat_<double>(cams[camInd].nDist, 1, cams[camInd].D));
342                 else if (cams[camInd].camModel == VisionCM::MUCM)
343                     omnidir::projectPoints(corner3D, corner2D, Vec3d(viewPose.vdata), Vec3d(viewPose.tdata), Matx33d(cams[camInd].K[0], 0, cams[camInd].K[2], 0, cams[camInd].K[1], cams[camInd].K[3], 0, 0, 1), cams[camInd].ab[0], Mat_<double>(cams[camInd].nDist, 1, cams[camInd].D));
344                 else if (cams[camInd].camModel == VisionCM::EUCM) {}
345                 else if (cams[camInd].camModel == VisionCM::DSCM) {}
346                 //2.3 CheckValid
347                 bool ok = true;
348                 for (int k = 0; k < corner2D.size(); ++k)
349                     if (corner2D[k].x < 10 || corner2D[k].x > imaCols - 10 || corner2D[k].y < 10 || corner2D[k].y > imaRows - 10) ok = false;
350                 //if (!ok) spdlog::warn("Invalid view and tvec{} rvec{}: {} {} {} {} {} {}", i, j, tvec[0], tvec[1], tvec[2], rvec[0], rvec[1], rvec[2]);
351 
352                 //2.4 AddGroup
353                 rawObs[camInd].poses.push_back(viewPose);
354                 rawObs[camInd].point3D.push_back(corner3D);
355                 rawObs[camInd].point2D.push_back(corner2D);
356                 rawObs[camInd].oksView.push_back(ok);
357             }
358         }
359         void refineRawMotion(vector<bool> oksView, int camInd = 0)
360         {
361             if (oksView.size() != rawObs[camInd].oksView.size()) { spdlog::critical("No same views: {}!={}", oksView.size(), rawObs[camInd].oksView.size()); assert(0); }
362             for (int k = 0; k < rawObs[camInd].oksView.size(); ++k) rawObs[camInd].oksView[k] = rawObs[camInd].oksView[k] && oksView[k];
363         }
364         void createDstMotion(int step = 1, int camInd = 0)
365         {
366             dstObs[camInd].clear();
367             for (int k = 0; k < rawObs[camInd].oksView.size(); k += step)
368             {
369                 if (!rawObs[camInd].oksView[k]) continue;
370                 dstObs[camInd].poses.push_back(rawObs[camInd].poses[k]);
371                 dstObs[camInd].point3D.push_back(rawObs[camInd].point3D[k]);
372                 dstObs[camInd].point2D.push_back(rawObs[camInd].point2D[k]);
373                 dstObs[camInd].oksView.push_back(true);
374             }
375             Vec6d idealFOV = cams[camInd].idealFOV(imaRows, imaCols);
376             spdlog::info("Cam{:}: ValidViews={:}/{:}  ImaSize=({}, {})  idealFOV=({:.1f}, {:.1f}, {:.1f}, {:.1f}, {:.1f}, {:.1f}, {:.1f})", camInd, dstObs[camInd].point3D.size(), rawObs[camInd].point3D.size(), imaCols, imaRows,
377                 idealFOV[0], idealFOV[1], idealFOV[2], idealFOV[3], idealFOV[4], idealFOV[5], cams[camInd].limitFOV());
378         }
379 
380     public://Visualize
381         void visMotion(int camInd0 = 0)
382         {
383             //1.CreateWidgets
384             static int camInd; camInd = camInd0;
385             viz::WCoordinateSystem worldSys(cmBoardMaxSide / 2);//basicSolid
386             viz::WPlane worldGrd(Point3d(camPoses[0].tdata[0], camPoses[0].tdata[1], camPoses[0].tdata[2]), Vec3d(0, 1, 0), Vec3d(0, 0, 1), Size2d(200, 200));//basicSolid
387             viz::WText worldTip(fmt::format("FunKey: w-s-d-a-8-5-6-4\nCamInd: {}\n{}{}", camInd, cams[camInd].print(imaRows, imaCols), camPoses[camInd].print()), Point(10, 480), 10);
388             vector<cv::Affine3d> camAffs; for (int k = 0; k < ncamera; ++k) camAffs.push_back(cv::Affine3d(Matx33d(camPoses[k].mdata), Vec3d(camPoses[k].tdata)));
389             viz::WTrajectory camTraj1(camAffs, viz::WTrajectory::FRAMES, cmSquareSide * 0.6);
390             viz::WTrajectorySpheres camTraj2(camAffs, 100, cmSquareSide * 0.1);
391             viz::WTrajectoryFrustums camTraj3(camAffs, Matx33d(cmBoardMinSide, 0, cmBoardMinSide * 0.85, 0, cmBoardMinSide, cmBoardMinSide * 0.85, 0, 0, 1), cmSquareSide * 0.4, viz::Color::yellow());
392             static vector<cv::Affine3d> boardAffs; for (int k = 0; k < nboard; ++k) boardAffs.push_back(cv::Affine3d(Matx33d(boardPoses[cams[camInd].camModel][k].mdata), Vec3d(boardPoses[cams[camInd].camModel][k].tdata)));
393             static viz::WTrajectorySpheres boardTraj(boardAffs, 1000, cmSquareSide * 0.1);
394 
395             //2.ShowWidgets
396             worldSys.setRenderingProperty(viz::OPACITY, 0.1);
397             worldGrd.setRenderingProperty(viz::OPACITY, 0.1);
398             camTraj1.setRenderingProperty(viz::OPACITY, 0.5);
399             camTraj2.setRenderingProperty(viz::OPACITY, 0.5);
400             camTraj3.setRenderingProperty(viz::OPACITY, 0.5);
401             boardTraj.setRenderingProperty(viz::OPACITY, 0.5);
402             static viz::Viz3d viz3d(__FUNCTION__);
403             viz3d.showWidget("worldSys", worldSys);
404             viz3d.showWidget("worldGrd", worldGrd);
405             viz3d.showWidget("worldTip", worldTip);
406             viz3d.showWidget("camTraj1", camTraj1);
407             viz3d.showWidget("camTraj2", camTraj2);
408             viz3d.showWidget("camTraj3", camTraj3);
409             viz3d.showWidget("boardTraj", boardTraj);
410 
411             //3.UpdateWidghts
412             static BoardMotion& thisMotion = *this;
413             viz3d.registerKeyboardCallback([](const viz::KeyboardEvent& keyboarEvent, void* pVizBorad)->void
414                 {
415                     if (keyboarEvent.action != viz::KeyboardEvent::KEY_DOWN) return;
416 
417                     //3.1 UpdateViewTraj
418                     if (keyboarEvent.code == 'w') thisMotion.vecZ1[thisMotion.cams[camInd].camModel] += thisMotion.cmBoardMinSide * 0.1;
419                     else if (keyboarEvent.code == 's') thisMotion.vecZ1[thisMotion.cams[camInd].camModel] -= thisMotion.cmBoardMinSide * 0.1;
420                     else if (keyboarEvent.code == 'd') thisMotion.vecS1[thisMotion.cams[camInd].camModel] += thisMotion.cmBoardMinSide * 0.1;
421                     else if (keyboarEvent.code == 'a') thisMotion.vecS1[thisMotion.cams[camInd].camModel] -= thisMotion.cmBoardMinSide * 0.1;
422                     else if (keyboarEvent.code == '8') thisMotion.vecZ2[thisMotion.cams[camInd].camModel] += thisMotion.cmBoardMinSide * 0.1;
423                     else if (keyboarEvent.code == '5') thisMotion.vecZ2[thisMotion.cams[camInd].camModel] -= thisMotion.cmBoardMinSide * 0.1;
424                     else if (keyboarEvent.code == '6') thisMotion.vecS2[thisMotion.cams[camInd].camModel] += thisMotion.cmBoardMinSide * 0.1;
425                     else if (keyboarEvent.code == '4') thisMotion.vecS2[thisMotion.cams[camInd].camModel] -= thisMotion.cmBoardMinSide * 0.1;
426                     if (keyboarEvent.code == 'w' || keyboarEvent.code == 's' || keyboarEvent.code == 'd' || keyboarEvent.code == 'a' ||
427                         keyboarEvent.code == '8' || keyboarEvent.code == '5' || keyboarEvent.code == '6' || keyboarEvent.code == '4')
428                     {
429                         thisMotion.resetBoardPose();
430                         thisMotion.createRawMotion(1, camInd);
431                         thisMotion.createDstMotion(1, camInd);
432                         boardAffs.clear();
433                         for (int k = 0; k < thisMotion.nboard; ++k) boardAffs.push_back(cv::Affine3d(Matx33d(thisMotion.boardPoses[thisMotion.cams[camInd].camModel][k].mdata), Vec3d(thisMotion.boardPoses[thisMotion.cams[camInd].camModel][k].tdata)));
434                         boardTraj = viz::WTrajectorySpheres(boardAffs, 1000, 1);
435                         boardTraj.setRenderingProperty(viz::OPACITY, 0.5);
436                         viz3d.showWidget("boardTraj", boardTraj);//auto cover the widget with same id
437                     }
438 
439                     //3.3 UpdateEachView
440                     static int viewPos = 0;//absolute index
441                     if (keyboarEvent.code == ' ')//Press space for next view
442                     {
443                         //1.GetNewView
444                         int viewCnt = int(thisMotion.rawObs[camInd].point3D.size());
445                         int viewInd = viewPos % viewCnt;
446 
447                         //2.FindMinMax
448                         Point3f min3D(FLT_MAX, FLT_MAX, FLT_MAX), max3D(-FLT_MAX, -FLT_MAX, -FLT_MAX);
449                         Point2f min2D(FLT_MAX, FLT_MAX), max2D(-FLT_MAX, -FLT_MAX);
450                         for (int k = 0; k < thisMotion.rawObs[camInd].point3D[k].size(); ++k)//Find
451                         {
452                             Point3f pt3 = thisMotion.rawObs[camInd].point3D[viewInd][k];
453                             Point2f pt2 = thisMotion.rawObs[camInd].point2D[viewInd][k];
454                             if (pt3.x < min3D.x) min3D.x = pt3.x;
455                             if (pt3.x > max3D.x) max3D.x = pt3.x;
456                             if (pt3.y < min3D.y) min3D.y = pt3.y;
457                             if (pt3.y > max3D.y) max3D.y = pt3.y;
458                             if (pt2.x < min2D.x) min2D.x = pt2.x;
459                             if (pt2.x > max2D.x) max2D.x = pt2.x;
460                             if (pt2.y < min2D.y) min2D.y = pt2.y;
461                             if (pt2.y > max2D.y) max2D.y = pt2.y;
462                         }
463 
464                         //3.AddWidget
465                         if (viewPos != 0)//exclude first start
466                             for (int k = 0; k < thisMotion.rawObs[camInd].point3D[viewInd == 0 ? viewCnt - 1 : viewInd - 1].size(); ++k) viz3d.removeWidget("corner" + std::to_string(k));//if current view has no same number of corners as last view
467                         viz3d.showWidget("viewSys", viz::WCoordinateSystem(thisMotion.cmBoardMinSide / 2), boardAffs[viewInd]);
468                         for (int k = 0; k < thisMotion.rawObs[camInd].point3D[viewInd].size(); ++k) viz3d.showWidget(fmt::format("corner{}", k), viz::WSphere(thisMotion.rawObs[camInd].point3D[viewInd][k], 1, 10), boardAffs[viewInd]);//show all corners of current view
469                         Mat_<uchar> ima2D(thisMotion.imaRows, thisMotion.imaCols, uchar(255));
470                         for (int k = 0; k < thisMotion.rawObs[camInd].point2D[viewInd].size(); ++k)
471                         {
472                             Point2f pt = thisMotion.rawObs[camInd].point2D[viewInd][k];
473                             if (pt.x < 10 || pt.x > thisMotion.imaCols - 10 || pt.y < 10 || pt.y > thisMotion.imaRows - 10) continue;
474                             cv::circle(ima2D, Point(int(pt.x), int(pt.y)), 2, Scalar::all(0), 4, 8, 0);
475                         }
476                         viz3d.showWidget("ima2D", viz::WImage3D(ima2D, Size2d(thisMotion.cmBoardWidth, thisMotion.cmBoardHeight)));
477                         viz3d.getWidget("ima2D").setRenderingProperty(viz::OPACITY, 0.8);
478 
479                         //4.ShowText
480                         string viewTip;
481                         viewTip += fmt::format("ViewCount: {}\n", thisMotion.rawObs[camInd].point3D.size());
482                         viewTip += fmt::format("ValidCount: {}\n", thisMotion.dstObs[camInd].point3D.size());
483                         viewTip += fmt::format("CurrentView: {}\n", viewInd);
484                         viewTip += fmt::format("CurrentValid: {}\n", thisMotion.rawObs[camInd].oksView[viewInd]);
485                         viewTip += fmt::format("Z1-Z2-S1-S2: {:.1f} {:.1f} {:.1f} {:.1f}\n",
486                             thisMotion.vecZ1[thisMotion.cams[camInd].camModel] / thisMotion.cmBoardMinSide,
487                             thisMotion.vecZ2[thisMotion.cams[camInd].camModel] / thisMotion.cmBoardMinSide,
488                             thisMotion.vecS1[thisMotion.cams[camInd].camModel] / thisMotion.cmBoardMinSide,
489                             thisMotion.vecS2[thisMotion.cams[camInd].camModel] / thisMotion.cmBoardMinSide);
490                         viewTip += fmt::format("MinMaxPoint3D: {:.1f} {:.1f} {:.1f} {:.1f}\n", min3D.x, min3D.y, max3D.x, max3D.y);
491                         viewTip += fmt::format("MinMaxPoint2D: {:.1f} {:.1f} {:.1f} {:.1f}\n", min2D.x, min2D.y, max2D.x, max2D.y);
492                         viewTip += fmt::format("CurrentBoardPose:\n{}", thisMotion.boardPoses[thisMotion.cams[camInd].camModel][viewInd].print());
493                         viewTip += fmt::format("CurrentRelativePose:\n{}", thisMotion.rawObs[camInd].poses[viewInd].print());
494                         viz3d.showWidget("viewTip", viz::WText(viewTip, Point(10, 10), 10));
495                         ++viewPos;
496                     }
497                 }, 0);
498             viz3d.spin();
499         }
500     };
501 
502 public://VisMotion
503     static void VisRTCM(int argc, char** argv) { BoardMotion boardMotion; boardMotion.initMotion(5, VisionCM::RTCM, true, false); boardMotion.createRawMotion(1, 2); boardMotion.createDstMotion(1, 2); boardMotion.visMotion(2); }
504     static void VisKBCM(int argc, char** argv) { BoardMotion boardMotion; boardMotion.initMotion(4, VisionCM::KBCM, true, false); boardMotion.createRawMotion(1, 4); boardMotion.createDstMotion(1, 4); boardMotion.visMotion(4); }
505     static void VisMUCM(int argc, char** argv) { BoardMotion boardMotion; boardMotion.initMotion(4, VisionCM::MUCM, false, false); boardMotion.createRawMotion(1, 6); boardMotion.createDstMotion(1, 6); boardMotion.visMotion(6); }
506 
507 public://TestCalib
508     static void CalibMono(int argc, char** argv)
509     {
510         for (int k = 0; k < 99; ++k)
511         {
512             //0.GenerateData
513             int whichModel = k % 3;
514             const int camInd = 0;
515             BoardMotion boardMotion;
516             if (whichModel == 0) boardMotion.initMotion(5, VisionCM::RTCM, true, false);
517             else if (whichModel == 1) boardMotion.initMotion(4, VisionCM::KBCM, true, false);
518             else if (whichModel == 2) boardMotion.initMotion(4, VisionCM::MUCM, false, false);
519             boardMotion.createRawMotion(2, camInd);
520             boardMotion.createDstMotion(1, camInd);
521             Size imaSize(boardMotion.imaCols, boardMotion.imaRows);
522             Mat_<double> camK0({ 3, 3 }, { boardMotion.cams[camInd].K[0], 0, boardMotion.cams[camInd].K[2], 0, boardMotion.cams[camInd].K[1], boardMotion.cams[camInd].K[3], 0, 0, 1 });
523             Mat_<double> camD0(boardMotion.cams[camInd].nDist, 1, boardMotion.cams[camInd].D);
524             Mat_<double> camAB0(boardMotion.cams[camInd].nModel, 1, boardMotion.cams[camInd].ab);
525             Mat_<Vec3d> camRs0; for (int i = 0; i < boardMotion.dstObs[camInd].poses.size(); ++i) camRs0.push_back(Vec3d(boardMotion.dstObs[camInd].poses[i].vdata));
526             Mat_<Vec3d> camTs0; for (int i = 0; i < boardMotion.dstObs[camInd].poses.size(); ++i) camTs0.push_back(Vec3d(boardMotion.dstObs[camInd].poses[i].tdata));
527 
528             //1.Calibration
529             Mat_<double> camK1;
530             Mat_<double> camD1;
531             Mat_<double> camAB1;
532             Mat_<Vec3d> camRs;
533             Mat_<Vec3d> camTs;
534             Mat_<double> errCamKD;
535             Mat_<double> errCamRT;
536             Mat_<double> errReprs;
537             Mat_<int> validIds;
538             double errRepr = 0;
539             if (whichModel == 0) errRepr =
540                 calibrateCamera(boardMotion.dstObs[camInd].point3D, boardMotion.dstObs[camInd].point2D, imaSize, camK1, camD1, camRs, camTs, errCamKD, errCamRT, errReprs, 0, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 60, 1e-6));
541             if (whichModel == 1) errRepr =
542                 fisheye::calibrate(boardMotion.dstObs[camInd].point3D, boardMotion.dstObs[camInd].point2D, imaSize, camK1, camD1, camRs, camTs, fisheye::CALIB_RECOMPUTE_EXTRINSIC, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 80, 1e-6));
543             if (whichModel == 2) errRepr =
544                 omnidir::calibrate(boardMotion.dstObs[camInd].point3D, boardMotion.dstObs[camInd].point2D, imaSize, camK1, camAB1, camD1, camRs, camTs, omnidir::CALIB_FIX_SKEW, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, 1e-6), validIds);
545 
546             //2.AnalyzeError
547             double infcamK0camK1 = cv::norm(camK0, camK1, NORM_INF);
548             double infcamD0camD1 = cv::norm(camD0.reshape(1, 1), camD1.reshape(1, 1), NORM_INF);
549             double infcamAB0camAB1 = 0; if (!camAB0.empty() && !camAB1.empty()) infcamAB0camAB1 = cv::norm(camAB0.row(0), camAB1, NORM_INF);
550 
551             //3.PrintError
552             spdlog::info("LOOP{} {} calibrate done: {}", k, whichModel == 0 ? "RTCM" : whichModel == 1 ? "KBCM" : "MUCM", errRepr);
553             if (infcamK0camK1 > 1E-6 || infcamD0camD1 > 1E-6 || infcamAB0camAB1 > 1E-6)
554             {
555                 cout << "infcamK0camK1: " << infcamK0camK1 << endl;
556                 cout << "infcamD0camD1: " << infcamD0camD1 << endl;
557                 cout << "infcamAB0camAB1: " << infcamAB0camAB1 << endl;
558                 if (1)
559                 {
560                     cout << endl << "camK0: " << camK0.reshape(1, 1) << endl;
561                     cout << endl << "camD0: " << camD0.reshape(1, 1) << endl;
562                     if (!camAB0.empty()) cout << endl << "camAB0: " << camAB0.reshape(1, 1) << endl;
563                     cout << endl << "camK1: " << camK1.reshape(1, 1) << endl;
564                     cout << endl << "camD1: " << camD1.reshape(1, 1) << endl;
565                     if (!camAB1.empty()) cout << endl << "camAB1: " << camAB1.reshape(1, 1) << endl;
566                 }
567                 cout << endl << "Press any key to continue" << endl; getchar();
568             }
569         }
570     }
571     static void CalibBino(int argc, char** argv)
572     {
573         for (int k = 0; k < 99; ++k)
574         {
575             //0.GenerateData
576             int whichModel = k % 3;
577             const int camInd1 = 1;
578             const int camInd2 = 3;
579             BoardMotion boardMotion;
580             if (whichModel == 0) boardMotion.initMotion(5, VisionCM::RTCM, true, false);
581             else if (whichModel == 1) boardMotion.initMotion(4, VisionCM::KBCM, true, false);
582             else if (whichModel == 2) boardMotion.initMotion(4, VisionCM::MUCM, false, false);
583             boardMotion.createRawMotion(2, camInd1);
584             boardMotion.createRawMotion(2, camInd2);
585             boardMotion.refineRawMotion(boardMotion.rawObs[camInd1].oksView, camInd2);
586             boardMotion.refineRawMotion(boardMotion.rawObs[camInd2].oksView, camInd1);
587             boardMotion.createDstMotion(1, camInd1);
588             boardMotion.createDstMotion(1, camInd2);
589             Size imaSize(boardMotion.imaCols, boardMotion.imaRows);
590             Mat_<double> cam1K0({ 3, 3 }, { boardMotion.cams[camInd1].K[0], 0, boardMotion.cams[camInd1].K[2], 0, boardMotion.cams[camInd1].K[1], boardMotion.cams[camInd1].K[3], 0, 0, 1 });
591             Mat_<double> cam2K0({ 3, 3 }, { boardMotion.cams[camInd2].K[0], 0, boardMotion.cams[camInd2].K[2], 0, boardMotion.cams[camInd2].K[1], boardMotion.cams[camInd2].K[3], 0, 0, 1 });
592             Mat_<double> cam1D0(boardMotion.cams[camInd1].nDist, 1, boardMotion.cams[camInd1].D);
593             Mat_<double> cam2D0(boardMotion.cams[camInd2].nDist, 1, boardMotion.cams[camInd2].D);
594             Mat_<double> cam1AB0(boardMotion.cams[camInd1].nModel, 1, boardMotion.cams[camInd1].ab);
595             Mat_<double> cam2AB0(boardMotion.cams[camInd2].nModel, 1, boardMotion.cams[camInd2].ab);
596             Mat_<Vec3d> cam1Rs0; for (int i = 0; i < boardMotion.dstObs[camInd1].poses.size(); ++i) cam1Rs0.push_back(Vec3d(boardMotion.dstObs[camInd1].poses[i].vdata));
597             Mat_<Vec3d> cam1Ts0; for (int i = 0; i < boardMotion.dstObs[camInd1].poses.size(); ++i) cam1Ts0.push_back(Vec3d(boardMotion.dstObs[camInd1].poses[i].tdata));
598             Mat_<Vec3d> cam2Rs0; for (int i = 0; i < boardMotion.dstObs[camInd2].poses.size(); ++i) cam2Rs0.push_back(Vec3d(boardMotion.dstObs[camInd2].poses[i].vdata));
599             Mat_<Vec3d> cam2Ts0; for (int i = 0; i < boardMotion.dstObs[camInd2].poses.size(); ++i) cam2Ts0.push_back(Vec3d(boardMotion.dstObs[camInd2].poses[i].tdata));
600             Mat_<double> cam21R0 = Mat_<double>(3, 3, boardMotion.camPoses[camInd2].inv().mul(boardMotion.camPoses[camInd1]).mdata).clone();
601             Mat_<double> cam21T0 = Mat_<double>(3, 1, boardMotion.camPoses[camInd2].inv().mul(boardMotion.camPoses[camInd1]).tdata).clone();
602 
603             //1.Calibration
604             Mat_<double> cam1K1, cam2K1;
605             Mat_<double> cam1D1, cam2D1;
606             Mat_<double> cam1AB1, cam2AB1;
607             Mat_<Vec3d> cam1Rs1, cam2Rs1;
608             Mat_<Vec3d> cam1Ts1, cam1Ts2;
609             Mat_<double> errCamKD1, errCamKD2;
610             Mat_<double> errCamRT1, errCamRT2;
611             Mat_<double> errReprs1, errReprs2;
612             Mat_<double> cam21R1, cam21T1, cam21E1, cam21F1;
613             Mat_<int> validIds;
614             double errRepr = 0;
615             if (whichModel == 0) errRepr = stereoCalibrate(boardMotion.rawObs[camInd1].point3D, boardMotion.rawObs[camInd1].point2D, boardMotion.rawObs[camInd2].point2D, cam1K1, cam1D1, cam2K1, cam2D1,
616                 imaSize, cam21R1, cam21T1, cam21E1, cam21F1, 0, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 60, 1e-6));
617             if (whichModel == 1) errRepr = fisheye::stereoCalibrate(boardMotion.rawObs[camInd1].point3D, boardMotion.rawObs[camInd1].point2D, boardMotion.rawObs[camInd2].point2D, cam1K1, cam1D1, cam2K1, cam2D1,
618                 imaSize, cam21R1, cam21T1, fisheye::CALIB_RECOMPUTE_EXTRINSIC, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 80, 1e-6));
619             if (whichModel == 2) errRepr = omnidir::stereoCalibrate(boardMotion.rawObs[camInd1].point3D, boardMotion.rawObs[camInd1].point2D, boardMotion.rawObs[camInd2].point2D, imaSize, imaSize,
620                 cam1K1, cam1AB1, cam1D1, cam2K1, cam2AB1, cam2D1, cam21R1, cam21T1, cam1Rs1, cam1Ts1, omnidir::CALIB_FIX_SKEW, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, 1e-6), validIds);
621             if (cam21R1.total() == 3) cv::Rodrigues(cam21R1, cam21R1);
622 
623             //2.AnalyzeError
624             double infcam1K0cam1K1 = cv::norm(cam1K0, cam1K1, NORM_INF);
625             double infcam1D0cam1D1 = cv::norm(cam1D0.reshape(1, 1), cam1D1.reshape(1, 1), NORM_INF);
626             double infcam2K0cam2K1 = cv::norm(cam2K0, cam2K1, NORM_INF);
627             double infcam2D0cam2D1 = cv::norm(cam2D0.reshape(1, 1), cam2D1.reshape(1, 1), NORM_INF);
628             double infcam1AB0cam1AB1 = 0; if (!cam1AB0.empty() && !cam1AB1.empty()) infcam1AB0cam1AB1 = cv::norm(cam1AB0.row(0), cam1AB1, NORM_INF);
629             double infcam2AB0cam2AB1 = 0; if (!cam2AB0.empty() && !cam2AB1.empty()) infcam2AB0cam2AB1 = cv::norm(cam2AB0.row(0), cam2AB1, NORM_INF);
630             double infcam21R0cam21R1 = cv::norm(cam21R0, cam21R1, NORM_INF);
631             double infcam21T0cam21T1 = cv::norm(cam21T0, cam21T1, NORM_INF);
632 
633             //3.PrintError
634             spdlog::info("LOOP{} {} calibrate done: {}", k, whichModel == 0 ? "RTCM" : whichModel == 1 ? "KBCM" : "MUCM", errRepr);
635             if (infcam1K0cam1K1 > 1E-6 || infcam1D0cam1D1 > 1E-6 ||
636                 infcam2K0cam2K1 > 1E-6 || infcam2D0cam2D1 > 1E-6 ||
637                 infcam21R0cam21R1 > 1E-6 || infcam21T0cam21T1 > 1E-6)
638             {
639                 cout << "infcam1K0cam1K1: " << infcam1K0cam1K1 << endl;
640                 cout << "infcam1D0cam1D1: " << infcam1D0cam1D1 << endl;
641                 cout << "infcam2K0cam2K1: " << infcam2K0cam2K1 << endl;
642                 cout << "infcam2D0cam2D1: " << infcam2D0cam2D1 << endl;
643                 cout << "infcam1AB0cam1AB1: " << infcam1AB0cam1AB1 << endl;
644                 cout << "infcam2AB0cam2AB1: " << infcam2AB0cam2AB1 << endl;
645                 cout << "infcam21R0cam21R1: " << infcam21R0cam21R1 << endl;
646                 cout << "infcam21T0cam21T1: " << infcam21T0cam21T1 << endl;
647                 if (0)
648                 {
649                     cout << endl << "cam1K0: " << cam1K0.reshape(1, 1) << endl;
650                     cout << endl << "cam1D0: " << cam1D0.reshape(1, 1) << endl;
651                     if (!cam1AB0.empty()) cout << endl << "cam1AB0: " << cam1AB0.reshape(1, 1) << endl;
652                     cout << endl << "cam1K1: " << cam1K1.reshape(1, 1) << endl;
653                     cout << endl << "cam1D1: " << cam1D1.reshape(1, 1) << endl;
654                     if (!cam1AB1.empty()) cout << endl << "cam1AB1: " << cam1AB1.reshape(1, 1) << endl;
655                     cout << endl << "cam2K0: " << cam2K0.reshape(1, 1) << endl;
656                     cout << endl << "cam2D0: " << cam2D0.reshape(1, 1) << endl;
657                     if (!cam2AB0.empty()) cout << endl << "cam2AB0: " << cam2AB0.reshape(1, 1) << endl;
658                     cout << endl << "cam2K1: " << cam2K1.reshape(1, 1) << endl;
659                     cout << endl << "cam2D1: " << cam2D1.reshape(1, 1) << endl;
660                     if (!cam2AB1.empty()) cout << endl << "cam2AB1: " << cam2AB1.reshape(1, 1) << endl;
661                     cout << endl << "cam21R0: " << cam21R0.reshape(1, 1) << endl;
662                     cout << endl << "cam21T0: " << cam21R0.reshape(1, 1) << endl;
663                     cout << endl << "cam21R1: " << cam21R1.reshape(1, 1) << endl;
664                     cout << endl << "cam21T1: " << cam21T1.reshape(1, 1) << endl;
665                 }
666                 cout << endl << "Press any key to continue" << endl; getchar();
667             }
668         }
669     }
670 };
671 
672 #ifdef Motion2DTest
673 int main(int argc, char** argv) { Motion2D::CalibMono(argc, argv); return 0; }
674 int main1(int argc, char** argv) { Motion2D::VisRTCM(argc, argv); return 0; }
675 int main2(int argc, char** argv) { Motion2D::VisKBCM(argc, argv); return 0; }
676 int main3(int argc, char** argv) { Motion2D::VisMUCM(argc, argv); return 0; }
677 int main4(int argc, char** argv) { Motion2D::CalibMono(argc, argv); return 0; }
678 int main5(int argc, char** argv) { Motion2D::CalibBino(argc, argv); return 0; }
679 #endif
680 
681 #if 0
682 static void TestMonoMotion2D()
683 {
684     for (int k = 0; k < 99; ++k)
685     {
686         //0.GenerateData
687         string modelName = k % 2 == 0 ? "KBCM" : "MUCM";
688         const int camInd = 0;
689         Motion2D::BoardMotion boardMotion;
690         if (modelName == "KBCM") boardMotion.initMotion(4, Motion2D::VisionCM::KBCM, true, false);
691         if (modelName == "MUCM") boardMotion.initMotion(4, Motion2D::VisionCM::MUCM, false, false);
692         boardMotion.createRawMotion(2, camInd);
693         boardMotion.createDstMotion(1, camInd);
694         Size imaSize(boardMotion.imaCols, boardMotion.imaRows);
695         Mat_<double> camK0({ 3, 3 }, { boardMotion.cams[camInd].K[0], 0, boardMotion.cams[camInd].K[2], 0, boardMotion.cams[camInd].K[1], boardMotion.cams[camInd].K[3], 0, 0, 1 });
696         Mat_<double> camD0(boardMotion.cams[camInd].nDist, 1, boardMotion.cams[camInd].D);
697         Mat_<double> camAB0(boardMotion.cams[camInd].nModel, 1, boardMotion.cams[camInd].ab);
698         Mat_<Vec3d> camRs0; for (int i = 0; i < boardMotion.dstObs[camInd].poses.size(); ++i) camRs0.push_back(Vec3d(boardMotion.dstObs[camInd].poses[i].vdata));
699         Mat_<Vec3d> camTs0; for (int i = 0; i < boardMotion.dstObs[camInd].poses.size(); ++i) camRs0.push_back(Vec3d(boardMotion.dstObs[camInd].poses[i].tdata));
700         Size boardSize(boardMotion.nHorCorner, boardMotion.nVerCorner);
701         float cmSquareSide = boardMotion.cmSquareSide;
702 
703         //1.Calibration
704         camodocal::Camera::ModelType modelIndex = modelName == "KBCM" ? camodocal::Camera::KANNALA_BRANDT : camodocal::Camera::MEI;
705         camodocal::CameraCalibration calibration(modelIndex, modelName, imaSize, boardSize, cmSquareSide); calibration.setVerbose(true);
706         calibration.setVerbose(true);
707         calibration.m_imagePoints = boardMotion.dstObs[camInd].point2D;
708         calibration.m_scenePoints = boardMotion.dstObs[camInd].point3D;
709         calibration.calibrate();
710         Mat_<double> camK1(3, 3);
711         Mat_<double> camD1(4, 1);
712         Mat_<double> camAB1(1, 1, 0.);
713         vector<double> caliParams; calibration.m_camera->writeParameters(caliParams);
714         if (modelName == "MUCM") camK1 << caliParams[5], 0, caliParams[7], 0, caliParams[6], caliParams[8], 0, 0, 1; else camK1 << caliParams[4], 0, caliParams[6], 0, caliParams[5], caliParams[7], 0, 0, 1;
715         if (modelName == "MUCM") camD1 << caliParams[1], caliParams[2], caliParams[3], caliParams[4]; else camD1 << caliParams[0], caliParams[1], caliParams[2], caliParams[3];
716         if (modelName == "MUCM") camAB1 << caliParams[0], 0; else camAB1 << 0;
717 
718         //2.AnalyzeError
719         double infcamK0camK1 = cv::norm(camK0, camK1, NORM_INF);
720         double infcamD0camD1 = cv::norm(camD0.reshape(1, 1), camD1.reshape(1, 1), NORM_INF);
721         double infcamAB0camAB1 = 0; if (!camAB0.empty() && !camAB1.empty()) infcamAB0camAB1 = cv::norm(camAB0.row(0), camAB1, NORM_INF);
722 
723         //3.PrintError
724         spdlog::info("LOOP{} {} calibrate done", k, modelName);
725         if (infcamK0camK1 > 1E-6 || infcamD0camD1 > 1E-6 || infcamAB0camAB1 > 1E-6)
726         {
727             cout << "infcamK0camK1: " << infcamK0camK1 << endl;
728             cout << "infcamD0camD1: " << infcamD0camD1 << endl;
729             cout << "infcamAB0camAB1: " << infcamAB0camAB1 << endl;
730             if (0)
731             {
732                 cout << endl << "camK0: " << camK0.reshape(1, 1) << endl;
733                 cout << endl << "camD0: " << camD0.reshape(1, 1) << endl;
734                 if (!camAB0.empty()) cout << endl << "camAB0: " << camAB0.reshape(1, 1) << endl;
735                 cout << endl << "camK1: " << camK1.reshape(1, 1) << endl;
736                 cout << endl << "camD1: " << camD1.reshape(1, 1) << endl;
737                 if (!camAB1.empty()) cout << endl << "camAB1: " << camAB1.reshape(1, 1) << endl;
738             }
739             cout << endl << "Press any key to continue" << endl; getchar();
740         }
741     }
742 }
743 #endif
744 
745 #endif
View Code