00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <iostream>
00021 #include <algorithm>
00022 #include "vobj_tracker.h"
00023 #include "homography4.h"
00024 #include "timer.h"
00025
00026 #ifdef min
00027 #undef min
00028 #endif
00029
00030 static vobj_keypoint::vobj_keypoint_factory_t default_vobj_keypoint_factory;
00031 static vobj_frame::vobj_frame_factory_t default_vobj_frame_factory;
00032
00033 vobj_tracker::vobj_tracker(int width, int height, int levels, int max_motion,
00034 visual_database *vdb, bool glContext,
00035 pyr_keypoint::pyr_keypoint_factory_t *kf,
00036 vobj_frame::vobj_frame_factory_t *ff,
00037 pyr_track::pyr_track_factory_t *tf )
00038 : kpt_tracker(width, height, levels, max_motion, glContext,
00039 (kf?kf:&default_vobj_keypoint_factory),
00040 (ff?ff:&default_vobj_frame_factory),
00041 tf),
00042
00043 vdb(vdb)
00044 {
00045 score_threshold=.00;
00046 homography_corresp_threshold = 15;
00047 fmat_corresp_threshold = 20;
00048 max_results=3;
00049 use_incremental_learning=true;
00050 }
00051
00052 pyr_frame *vobj_tracker::process_frame(IplImage *im)
00053 {
00054 vobj_frame *frame = static_cast<vobj_frame *>(kpt_tracker::process_frame(im));
00055 vobj_frame *last_frame = static_cast<vobj_frame *>(get_nth_frame(1));
00056 track_objects(frame, last_frame);
00057 if (use_incremental_learning)
00058 incremental_learning(frame, 5, 30, 3000);
00059 return frame;
00060 }
00061
00062 pyr_frame *vobj_tracker::process_frame_pipeline(IplImage *im)
00063 {
00064 pyr_frame *new_f=0;
00065 if (im) new_f = create_frame(im);
00066 #pragma omp parallel
00067 {
00068 #pragma omp master
00069 {
00070 if (im) {
00071
00072 new_f->pyr->build();
00073
00074
00075 detect_keypoints(new_f);
00076
00077 }
00078 }
00079 #pragma omp single
00080 {
00081 if (pipeline_stage1) {
00082 traverse_tree(pipeline_stage1);
00083 pipeline_stage1->append_to(*this);
00084 vobj_frame *last_frame = static_cast<vobj_frame *>(get_nth_frame(1));
00085 track_ncclk(pipeline_stage1, last_frame);
00086 track_objects(static_cast<vobj_frame *>(pipeline_stage1), last_frame);
00087 if (use_incremental_learning)
00088 incremental_learning(static_cast<vobj_frame *>(pipeline_stage1), 5, 30, 3000);
00089 }
00090 }
00091 }
00092 pyr_frame *out = pipeline_stage1;
00093 pipeline_stage1 = new_f;
00094 return out;
00095 }
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 int vobj_tracker::track_objects(vobj_frame *frame, vobj_frame *last_frame)
00106 {
00107
00108 TaskTimer::pushTask("track_objects");
00109
00110 TaskTimer::pushTask("find_candidates");
00111 std::set<visual_object *> candidates;
00112 find_candidates(frame, candidates, last_frame);
00113 TaskTimer::popTask();
00114
00115 TaskTimer::pushTask("verify");
00116 for (std::set<visual_object *>::iterator it(candidates.begin()); it!= candidates.end(); ++it)
00117 {
00118 vobj_instance instance;
00119 if (verify(frame, *it, &instance)) {
00120
00121 frame->visible_objects.push_back(instance);
00122 }
00123 }
00124 TaskTimer::popTask();
00125
00126 TaskTimer::popTask();
00127 return frame->visible_objects.size();
00128 }
00129
00130 void vobj_tracker::find_candidates(vobj_frame *frame, std::set<visual_object *> &candidates, vobj_frame *last_frame)
00131 {
00132 candidates.clear();
00133 if (frame==0) return;
00134
00135 if (last_frame)
00136 for (vobj_instance_vector::const_iterator it(last_frame->visible_objects.begin()); it!=last_frame->visible_objects.end(); ++it)
00137 {
00138 assert(it->object != 0);
00139 candidates.insert(it->object);
00140 }
00141
00142
00143 if (query.get() == 0) {
00144 query.reset(vdb->create_incremental_query());
00145 init_query_with_frame(*query, frame);
00146 } else {
00147
00148 update_query_with_frame(*query, this);
00149 }
00150
00151 for (incremental_query::iterator it(query->sort_results(max_results+candidates.size())); it != query->end() && it->score > score_threshold; ++it)
00152 {
00153 candidates.insert(static_cast<visual_object *>(it->c));
00154 }
00155
00156
00157 }
00158
00159 int get_correspondences(vobj_frame *frame, visual_object *obj, visual_object::correspondence_vector &corresp)
00160 {
00161 corresp.clear();
00162 corresp.reserve(frame->points.size()*4);
00163
00164 double score=0;
00165 double max_score=0;
00166
00167 int npts=0;
00168
00169 int nb_tracked=0;
00170
00171
00172
00173
00174 for (id_cluster::uumap::iterator i(obj->histo.begin()); i!=obj->histo.end(); ++i) {
00175 max_score += obj->vdb->idf(i->first);
00176 }
00177
00178 std::set<unsigned> matched_cids;
00179
00180 for (tracks::keypoint_frame_iterator it(frame->points.begin()); !it.end(); ++it) {
00181 vobj_keypoint *k = (vobj_keypoint *) it.elem();
00182
00183 vobj_keypoint *prev = k->prev_match_vobj();
00184 if (prev && prev->vobj && prev->obj_kpt)
00185 {
00186 if (prev->vobj == obj) {
00187
00188 corresp.push_back(visual_object::correspondence(prev->obj_kpt, k, 100));
00189 nb_tracked++;
00190 }
00191 continue;
00192 }
00193
00194 if (k->vobj) continue;
00195
00196
00197 if (!k->track_is_longer(2)) continue;
00198
00199 visual_database *vdb = obj->vdb;
00200
00201 if (((pyr_frame *)k->frame)->tracker->id_clusters==0) {
00202
00203 visual_object::db_keypoint_vector::iterator begin, end;
00204 obj->find(k->id,begin,end);
00205 for (visual_object::db_keypoint_vector::iterator i(begin); i!=end; i++) {
00206 corresp.push_back(visual_object::correspondence(const_cast<db_keypoint*>(&(*i)), k, .1));
00207 if (matched_cids.insert(k->id).second) {
00208 id_cluster_collection::id2cluster_map::iterator id_it = vdb->id2cluster.find(k->id);
00209 if (id_it != vdb->id2cluster.end())
00210 score += vdb->idf(id_it);
00211 }
00212 }
00213 } else {
00214
00215
00216 pyr_track *track = (pyr_track *) k->track;
00217 if (track ==0 || k->cid==0) continue;
00218
00219 npts++;
00220
00221 bool added=false;
00222 track->id_histo.sort_results_min_ratio(.7);
00223 for(incremental_query::iterator it(track->id_histo.begin()); it!=track->id_histo.end(); ++it)
00224 {
00225 int cid = it->c->id;
00226 visual_object::db_keypoint_vector::iterator begin, end;
00227 obj->find(cid,begin,end);
00228
00229 if (begin == end) continue;
00230
00231 float idf=1;
00232 id_cluster_collection::id2cluster_map::iterator id_it = vdb->id2cluster.find(cid);
00233 if (id_it != vdb->id2cluster.end())
00234 idf = vdb->idf(id_it);
00235
00236 float s = it->score * idf;
00237 for (visual_object::db_keypoint_vector::iterator i(begin); i!=end; i++)
00238 {
00239 corresp.push_back(visual_object::correspondence(const_cast<db_keypoint *>(&(*i)), k, s));
00240 if (!added) {
00241 added=true;
00242 if (matched_cids.insert(cid).second)
00243 score += idf;
00244 }
00245 }
00246 }
00247 }
00248 }
00249 return nb_tracked;
00250 }
00251
00252 static point2d transform(CvMat *H, point2d &a)
00253 {
00254 float *h = H->data.fl;
00255 float m[3];
00256 for (int i=0; i<3; i++)
00257 m[i] = h[i*3]*a.u + h[i*3+1]*a.v + h[i*3+2];
00258 return point2d(m[0]/m[2], m[1]/m[2]);
00259 }
00260
00261 static bool check_epipolar_constraint(const point2d &a, const CvMat *M, const point2d &b, float threshold=3.0f)
00262 {
00263 float *h = M->data.fl;
00264 float m[3];
00265 for (int i=0; i<3; i++)
00266 m[i] = h[i*3]*b.u + h[i*3+1]*b.v + h[i*3+2];
00267
00268 float d = m[0]*a.u + m[1]*a.v + m[2];
00269
00270 return fabsf(d) < threshold;
00271 }
00272
00273 bool vobj_tracker::verify(vobj_frame *frame, visual_object *obj, vobj_instance *instance)
00274 {
00275
00276 instance->object=0;
00277 if ((obj->get_flags() & (visual_object::VERIFY_HOMOGRAPHY | visual_object::VERIFY_FMAT)) == 0) return false;
00278
00279 TaskTimer::pushTask("get_correspondences");
00280 visual_object::correspondence_vector corresp;
00281 int nb_tracked=get_correspondences(frame, obj, corresp);
00282 TaskTimer::popTask();
00283
00284 int n_corresp = corresp.size();
00285
00286 if (nb_tracked >= 10) n_corresp = std::min((int)(1.2*nb_tracked), n_corresp);
00287
00288 if (n_corresp < 10) return 0;
00289
00290 CvMat *frame_pts = cvCreateMat(corresp.size(), 2, CV_32FC1);
00291 CvMat *obj_pts = cvCreateMat(corresp.size(), 2, CV_32FC1);
00292 CvMat *mask = cvCreateMat(1, corresp.size(), CV_8UC1);
00293
00294 float *f = frame_pts->data.fl + nb_tracked*2;
00295 float *o = obj_pts->data.fl + nb_tracked*2;
00296 float *f_t = frame_pts->data.fl;
00297 float *o_t = obj_pts->data.fl;
00298
00299 for (visual_object::correspondence_vector::iterator it(corresp.begin()); it!=corresp.end(); ++it) {
00300 if (it->correl >=100 ) {
00301
00302 *f_t++ = it->frame_kpt->u;
00303 *f_t++ = it->frame_kpt->v;
00304
00305 *o_t++ = it->obj_kpt->u;
00306 *o_t++ = it->obj_kpt->v;
00307
00308 } else {
00309
00310 *f++ = it->frame_kpt->u;
00311 *f++ = it->frame_kpt->v;
00312
00313 *o++ = it->obj_kpt->u;
00314 *o++ = it->obj_kpt->v;
00315
00316 }
00317 }
00318 obj_pts->rows = frame_pts->rows = mask->cols = n_corresp;
00319
00320
00321
00322 CvMat tmat = instance->get_transform();
00323 CvMat *M = &tmat;
00324
00325 int r = 0;
00326 int support = -1;
00327 TaskTimer::pushTask("FindHomography");
00328 if (nb_tracked>=10) TaskTimer::pushTask("Track");
00329 else TaskTimer::pushTask("Detect");
00330 if (obj->get_flags() & visual_object::VERIFY_HOMOGRAPHY) {
00331 if (nb_tracked <10) {
00332 if (0)
00333 r = cvFindHomography(obj_pts, frame_pts, M, CV_RANSAC, 6, mask);
00334 else {
00335 support = ransac_h4(
00336 obj_pts->data.fl, obj_pts->step,
00337 frame_pts->data.fl, frame_pts->step,
00338 obj_pts->rows,
00339 1000,
00340 6,
00341 50,
00342 instance->transform,
00343 0,
00344 obj_pts->data.fl,frame_pts->data.fl);
00345
00346 if (support >= homography_corresp_threshold) {
00347
00348 obj_pts->rows = support;
00349 frame_pts->rows = support;
00350 r = cvFindHomography(obj_pts, frame_pts, M, CV_LMEDS);
00351 } else {
00352 r=0;
00353 }
00354 }
00355 } else {
00356 if (0) {
00357 r = cvFindHomography(obj_pts, frame_pts, M, CV_LMEDS, 6, mask);
00358 } else {
00359 support = ransac_h4(
00360 obj_pts->data.fl, obj_pts->step,
00361 frame_pts->data.fl, frame_pts->step,
00362 obj_pts->rows,
00363 100,
00364 3.5,
00365 100,
00366 instance->transform,
00367 0,
00368 obj_pts->data.fl,frame_pts->data.fl);
00369
00370 obj_pts->rows = support;
00371 frame_pts->rows = support;
00372
00373 r = cvFindHomography(obj_pts, frame_pts, M);
00374 }
00375 }
00376 } else {
00377 r = cvFindFundamentalMat(obj_pts, frame_pts, M, (nb_tracked>=16 ? CV_FM_LMEDS : CV_FM_RANSAC), 4, .99, mask);
00378 }
00379 TaskTimer::popTask();
00380 TaskTimer::popTask();
00381
00382 if (r!=1) {
00383 cvReleaseMat(&mask);
00384 cvReleaseMat(&frame_pts);
00385 cvReleaseMat(&obj_pts);
00386 corresp.clear();
00387 return false;
00388 }
00389
00390 int inliers=0;
00391 int inlier_threshold;
00392 if (obj->get_flags() & visual_object::VERIFY_HOMOGRAPHY) {
00393
00394 inlier_threshold = homography_corresp_threshold;
00395
00396 for (unsigned i=0; i<corresp.size(); ++i) {
00397 vobj_keypoint *k = static_cast<vobj_keypoint *>(corresp[i].frame_kpt);
00398 point2d p = transform(M, *corresp[i].obj_kpt);
00399 float dist = p.dist(*k);
00400 if (dist<6) {
00401 inliers++;
00402 } else {
00403 corresp[i].frame_kpt = 0;
00404 vobj_keypoint *prev = k->prev_match_vobj();
00405 if (prev && prev->vobj==obj) {
00406 if (0)
00407 std::cout << " Point at " << k->u << "," << k->v
00408 << " was lost. Reproj error: " << dist << std::endl;
00409 }
00410 }
00411 }
00412 } else if (obj->get_flags() & visual_object::VERIFY_FMAT) {
00413
00414 inlier_threshold = fmat_corresp_threshold;
00415 std::cout << "F-Mat checking.\n";
00416 for (unsigned i=0; i<corresp.size(); ++i) {
00417 vobj_keypoint *k = static_cast<vobj_keypoint *>(corresp[i].frame_kpt);
00418 if (check_epipolar_constraint(*corresp[i].obj_kpt, M, *k)) {
00419 inliers++;
00420 } else {
00421 corresp[i].frame_kpt=0;
00422 }
00423 }
00424 }
00425
00426
00427
00428 if (0)
00429 std::cout << " Checking object, " << inliers << " correct matches out of "
00430 << corresp.size() << "( used: " << n_corresp << " tracked: " << nb_tracked << ")\n";
00431
00432 bool success = (inliers>=inlier_threshold);
00433 if (success) instance->object = obj;
00434 instance->support = inliers;
00435
00436
00437 if (success)
00438 for (unsigned i=0; i<corresp.size(); ++i) {
00439 if (corresp[i].frame_kpt) {
00440 vobj_keypoint *k = static_cast<vobj_keypoint *>(corresp[i].frame_kpt);
00441 k->vobj = obj;
00442 k->obj_kpt = corresp[i].obj_kpt;
00443 }
00444 }
00445
00446 if (success)
00447 std::cout << "Matched " << inliers << " features, out of " << obj->nb_points() << " (" << 100.0f*inliers/obj->nb_points()
00448 << "%)\n";
00449
00450 cvReleaseMat(&mask);
00451 cvReleaseMat(&frame_pts);
00452 cvReleaseMat(&obj_pts);
00453 return success;
00454 }
00455
00456
00457 void vobj_tracker::remove_visible_objects_from_db(vobj_frame *frame)
00458 {
00459 if (frame->visible_objects.size()==0) return;
00460
00461 for (vobj_instance_vector::iterator it(frame->visible_objects.begin());
00462 it != frame->visible_objects.end(); ++it)
00463 {
00464 vdb->remove_object(it->object);
00465
00466
00467
00468 delete it->object;
00469 }
00470
00471 for (tracks::keypoint_frame_iterator it(frame->points.begin()); !it.end(); ++it) {
00472 vobj_keypoint *k = (vobj_keypoint *) it.elem();
00473 k->vobj=0;
00474 k->obj_kpt=0;
00475 }
00476 frame->visible_objects.clear();
00477 }
00478
00479 vobj_keypoint *vobj_frame::find_closest_match(float u, float v, float radius)
00480 {
00481 float best_dist = radius*radius;
00482 vobj_keypoint *best_match=0;
00483
00484 for (tracks::keypoint_frame_iterator it=points.search(u, v, radius); !it.end(); ++it) {
00485 vobj_keypoint *p = (vobj_keypoint *) it.elem();
00486 if (p->vobj) {
00487 float du = u-p->u;
00488 float dv = v-p->v;
00489 float d2 = du*du+dv*dv;
00490
00491 if (d2<best_dist) {
00492 best_dist = d2;
00493 best_match = p;
00494 }
00495 }
00496 }
00497 return best_match;
00498 }
00499
00500 vobj_instance *vobj_frame::find_instance(visual_object *obj)
00501 {
00502 for (vobj_instance_vector::iterator it=visible_objects.begin(); it!=visible_objects.end(); ++it)
00503 if (it->object == obj) return &(*it);
00504 return 0;
00505 }
00506
00507 static point2d back_project(const point2d &p, const float H[3][3])
00508 {
00509 float su = p.u;
00510 float sv = p.v;
00511
00512 float t4 = H[0][0]*H[1][1];
00513 float t6 = H[0][0]*H[1][2];
00514 float t8 = H[0][1]*H[1][0];
00515 float t10 = H[0][2]*H[1][0];
00516 float t12 = H[0][1]*H[2][0];
00517 float t14 = H[0][2]*H[2][0];
00518 float t17 = 1/(t4*H[2][2]-t6*H[2][1]-t8*H[2][2]+t10*H[2][1]+t12*H[1][2]-t14*H[1][1]);
00519 float r[3];
00520 r[0] = (H[1][1]*H[2][2]-H[1][2]*H[2][1])*t17*su-(H[0][1]*H[2][2]-H[0][2]*
00521 H[2][1])*t17*sv+(H[0][1]*H[1][2]-H[0][2]*H[1][1])*t17;
00522 r[1] = -(H[1][0]*H[2][2]-H[1][2]*H[2][0])*t17*su+(H[0][0]*H[2][2]-t14)*
00523 t17*sv-(t6-t10)*t17;
00524 r[2] = (H[1][0]*H[2][1]-H[1][1]*H[2][0])*t17*su-(H[0][0]*H[2][1]-t12)*t17
00525 *sv+(t4-t8)*t17;
00526
00527 return point2d(r[0]/r[2], r[1]/r[2]);
00528 }
00529
00530 static point2d homo_transform(const float h[3][3], const point2d &p)
00531 {
00532 float a = h[0][0]*p.u + h[0][1]*p.v + h[0][2];
00533 float b = h[1][0]*p.u + h[1][1]*p.v + h[1][2];
00534 float c = h[2][0]*p.u + h[2][1]*p.v + h[2][2];
00535 return point2d(a/c, b/c);
00536 }
00537
00538 void vobj_tracker::incremental_learning(vobj_frame *frame, int track_length, float radius, int max_pts)
00539 {
00540 if (frame->visible_objects.size()==0)
00541 return;
00542
00543 vdb->start_update();
00544
00545 for (tracks::keypoint_frame_iterator it(frame->points.begin()); !it.end(); ++it) {
00546 vobj_keypoint *k = (vobj_keypoint *) it.elem();
00547
00548
00549 if (k->vobj || k->obj_kpt || k->cid==0 || k->track_length() < track_length) {
00550
00551 continue;
00552 }
00553
00554
00555 vobj_keypoint *closest_match = frame->find_closest_match(k->u, k->v, radius);
00556 if (!closest_match) {
00557
00558 continue;
00559 }
00560 visual_object *obj = closest_match->vobj;
00561
00562
00563 if (!obj || (obj->get_flags() & visual_object::VERIFY_HOMOGRAPHY)==0) {
00564
00565 continue;
00566 }
00567
00568
00569 float filled_percent = obj->nb_points()/(float)max_pts;
00570 if ( filled_percent > ((float)rand()/(float)RAND_MAX)) continue;
00571
00572 vobj_instance *base_instance = frame->find_instance(obj);
00573
00574 point2d backproj = back_project(*k, base_instance->transform);
00575
00576 bool ok=true;
00577
00578 tracks::keypoint_match_iterator t_it(k);
00579 for (--t_it; !t_it.end(); --t_it) {
00580 vobj_keypoint *t_k = (vobj_keypoint *) t_it.elem();
00581 vobj_frame *t_f = (vobj_frame *) t_k->frame;
00582
00583
00584 vobj_instance *inst = t_f->find_instance(obj);
00585 if (!inst || homo_transform(inst->transform, backproj).dist(*t_k) > 3) {
00586 ok = false;
00587 break;
00588 }
00589 }
00590
00591 if (ok) {
00592 std::cout << "Adding keypoint at " << k->u <<"," << k->v << " backproj at " << backproj.u << ","<<backproj.v
00593 << ", nbkpt: " << obj->nb_points() << "/" << max_pts << std::endl;
00594
00595 pyr_keypoint pk(*k);
00596 pk.u = backproj.u;
00597 pk.v = backproj.v;
00598 k->obj_kpt = obj->add_keypoint(&pk, obj->representative_image);
00599 if (k->obj_kpt)
00600 k->vobj = obj;
00601 }
00602 }
00603
00604 vdb->finish_update();
00605 }