00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "SfM.h"
00025
00026 namespace alvar {
00027
00028 class CameraMoves
00029 {
00030 bool is_initialized;
00031 double prev[3];
00032
00033 public:
00034
00035 CameraMoves()
00036 {
00037 is_initialized = false;
00038 memset(prev, 0, 3*sizeof(double));
00039 }
00040
00041 bool UpdateDistance(Pose* pose, double limit=10)
00042 {
00043 double trad[3]; CvMat tra = cvMat(3, 1, CV_64F, trad);
00044 Pose p = *pose;
00045 p.Invert();
00046 p.GetTranslation(&tra);
00047 if(is_initialized == false)
00048 {
00049 memcpy(prev, trad, 3*sizeof(double));
00050 is_initialized = true;
00051 return false;
00052 }
00053 double dist = (prev[0]-trad[0])*(prev[0]-trad[0]) +
00054 (prev[1]-trad[1])*(prev[1]-trad[1]) +
00055 (prev[2]-trad[2])*(prev[2]-trad[2]);
00056 if(dist > limit)
00057 {
00058 memcpy(prev, trad, 3*sizeof(double));
00059 return true;
00060 }
00061 return false;
00062 }
00063 };
00064 CameraMoves moving;
00065
00066 void SimpleSfM::Reset(bool reset_also_triangulated) {
00067 pose_ok = false;
00068 container = container_reset_point;
00069 if (reset_also_triangulated) {
00070 container_triangulated = container_triangulated_reset_point;
00071 }
00072 pose_difference.Reset();
00073 pose_difference.Mirror(false, true, true);
00074 }
00075
00076 void SimpleSfM::SetResetPoint() {
00077 container_reset_point = container;
00078 container_triangulated_reset_point = container_triangulated;
00079 }
00080
00081 void SimpleSfM::Clear() {
00082 container.clear();
00083 }
00084
00085 CameraEC *SimpleSfM::GetCamera() { return &cam; }
00086
00087 Pose *SimpleSfM::GetPose() { return &pose; }
00088
00089 bool SimpleSfM::AddMultiMarker(const char *fname, FILE_FORMAT format) {
00090 MultiMarkerEC mm;
00091 return mm.Load(container, fname, format, 0, 0,1023);
00092 }
00093
00094 bool SimpleSfM::AddMultiMarker(MultiMarkerEC *mm) {
00095 return mm->MarkersToEC(container, 0, 0, 1023);
00096 }
00097
00098 void SimpleSfM::AddMarker(int marker_id, double edge_length, Pose &pose) {
00099 marker_detector.MarkerToEC(container, marker_id, edge_length, pose, 0, 0, 1023);
00100 }
00101
00102 float PointVectorFromCamera(CvPoint3D32f p3d, CvPoint3D32f &p3d_vec, Pose *camera_pose) {
00103 double pd[16], v[4] = {0,0,0,1};
00104 CvMat Pi = cvMat(4, 4, CV_64F, pd);
00105 CvMat V = cvMat(4, 1, CV_64F, v);
00106
00107
00108 camera_pose->GetMatrix(&Pi);
00109 cvInv(&Pi, &Pi);
00110 cvMatMul(&Pi, &V, &V);
00111 v[0] /= v[3];
00112 v[1] /= v[3];
00113 v[2] /= v[3];
00114
00115
00116 p3d_vec.x = float(p3d.x - v[0]);
00117 p3d_vec.y = float(p3d.y - v[1]);
00118 p3d_vec.z = float(p3d.z - v[2]);
00119
00120 return std::sqrt(p3d_vec.x*p3d_vec.x + p3d_vec.y*p3d_vec.y + p3d_vec.z*p3d_vec.z);
00121 }
00122
00123 void CreateShadowPoint(CvPoint3D32f &p3d_sh, CvPoint3D32f p3d, CameraEC *cam, Pose *camera_pose, float parallax_length, float triangulate_angle) {
00124
00125 float l = PointVectorFromCamera(p3d, p3d_sh, camera_pose);
00126
00127
00128 CvPoint2D32f p2d;
00129 CvPoint3D32f p3d2;
00130 cam->ProjectPoint(p3d, camera_pose, p2d);
00131 p2d.x += parallax_length;
00132 cam->Get3dOnDepth(camera_pose, p2d, l, p3d2);
00133 p3d2.x -= p3d.x;
00134 p3d2.y -= p3d.y;
00135 p3d2.z -= p3d.z;
00136 float pl = std::sqrt(p3d2.x*p3d2.x + p3d2.y*p3d2.y + p3d2.z*p3d2.z);
00137 float shadow_point_dist = float(pl / std::abs(tan(triangulate_angle*3.1415926535/180.)));
00138
00139
00140 p3d_sh.x /= l;
00141 p3d_sh.y /= l;
00142 p3d_sh.z /= l;
00143 p3d_sh.x *= shadow_point_dist;
00144 p3d_sh.y *= shadow_point_dist;
00145 p3d_sh.z *= shadow_point_dist;
00146 p3d_sh.x += p3d.x;
00147 p3d_sh.y += p3d.y;
00148 p3d_sh.z += p3d.z;
00149
00150
00151
00152 }
00153
00154 bool SimpleSfM::Update(IplImage *image, bool assume_plane, bool triangulate, float reproj_err_limit, float triangulate_angle) {
00155 const int min_triangulate=50, max_triangulate=150;
00156 const float plane_dist_limit = 100.f;
00157 const bool remember_3d_points = true;
00158 const float parallax_length = 10.f;
00159 const float parallax_length_sq = parallax_length*parallax_length;
00160 float reproj_err_limit_sq = reproj_err_limit*reproj_err_limit;
00161 std::map<int, Feature>::iterator iter;
00162 std::map<int, Feature>::iterator iter_end = container.end();
00163
00164
00165 marker_detector.Detect(image, &cam, container, 0, 0, 1023, true, false);
00166 tf.Purge();
00167 tf.Track(image, 0, container, 1);
00168
00169 tf.EraseNonTracked(container, 1);
00170
00171
00172 if (!pose_ok) pose_ok = cam.CalcExteriorOrientation(container, &pose);
00173 pose_ok = cam.UpdatePose(container, &pose);
00174 if (!pose_ok) pose_ok = cam.UpdatePose(container, &pose, 0);
00175 if (!pose_ok) return false;
00176
00177
00178 double err_markers = cam.Reproject(container, &pose, 0, true, false, 100);
00179 if (err_markers > reproj_err_limit*2) { Reset(false); return false;}
00180 double err_features = cam.Reproject(container, &pose, 1, false, false, 100);
00181 if ((err_markers == 0) && (err_features > reproj_err_limit*2)) {
00182
00183
00184 return true;
00185 }
00186
00187
00188 if (remember_3d_points) {
00189 IplImage *mask = tf.NewFeatureMask();
00190 iter = container_triangulated.begin();
00191 while(iter != container_triangulated.end()) {
00192 if (container.find(iter->first) == container.end()) {
00193 Camera *c = &cam;
00194 c->ProjectPoint(iter->second.p3d, &pose, iter->second.projected_p2d);
00195 if ((iter->second.projected_p2d.x >= 0) &&
00196 (iter->second.projected_p2d.y >= 0) &&
00197 (iter->second.projected_p2d.x < image->width) &&
00198 (iter->second.projected_p2d.y < image->height))
00199 {
00200 CvScalar s = cvGet2D(mask, int(iter->second.projected_p2d.y), int(iter->second.projected_p2d.x));
00201 if (s.val[0] == 0) {
00202 container[iter->first] = iter->second;
00203 container[iter->first].estimation_type = 3;
00204 container[iter->first].p2d = container[iter->first].projected_p2d;
00205 }
00206 }
00207 }
00208 iter++;
00209 }
00210 }
00211
00212
00213
00214 tf.AddFeatures(container, 1, 1024, 0xffffff);
00215 if (assume_plane) {
00216 for (iter = container.begin(); iter != iter_end; iter++) {
00217 Feature &f = iter->second;
00218
00219 if (!f.has_p3d && f.estimation_type < 1) {
00220
00221
00222
00223
00224
00225 cam.Get3dOnDepth(&pose, f.p2d, plane_dist_limit, f.p3d);
00226
00227
00228
00229
00230
00231 f.p3d_sh = f.p3d;
00232
00233 f.has_p3d = true;
00234 f.estimation_type = 1;
00235 }
00236 }
00237 }
00238
00239
00240 if (triangulate) {
00241 for (iter = container.begin(); iter != iter_end; iter++) {
00242 Feature &f = iter->second;
00243
00244 if (!f.has_p3d && !f.has_stored_pose) {
00245 f.pose1 = pose;
00246 f.p2d1 = f.p2d;
00247 f.has_stored_pose = true;
00248 cam.Get3dOnDepth(&pose, f.p2d, 8, f.p3d);
00249 CreateShadowPoint(f.p3d_sh, f.p3d, &cam, &pose, parallax_length, triangulate_angle);
00250 }
00251 if (!f.has_p3d && f.has_stored_pose && f.estimation_type < 2) {
00252 double dist_sh_sq = (f.projected_p2d_sh.x-f.projected_p2d.x)*(f.projected_p2d_sh.x-f.projected_p2d.x);
00253 dist_sh_sq += (f.projected_p2d_sh.y-f.projected_p2d.y)*(f.projected_p2d_sh.y-f.projected_p2d.y);
00254 if (dist_sh_sq > parallax_length_sq) {
00255 CvPoint2D32f u1 = f.p2d1;
00256 CvPoint2D32f u2 = f.p2d;
00257 cam.Camera::Undistort(u1);
00258 cam.Camera::Undistort(u2);
00259 if(cam.ReconstructFeature(&f.pose1, &pose, &u1, &u2, &f.p3d, 10e-6)) {
00260 CreateShadowPoint(f.p3d_sh, f.p3d, &cam, &pose, parallax_length, triangulate_angle);
00261 f.has_p3d = true;
00262 } else
00263 f.has_stored_pose = false;
00264 f.estimation_type = 2;
00265 }
00266 }
00267 }
00268 }
00269
00270
00271 cam.Reproject(container, &pose, 1, false, false, 100);
00272 iter = container.begin();
00273 while(iter != container.end()) {
00274 bool iter_inc = true;
00275 if (iter->second.type_id > 0) {
00276 Feature &f = iter->second;
00277 if ((f.estimation_type == 0) || !f.has_p2d || !f.has_p3d);
00278 else {
00279
00280 double dist_sq = (f.p2d.x-f.projected_p2d.x)*(f.p2d.x-f.projected_p2d.x);
00281 dist_sq += (f.p2d.y-f.projected_p2d.y)*(f.p2d.y-f.projected_p2d.y);
00282
00283 if (f.estimation_type == 1) {
00284 if (dist_sq > (reproj_err_limit_sq)) f.has_p3d = false;
00285 } else if (f.estimation_type == 2) {
00286 if (dist_sq > (reproj_err_limit_sq)) {
00287 container.erase(iter++);
00288 iter_inc = false;
00289 }
00290 } else if (f.estimation_type == 3) {
00291 if (container_triangulated.size() < min_triangulate) {
00292 if (dist_sq > (reproj_err_limit_sq)) {
00293 container.erase(iter++);
00294 iter_inc = false;
00295 }
00296 } else {
00297 if (dist_sq > (reproj_err_limit_sq)) f.has_p3d = false;
00298 if (dist_sq > (reproj_err_limit_sq*2)) {
00299 std::map<int, Feature>::iterator iter_tmp;
00300 iter_tmp = container_triangulated.find(iter->first);
00301 if (iter_tmp != container_triangulated.end()) {
00302 container_triangulated.erase(iter_tmp);
00303 }
00304 container.erase(iter++);
00305 iter_inc = false;
00306 }
00307 }
00308 }
00309 }
00310 }
00311 if (iter_inc) iter++;
00312 }
00313
00314
00315 if (remember_3d_points && (container_triangulated.size() < max_triangulate)) {
00316 iter = container.begin();
00317 while(iter != container.end()) {
00318 if ((iter->second.type_id > 0) &&
00319 (container_triangulated.find(iter->first) == container_triangulated.end()))
00320 {
00321 Feature &f = iter->second;
00322 double dist_sq = (f.p2d.x-f.projected_p2d.x)*(f.p2d.x-f.projected_p2d.x);
00323 dist_sq += (f.p2d.y-f.projected_p2d.y)*(f.p2d.y-f.projected_p2d.y);
00324 double dist_sh_sq = (f.projected_p2d_sh.x-f.projected_p2d.x)*(f.projected_p2d_sh.x-f.projected_p2d.x);
00325 dist_sh_sq += (f.projected_p2d_sh.y-f.projected_p2d.y)*(f.projected_p2d_sh.y-f.projected_p2d.y);
00326 if ((dist_sq < reproj_err_limit_sq) && (dist_sh_sq > parallax_length_sq)) {
00327 container_triangulated[iter->first] = iter->second;
00328 f.estimation_type = 3;
00329 }
00330 }
00331 iter++;
00332 if (container_triangulated.size() >= max_triangulate) break;
00333 }
00334 }
00335
00336 return true;
00337 }
00338
00339 bool SimpleSfM::UpdateTriangulateOnly(IplImage *image) {
00340 marker_detector.Detect(image, &cam, container, 0, 0, 1023, true, false);
00341 tf.Purge();
00342 tf.Track(image, 0, container, 1, 1024, 65535);
00343 tf.EraseNonTracked(container, 1);
00344 if (!pose_ok) pose_ok = cam.CalcExteriorOrientation(container, &pose);
00345 else pose_ok = cam.UpdatePose(container, &pose);
00346 if(pose_ok) update_tri = moving.UpdateDistance(&pose, scale);
00347 std::map<int,Feature>::iterator iter = container.begin();
00348 std::map<int,Feature>::iterator iter_end = container.end();
00349 for(;iter != iter_end; iter++) {
00350 if (pose_ok && (iter->second.type_id == 1) && (!iter->second.has_stored_pose) && (!iter->second.has_p3d)) {
00351 iter->second.pose1 = pose;
00352 iter->second.p2d1 = iter->second.p2d;
00353 iter->second.has_stored_pose = true;
00354 }
00355 }
00356 iter = container.begin();
00357 for(;iter != iter_end; iter++)
00358 {
00359 Feature &f = iter->second;
00360 if(update_tri && f.has_stored_pose && !f.has_p3d) {
00361 f.tri_cntr++;
00362 }
00363 if(f.tri_cntr==3) {
00364 CvPoint2D32f u1 = f.p2d1;
00365 CvPoint2D32f u2 = f.p2d;
00366 cam.Camera::Undistort(u1);
00367 cam.Camera::Undistort(u2);
00368 if(cam.ReconstructFeature(&f.pose1, &pose, &u1, &u2, &f.p3d, 10e-6))
00369 f.has_p3d = true;
00370 else
00371 f.has_stored_pose = false;
00372 f.tri_cntr = 0;
00373 }
00374 }
00375 if (pose_ok) {
00376 double err_markers = cam.Reproject(container, &pose, 0, true, false, 100);
00377 if(err_markers > 30) { Reset(false); return false;}
00378 double err_features = cam.Reproject(container, &pose, 1, false, false, 100);
00379 cam.EraseUsingReprojectionError(container, 30, 1);
00380 }
00381 return pose_ok;
00382 }
00383
00384 bool SimpleSfM::UpdateRotationsOnly(IplImage *image) {
00385 int n_markers = marker_detector.Detect(image, &cam, container, 0, 0, 1023, true, false);
00386 static int n_markers_prev = 0;
00387 tf.Purge();
00388 tf.Track(image, 0, container, 1, 1024, 65535);
00389 tf.EraseNonTracked(container, 1);
00390 int type_id = -1;
00391 if(n_markers>=1) type_id = 0;
00392 if (n_markers==1)
00393 {
00394 pose_ok = cam.CalcExteriorOrientation(container, &pose, 0);
00395 if(pose_ok) pose_original = pose;
00396 }
00397 else if(n_markers>1)
00398 {
00399 if(pose_ok)
00400 pose_ok = cam.UpdatePose(container, &pose, 0);
00401 else
00402 pose_ok = cam.CalcExteriorOrientation(container, &pose, 0);
00403 if(pose_ok) pose_original = pose;
00404 }
00405 else
00406 {
00407 if (n_markers_prev > 0) {
00408 pose_difference.Reset();
00409 pose_difference.Mirror(false, true, true);
00410 std::map<int,Feature>::iterator iter = container.begin();
00411 std::map<int,Feature>::iterator iter_end = container.end();
00412 for(;iter != iter_end; iter++) {
00413 if ((iter->second.type_id == 1) && (iter->second.has_p2d)) {
00414 CvPoint2D32f _p2d = iter->second.p2d;
00415 cam.Get3dOnDepth(&pose_difference, _p2d, 1, iter->second.p3d);
00416 iter->second.has_p3d = true;
00417 }
00418 }
00419 }
00420 cam.UpdateRotation(container, &pose_difference, 1);
00421 if(pose_ok)
00422 {
00423 double rot_mat[16];
00424 double gl_mat[16];
00425 pose_difference.GetMatrixGL(rot_mat);
00426 pose_original.GetMatrixGL(gl_mat);
00427 CvMat rot = cvMat(4, 4, CV_64F, rot_mat);
00428 CvMat mod = cvMat(4, 4, CV_64F, gl_mat);
00429 cvMatMul(&mod, &rot, &rot);
00430 pose.SetMatrixGL(rot_mat);
00431 }
00432
00433 }
00434 n_markers_prev = n_markers;
00435 if (pose_ok) {
00436 if (n_markers < 1) {
00437 std::map<int,Feature>::iterator iter = container.begin();
00438 std::map<int,Feature>::iterator iter_end = container.end();
00439 for(;iter != iter_end; iter++) {
00440 if ((iter->second.type_id == 1) && (!iter->second.has_p3d) && (iter->second.has_p2d)) {
00441 CvPoint2D32f _p2d = iter->second.p2d;
00442 cam.Get3dOnDepth(&pose_difference, _p2d, 1, iter->second.p3d);
00443 iter->second.has_p3d = true;
00444 }
00445 }
00446 }
00447
00448 double err_markers = cam.Reproject(container, &pose, 0, true, false, 100);
00449 if(err_markers > 10) { Reset(false); return false;}
00450 double err_features = cam.Reproject(container, &pose_difference, 1, false, false, 100);
00451 cam.EraseUsingReprojectionError(container, 10, 1);
00452 }
00453 return pose_ok;
00454 }
00455
00456 void SimpleSfM::Draw(IplImage *rgba) {
00457 if(markers_found) return;
00458 std::map<int,Feature>::iterator iter = container.begin();
00459 std::map<int,Feature>::iterator iter_end = container.end();
00460 for(;iter != iter_end;iter++) {
00461 Feature &f = iter->second;
00462 if (f.has_p2d) {
00463 int r=0, g=0, b=0, rad=1;
00464 if (f.type_id == 0) {r=255; g=0; b=0;}
00465 else if (f.estimation_type == 0) {
00466 if (f.has_stored_pose) {r=255; g=0; b=255;}
00467 else {r=0; g=255; b=255;}
00468 }
00469 else if (f.estimation_type == 1) {r=0; g=255; b=0;}
00470 else if (f.estimation_type == 2) {r=255; g=0; b=255;}
00471 else if (f.estimation_type == 3) {r=0; g=0; b=255;}
00472 if (f.has_p3d) rad=5;
00473 else rad = f.tri_cntr+1;
00474
00475 cvCircle(rgba, cvPointFrom32f(f.p2d), rad, CV_RGB(r,g,b));
00476 if (pose_ok) {
00477
00478 if (f.type_id > 0 && f.estimation_type < 3 && f.p3d_sh.x != 0.f) {
00479 cvLine(rgba, cvPointFrom32f(f.projected_p2d), cvPointFrom32f(f.projected_p2d_sh), CV_RGB(0,255,0));
00480 }
00481
00482 if (f.has_p3d) {
00483 cvLine(rgba, cvPointFrom32f(f.p2d), cvPointFrom32f(f.projected_p2d), CV_RGB(255,0,255));
00484 }
00485 }
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502 }
00503 }
00504 }
00505
00506 }
00507