00001 #include <stdio.h>
00002 #include <vector>
00003 #include "ceres/ceres.h"
00004 #include "ceres/rotation.h"
00005 #include <iostream>
00006 typedef struct
00007 {
00008 int p_id;
00009 double x;
00010 double y;
00011 } observation;
00012
00013 typedef struct
00014 {
00015 union
00016 {
00017 struct
00018 {
00019 double x;
00020 double y;
00021 double z;
00022 };
00023 double PB[3];
00024 };
00025 } point;
00026
00027 typedef struct
00028 {
00029 union
00030 {
00031 struct
00032 {
00033 double PB_extrinsics[6];
00034 double PB_intrinsics[9];
00035 };
00036 struct
00037 {
00038 double aa[3];
00039 double pos[3];
00040 double fx;
00041 double fy;
00042 double cx;
00043 double cy;
00044 double k1;
00045 double k2;
00046 double k3;
00047 double p1;
00048 double p2;
00049 };
00050 };
00051 } Camera;
00052
00053
00054 void print_QTasH(double qx, double qy, double qz, double qw, double tx, double ty, double tz);
00055 void print_AATasH(double x, double y, double z, double tx, double ty, double tz);
00056 void print_AATasHI(double x, double y, double z, double tx, double ty, double tz);
00057 void print_AAasEuler(double x, double y, double z);
00058 void print_camera(Camera C, std::string words);
00059 observation project_point(Camera C, point P);
00060
00061
00062 observation project_point(Camera C, point P)
00063 {
00064 double p[3];
00065 double pt[3];
00066 pt[0] = P.x;
00067 pt[1] = P.y;
00068 pt[2] = P.z;
00069
00070
00071
00072
00073 ceres::AngleAxisRotatePoint(C.aa, pt, p);
00074 printf("point %6.3lf %6.3lf %6.3lf rotated: %6.3lf %6.3lf %6.3lf ", P.x, P.y, P.z, p[0], p[1], p[2]);
00075 p[0] += C.pos[0];
00076 p[1] += C.pos[1];
00077 p[2] += C.pos[2];
00078 printf("translated: %6.3lf %6.3lf %6.3lf\n", p[0], p[1], p[2]);
00079
00080 double xp = p[0] / p[2];
00081 double yp = p[1] / p[2];
00082
00083
00084
00085 double r2 = xp * xp + yp * yp;
00086 double r4 = r2 * r2;
00087 double r6 = r2 * r4;
00088
00089 double xp2 = xp * xp;
00090 double yp2 = yp * yp;
00091
00092
00093 double xpp = xp + C.k1 * r2 * xp + C.k2 * r4 * xp + C.k3 * r6 * xp + C.p2 * (r2 + 2 * xp2) + 2 * C.p1 * xp * yp;
00094 double ypp = yp + C.k1 * r2 * yp + C.k2 * r4 * yp + C.k3 * r6 * yp + C.p1 * (r2 + 2 * yp2) + 2 * C.p2 * xp * yp;
00095
00096
00097 observation O;
00098 O.p_id = 0;
00099 O.x = C.fx * xpp + C.cx;
00100 O.y = C.fy * ypp + C.cy;
00101 return (O);
00102 }
00103
00104 struct Camera_reprj_error
00105 {
00106 Camera_reprj_error(double ob_x, double ob_y) :
00107 Ox(ob_x), Oy(ob_y)
00108 {
00109 }
00110
00111 template<typename T>
00112 bool operator()(const T* const c_p1,
00113 const T* c_p2,
00114 const T* point,
00115 T* resid) const
00116 {
00117
00118 int q = 0;
00119 const T& x = c_p1[q++];
00120 const T& y = c_p1[q++];
00121 const T& z = c_p1[q++];
00122 const T& tx = c_p1[q++];
00123 const T& ty = c_p1[q++];
00124 const T& tz = c_p1[q++];
00125
00126 q = 0;
00127 const T& fx = c_p2[q++];
00128 const T& fy = c_p2[q++];
00129 const T& cx = c_p2[q++];
00130 const T& cy = c_p2[q++];
00131 const T& k1 = c_p2[q++];
00132 const T& k2 = c_p2[q++];
00133 const T& k3 = c_p2[q++];
00134 const T& p1 = c_p2[q++];
00135 const T& p2 = c_p2[q++];
00136
00137
00138 T aa[3];
00139 T p[3];
00140 aa[0] = x;
00141 aa[1] = y;
00142 aa[2] = z;
00143 ceres::AngleAxisRotatePoint(aa, point, p);
00144
00145
00146 T xp1 = p[0] + tx;
00147 T yp1 = p[1] + ty;
00148 T zp1 = p[2] + tz;
00149
00150
00151 T xp = xp1 / zp1;
00152 T yp = yp1 / zp1;
00153
00154
00155 T r2 = xp * xp + yp * yp;
00156 T r4 = r2 * r2;
00157 T r6 = r2 * r4;
00158
00159 T xp2 = xp * xp;
00160 T yp2 = yp * yp;
00161
00162 T xpp = xp + k1 * r2 * xp + k2 * r4 * xp + k3 * r6 * xp + p2 * (r2 + T(2.0) * xp2) + T(2.0) * p1 * xp * yp;
00163 T ypp = yp + k1 * r2 * yp + k2 * r4 * yp + k3 * r6 * yp + p1 * (r2 + T(2.0) * yp2) + T(2.0) * p2 * xp * yp;
00164
00165 resid[0] = fx * xpp + cx - Ox;
00166 resid[1] = fy * ypp + cy - Oy;
00167
00168 return true;
00169 }
00170
00171
00172
00173 static ceres::CostFunction* Create(const double o_x, const double o_y)
00174 {
00175 return (new ceres::AutoDiffCostFunction<Camera_reprj_error, 2, 6, 9, 3>(new Camera_reprj_error(o_x, o_y)));
00176 }
00177 double Ox;
00178 double Oy;
00179 };
00180
00181 int main(int argc, char** argv)
00182 {
00183
00184 google::InitGoogleLogging(argv[0]);
00185 if (argc != 5)
00186 {
00187 std::cerr << "usage: monoExCal <3Dpoints_file> <observation_file> <intrinsic_file> <extrinsic_file>\n";
00188 return 1;
00189 }
00190 int num_points;
00191 int num_observations;
00192 observation o;
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219 FILE *points_fp = fopen(argv[1], "r");
00220 FILE *observations_fp = fopen(argv[2], "r");
00221 FILE *intrinsics_fp = fopen(argv[3], "r");
00222 FILE *extrinsics_fp = fopen(argv[4], "r");
00223 if (points_fp == NULL)
00224 {
00225 printf("Could not open file: %s", argv[1]);
00226 exit(1);
00227 }
00228 if (observations_fp == NULL)
00229 {
00230 printf("Could not open file: %s", argv[2]);
00231 exit(1);
00232 }
00233 if (intrinsics_fp == NULL)
00234 {
00235 printf("Could not open file: %s", argv[3]);
00236 exit(1);
00237 }
00238 if (extrinsics_fp == NULL)
00239 {
00240 printf("Could not open file: %s", argv[4]);
00241 exit(1);
00242 }
00243
00244
00245 if (fscanf(points_fp, "%d", &num_points) != 1)
00246 {
00247 printf("couldn't read num_points\n");
00248 exit(1);
00249 }
00250 std::vector<point> Pts;
00251 for (int i = 0; i < num_points; i++)
00252 {
00253 point p;
00254 if (fscanf(points_fp, "%lf %lf %lf", &p.x, &p.y, &p.z) != 3)
00255 {
00256 printf("couldn't read point %d from %s\n", i, argv[1]);
00257 exit(1);
00258 }
00259 Pts.push_back(p);
00260 }
00261 fclose(points_fp);
00262
00263
00264 if (fscanf(observations_fp, "%d", &num_observations) != 1)
00265 {
00266 printf("couldn't read num_observations\n");
00267 exit(1);
00268 }
00269 if (num_observations != num_points)
00270 {
00271 printf("WARNING, num_points NOT EQUAL to num_observations\n");
00272 }
00273 std::vector<observation> Ob;
00274 for (int i = 0; i < num_observations; i++)
00275 {
00276 if (fscanf(observations_fp, "%lf %lf", &o.x, &o.y) != 2)
00277 {
00278 printf("couldn't read observation %d from %s\n", i, argv[2]);
00279 exit(1);
00280 }
00281 o.p_id = i;
00282 Ob.push_back(o);
00283 }
00284 fclose(observations_fp);
00285
00286
00287 Camera C;
00288 char dum[255];
00289 double Dum, Dum2, Dum3;
00290 int image_width;
00291 int image_height;
00292 int rtn = 0;
00293 rtn += fscanf(intrinsics_fp, "%s", dum);
00294 rtn += fscanf(intrinsics_fp, "%s", dum);
00295 rtn += fscanf(intrinsics_fp, "%s", dum);
00296 rtn += fscanf(intrinsics_fp, "%s", dum);
00297
00298 rtn += fscanf(intrinsics_fp, "%s", dum);
00299
00300 rtn += fscanf(intrinsics_fp, "%d", &image_width);
00301 printf("image_width: %d\n", image_width);
00302 rtn += fscanf(intrinsics_fp, "%s", dum);
00303 rtn += fscanf(intrinsics_fp, "%d", &image_height);
00304 printf("height: %d\n", image_height);
00305 rtn += fscanf(intrinsics_fp, "%s", dum);
00306
00307 rtn += fscanf(intrinsics_fp, "%s", dum);
00308
00309 rtn += fscanf(intrinsics_fp, "%s", dum);
00310
00311 rtn += fscanf(intrinsics_fp, "%lf %lf %lf", &C.fx, &Dum, &C.cx);
00312 rtn += fscanf(intrinsics_fp, "%lf %lf %lf", &Dum, &C.fy, &C.cy);
00313 rtn += fscanf(intrinsics_fp, "%lf %lf %lf", &Dum, &Dum2, &Dum3);
00314 rtn += fscanf(intrinsics_fp, "%s", dum);
00315 printf("camera matrix:\n");
00316 printf("%8.3lf %8.3lf %8.3lf\n", C.fx, 0.0, C.cx);
00317 printf("%8.3lf %8.3lf %8.3lf\n", 0.0, C.fy, C.cy);
00318 printf("%8.3lf %8.3lf %8.3lf\n", 0.0, 0.0, 0.0);
00319
00320 rtn += fscanf(intrinsics_fp, "%lf %lf %lf %lf %lf", &C.k1, &C.k2, &C.k3, &C.p1, &C.p2);
00321 printf("Distortion: [ %8.3lf %8.3lf %8.3lf %8.3lf %8.3lf ]\n", C.k1, C.k2, C.k3, C.p1, C.p2);
00322 fclose(intrinsics_fp);
00323
00324
00325 double H[4][4];
00326 rtn = 0;
00327 rtn += fscanf(extrinsics_fp, "%lf %lf %lf %lf", &H[0][0], &H[0][1], &H[0][2], &H[0][3]);
00328 rtn += fscanf(extrinsics_fp, "%lf %lf %lf %lf", &H[1][0], &H[1][1], &H[1][2], &H[1][3]);
00329 rtn += fscanf(extrinsics_fp, "%lf %lf %lf %lf", &H[2][0], &H[2][1], &H[2][2], &H[2][3]);
00330 rtn += fscanf(extrinsics_fp, "%lf %lf %lf %lf", &H[3][0], &H[3][1], &H[3][2], &H[3][3]);
00331 if (rtn != 16)
00332 {
00333 printf("could not read extrinsics rtn=%d from %s\n", rtn, argv[4]);
00334 exit(1);
00335 }
00336 fclose(extrinsics_fp);
00337
00338
00339 double HI[9];
00340 HI[0] = H[0][0];
00341 HI[1] = H[0][1];
00342 HI[2] = H[0][2];
00343
00344 HI[3] = H[1][0];
00345 HI[4] = H[1][1];
00346 HI[5] = H[1][2];
00347
00348 HI[6] = H[2][0];
00349 HI[7] = H[2][1];
00350 HI[8] = H[2][2];
00351 C.pos[0] = -(H[0][3] * H[0][0] + H[1][3] * H[1][0] + H[2][3] * H[2][0]);
00352 C.pos[1] = -(H[0][3] * H[0][1] + H[1][3] * H[1][1] + H[2][3] * H[2][1]);
00353 C.pos[2] = -(H[0][3] * H[0][2] + H[1][3] * H[1][2] + H[2][3] * H[2][2]);
00354 printf("C.xyz = %lf %lf %lf\n", C.pos[0], C.pos[1], C.pos[2]);
00355 ceres::RotationMatrixToAngleAxis(HI, C.aa);
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367 #define MONO_EXCAL_DEBUG
00368 #ifdef MONO_EXCAL_DEBUG
00369
00370
00371 FILE *fp_temp1 = fopen("Obs.m", "w");
00372 FILE *fp_temp2 = fopen("Rep.m", "w");
00373 FILE *fp_temp3 = fopen("FRep.m", "w");
00374 fprintf(fp_temp1, "O = [ ");
00375 fprintf(fp_temp2, "R = [ ");
00376 fprintf(fp_temp3, "F = [ ");
00377 for (int i = 0; i < num_points; i++)
00378 {
00379 o = project_point(C, Pts[i]);
00380 printf("Errors %d = %lf %lf\n", i, Ob[i].x - o.x, Ob[i].y - o.y);
00381 fprintf(fp_temp1, "%lf %lf;\n", Ob[i].x, Ob[i].y);
00382 fprintf(fp_temp2, "%lf %lf;\n", o.x, o.y);
00383 }
00384 fprintf(fp_temp1, "];\n");
00385 fprintf(fp_temp2, "];\n");
00386 fclose(fp_temp1);
00387 fclose(fp_temp2);
00388 #endif // MONO_EXCAL_DEBUG
00389 print_camera(C, "Original Parameters");
00390
00391
00392 ceres::Problem problem;
00393 for (int i = 0; i < num_observations; ++i)
00394 {
00395
00396
00397
00398 ceres::CostFunction* cost_function = Camera_reprj_error::Create(Ob[i].x, Ob[i].y);
00399
00400 problem.AddResidualBlock(cost_function, NULL, C.PB_extrinsics, C.PB_intrinsics, Pts[i].PB);
00401 problem.SetParameterBlockConstant(C.PB_intrinsics);
00402 problem.SetParameterBlockConstant(Pts[i].PB);
00403
00404
00405
00406
00407
00408
00409 }
00410
00411
00412
00413
00414 ceres::Solver::Options options;
00415 options.linear_solver_type = ceres::DENSE_SCHUR;
00416 options.minimizer_progress_to_stdout = true;
00417 options.max_num_iterations = 1000;
00418
00419 ceres::Solver::Summary summary;
00420 ceres::Solve(options, &problem, &summary);
00421 std::cout << summary.FullReport() << "\n";
00422
00423 #ifdef MONO_EXCAL_DEBUG
00424
00425 for (int i = 0; i < num_points; i++)
00426 {
00427 o = project_point(C, Pts[i]);
00428 printf("%d : Ob= %6.3lf %6.3lf ", i, Ob[i].x, Ob[i].y);
00429 printf("%d : o= %6.3lf %6.3lf Errors = %10.3lf %10.3lf\n", i, o.x, o.y, Ob[i].x - o.x, Ob[i].y - o.y);
00430 fprintf(fp_temp3, "%lf %lf;\n", o.x, o.y);
00431 }
00432 fprintf(fp_temp3, "];\n");
00433 fclose(fp_temp3);
00434 #endif // MONO_EXCAL_DEBUG
00435
00436 print_camera(C, "final parameters");
00437
00438
00439 std::string temp(argv[4]);
00440 std::string new_ex_file = "new_" + temp;
00441 extrinsics_fp = fopen(new_ex_file.c_str(), "w");
00442 ceres::AngleAxisToRotationMatrix(C.aa, HI);
00443
00444
00445 H[0][0] = HI[0];
00446 H[0][1] = HI[1];
00447 H[0][2] = HI[2];
00448
00449 H[1][0] = HI[3];
00450 H[1][1] = HI[4];
00451 H[1][2] = HI[5];
00452
00453 H[2][0] = HI[6];
00454 H[2][1] = HI[7];
00455 H[2][2] = HI[8];
00456
00457 H[0][3] = -(C.pos[0] * HI[0] + C.pos[1] * HI[1] + C.pos[2] * HI[2]);
00458 H[1][3] = -(C.pos[0] * HI[3] + C.pos[1] * HI[4] + C.pos[2] * HI[5]);
00459 H[2][3] = -(C.pos[0] * HI[6] + C.pos[1] * HI[7] + C.pos[2] * HI[8]);
00460
00461 fprintf(extrinsics_fp, "%9.3lf %9.3lf %9.3lf %9.3lf\n", H[0][0], H[0][1], H[0][2], H[0][3]);
00462 fprintf(extrinsics_fp, "%9.3lf %9.3lf %9.3lf %9.3lf\n", H[1][0], H[1][1], H[1][2], H[1][3]);
00463 fprintf(extrinsics_fp, "%9.3lf %9.3lf %9.3lf %9.3lf\n", H[2][0], H[2][1], H[2][2], H[2][3]);
00464 fprintf(extrinsics_fp, "%9.3lf %9.3lf %9.3lf %9.3lf\n", 0.0, 0.0, 0.0, 1.0);
00465 fclose(extrinsics_fp);
00466
00467 return 0;
00468 }
00469
00470
00471 void print_QTasH(double qx, double qy, double qz, double qw, double tx, double ty, double tz)
00472 {
00473 double Rs11 = qw * qw + qx * qx - qy * qy - qz * qz;
00474 double Rs21 = 2.0 * qx * qy + 2.0 * qw * qz;
00475 double Rs31 = 2.0 * qx * qz - 2.0 * qw * qy;
00476
00477 double Rs12 = 2.0 * qx * qy - 2.0 * qw * qz;
00478 double Rs22 = qw * qw - qx * qx + qy * qy - qz * qz;
00479 double Rs32 = 2.0 * qy * qz + 2.0 * qw * qx;
00480
00481 double Rs13 = 2.0 * qx * qz + 2.0 * qw * qy;
00482 double Rs23 = 2.0 * qy * qz - 2.0 * qw * qx;
00483 double Rs33 = qw * qw - qx * qx - qy * qy + qz * qz;
00484
00485 printf("%6.3lf %6.3lf %6.3lf %6.3lf\n", Rs11, Rs12, Rs13, tx);
00486 printf("%6.3lf %6.3lf %6.3lf %6.3lf\n", Rs21, Rs22, Rs23, ty);
00487 printf("%6.3lf %6.3lf %6.3lf %6.3lf\n", Rs31, Rs32, Rs33, tz);
00488 printf("%6.3lf %6.3lf %6.3lf %6.3lf\n", 0.0, 0.0, 0.0, 1.0);
00489 }
00490
00491
00492 void print_AATasH(double x, double y, double z, double tx, double ty, double tz)
00493 {
00494 double R[9];
00495 double aa[3];
00496 aa[0] = x;
00497 aa[1] = y;
00498 aa[2] = z;
00499 ceres::AngleAxisToRotationMatrix(aa, R);
00500 printf("%6.3lf %6.3lf %6.3lf %6.3lf\n", R[0], R[3], R[6], tx);
00501 printf("%6.3lf %6.3lf %6.3lf %6.3lf\n", R[1], R[4], R[7], ty);
00502 printf("%6.3lf %6.3lf %6.3lf %6.3lf\n", R[2], R[5], R[8], tz);
00503 printf("%6.3lf %6.3lf %6.3lf %6.3lf\n", 0.0, 0.0, 0.0, 1.0);
00504 }
00505
00506
00507 void print_AATasHI(double x, double y, double z, double tx, double ty, double tz)
00508 {
00509 double R[9];
00510 double aa[3];
00511 aa[0] = x;
00512 aa[1] = y;
00513 aa[2] = z;
00514 ceres::AngleAxisToRotationMatrix(aa, R);
00515 double ix = -(tx * R[0] + ty * R[1] + tz * R[2]);
00516 double iy = -(tx * R[3] + ty * R[4] + tz * R[5]);
00517 double iz = -(tx * R[6] + ty * R[7] + tz * R[8]);
00518 printf("%6.3lf %6.3lf %6.3lf %6.3lf\n", R[0], R[1], R[2], ix);
00519 printf("%6.3lf %6.3lf %6.3lf %6.3lf\n", R[3], R[4], R[5], iy);
00520 printf("%6.3lf %6.3lf %6.3lf %6.3lf\n", R[6], R[7], R[8], iz);
00521 printf("%6.3lf %6.3lf %6.3lf %6.3lf\n", 0.0, 0.0, 0.0, 1.0);
00522 }
00523
00524 void print_AAasEuler(double x, double y, double z)
00525 {
00526 double R[9];
00527 double aa[3];
00528 aa[0] = x;
00529 aa[1] = y;
00530 aa[2] = z;
00531 ceres::AngleAxisToRotationMatrix(aa, R);
00532 double rx = atan2(R[7], R[8]);
00533 double ry = atan2(-R[6], sqrt(R[7] * R[7] + R[8] * R[8]));
00534 double rz = atan2(R[3], R[0]);
00535 printf("rpy = %8.4f %8.4f %8.4f\n", rx, ry, rz);
00536 }
00537 void print_camera(Camera C, std::string words)
00538 {
00539 printf("%s\n", words.c_str());
00540 printf("Camera to World Transform:\n");
00541 print_AATasHI(C.aa[0], C.aa[1], C.aa[2], C.pos[0], C.pos[1], C.pos[2]);
00542
00543 printf("World to Camera\n");
00544 print_AATasH(C.aa[0], C.aa[1], C.aa[2], C.pos[0], C.pos[1], C.pos[2]);
00545 print_AAasEuler(C.aa[0], C.aa[1], C.aa[2]);
00546 printf("fx = %8.3lf fy = %8.3lf\n", C.fx, C.fy);
00547 printf("k1 = %8.3lf k2 = %8.3lf k3 = %8.3lf\n", C.k1, C.k2, C.k3);
00548 printf("p1 = %8.3lf p2 = %8.3lf\n", C.p1, C.p2);
00549 printf("cx = %8.3lf cy = %8.3lf\n", C.cx, C.cy);
00550 }