00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <iostream>
00021 #include <highgui.h>
00022 #include <fstream>
00023 #include "vsview.h"
00024 #include <QInputDialog>
00025 #include <map>
00026 #include <polyora/timer.h>
00027 #include <math.h>
00028
00029
00030
00031 #ifndef M_2PI
00032 #define M_2PI 6.283185307179586476925286766559f
00033 #endif
00034 #ifndef M_PI
00035 #define M_PI 3.141592653589793238462643383279f
00036 #endif
00037
00038 using namespace std;
00039
00040 const int fps_stat_bin_size=20;
00041
00042 void gl_hash_mark(unsigned code, float x, float y, float orient=0, float r = 5);
00043
00044 struct id_pair {
00045 unsigned a, b;
00046 id_pair(unsigned id1, unsigned id2) {
00047 if (id1 < id2) {
00048 a= id1;
00049 b= id2;
00050 } else {
00051 a=id2;
00052 b=id1;
00053 }
00054 }
00055
00056 bool operator< (const id_pair &p)const
00057 {
00058 if (a < p.a) return true;
00059 if (a == p.a) return b < p.b;
00060 return false;
00061 }
00062 };
00063
00064 map<id_pair,unsigned> affinity_matrix;
00065
00066 using namespace std;
00067 VSView::VSView(QWidget *parent, const char *name, VideoSource *vs)
00068 : GLBox(parent, name), vs(vs), database(id_cluster_collection::QUERY_IDF_NORMALIZED),
00069 query(0)
00070 {
00071 descrf=0;
00072 timer=startTimer(0);
00073 filter = false;
00074 record=false;
00075 record_pts=false;
00076 record_movie=false;
00077 viewScores=false;
00078
00079 tree_fn = 0;
00080 clusters_fn = "clusters.bin";
00081 descriptors_fn = "descriptors.dat";
00082 visual_db_fn = "visual.db";
00083
00084 help_window = 0;
00085
00086
00087
00088 entry=0;
00089 nb_missing_frames=0;
00090 auto_index = false;
00091 dark = false;
00092
00093 nbLev = 10;
00094 tracker=0;
00095 frameCnt=0;
00096 frameno=0;
00097 threshold = .06;
00098
00099 selected_kpt = 0;
00100 gt_success = gt_fail = 0;
00101 false_pos = false_neg = 0;
00102 true_neg = 0;
00103
00104 nlost=0;
00105
00106 use_pipeline = false;
00107
00108
00109 view_mode = VIEW_ANNOTATIONS;
00110
00111 im = 0;
00112
00113 int w,h;
00114 if (vs) {
00115 vs->getSize(w,h);
00116
00117 zoom(.5,1);
00118 resize(w/.5,h);
00119
00120 while ((h/(1<<nbLev)) < 16) {
00121 nbLev--;
00122 }
00123 std::cout << "Video source: " << w << "x"<<h<<", working with " << nbLev << " levels.\n";
00124
00125 im = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3);
00126 vs->getFrame(im);
00127 vs->start();
00128 setImage(im);
00129
00130 }
00131 }
00132
00133 VSView::~VSView() {
00134 if (query)
00135 delete query;
00136
00137 if (im) cvReleaseImage(&im);
00138 if (vs) delete vs;
00139 if (descrf) fclose(descrf);
00140 if (help_window) delete help_window;
00141 }
00142
00143 void VSView::timerEvent(QTimerEvent *) {
00144
00145 TaskTimer::pushTask("main loop");
00146
00147 if (im==0) return;
00148 createTracker();
00149
00150 makeCurrent();
00151
00152 float fps=0;
00153 int ms = qtime.elapsed();
00154 if (frameCnt>0 && ms > 500) {
00155 ms = qtime.restart();
00156 fps = 1000.0f*frameCnt / ms;
00157 frameCnt=0;
00158 char str[512];
00159 sprintf(str,"QtPolyora, Julien Pilet, %3.1f fps", fps);
00160 setWindowTitle(str);
00161 }
00162
00163 static int n=0;
00164 if (vs) {
00165 int w,h;
00166 vs->getSize(w,h);
00167 int lastId = vs->getId();
00168 if (lastId == 1) total_time.start();
00169
00170
00171 TaskTimer::pushTask("Fetch frame");
00172 vs->getFrame(im);
00173
00174 if (lastId > vs->getId()) {
00175
00176 summary();
00177 close();
00178 return;
00179 }
00180
00181 frameCnt++;
00182 setImage(im);
00183 IplImage *frame = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1);
00184 cvCvtColor(im,frame,CV_BGR2GRAY);
00185
00186 TaskTimer::popTask();
00187
00188 makeCurrent();
00189 pyr_frame *pframe = 0;
00190
00191 QTime frame_processing;
00192 frame_processing.restart();
00193 float frame_processing_time=0;
00194
00195 TaskTimer::pushTask("Process frame");
00196
00197 if (use_pipeline) {
00198 pframe = tracker->process_frame_pipeline(frame);
00199 if (pframe)
00200 setImage(pframe->pyr->images[0]);
00201 }else
00202 pframe = tracker->process_frame(frame);
00203
00204
00205 if (record_pts) {
00206 save_descriptors(pframe);
00207 } else {
00208
00209
00210
00211 if (pframe) {
00212 TaskTimer::pushTask("Query");
00213 TaskTimer::pushTask("Query update");
00214 if (!query) {
00215 query = database.create_incremental_query();
00216
00217
00218
00219 init_query_with_frame(*query, pframe);
00220 } else {
00221 update_query_with_frame(*query, tracker);
00222 }
00223 TaskTimer::popTask();
00224 TaskTimer::pushTask("Sorting results and fetching correspondences");
00225 float score;
00226 entry = (visual_object *)query->get_best(&score);
00227 if (entry) {
00228 float r =entry->get_correspondences(pframe, corresp);
00229 cout << "Frame #" << vs->getId() << ": score=" << score;
00230 cout << " r= " << r << " retrieved: '" << entry->get_comment() << "', gt: '"
00231 << ground_truth << "'" << endl;
00232 if (r<threshold) entry=0;
00233 }
00234 TaskTimer::popTask();
00235 TaskTimer::popTask();
00236
00237 if (entry) nb_missing_frames=0;
00238 else nb_missing_frames++;
00239
00240 if (use_pipeline)
00241 script_exec(vs->getId()-1);
00242 else
00243 script_exec(vs->getId());
00244
00245 if (auto_index && entry==0 && nb_missing_frames > 10)
00246 add_current_frame_to_db("auto", 0);
00247
00248 if (record) save_tracks();
00249 }
00250
00251 }
00252
00253 tracker->remove_unmatched_tracks(tracker->get_nth_frame(2));
00254 if (!record) {
00255 tracks::frame_iterator it = tracker->get_nth_frame_it(512);
00256 tracker->remove_frame(it);
00257 }
00258
00259 frame_processing_time = frame_processing.elapsed();
00260 update_fps_stat(frame_processing_time, pframe);
00261
00262 if (selected_kpt) {
00263 selected_kpt = (pyr_keypoint *) selected_kpt->matches.next;
00264 if (selected_kpt) cout << "id: "<<selected_kpt->id << " cid: " << selected_kpt->cid << endl;
00265 }
00266
00267 if (0) {
00268 char fn[256];
00269 sprintf(fn,"out/frame%04d.bmp", n++);
00270 cvSaveImage(fn, image);
00271 }
00272
00273 TaskTimer::popTask();
00274
00275 update();
00276
00277 if (record_movie) {
00278 char fn[256];
00279 sprintf(fn,"out/frame%04d.bmp", frameno++);
00280 renderAndSave(fn,0,0);
00281 }
00282
00283 }
00284 TaskTimer::popTask();
00285 }
00286
00287 void VSView::update_fps_stat(float fr_ms, pyr_frame *pframe)
00288 {
00289 if (!pframe) return;
00290
00291 unsigned hbin = pframe->points.size() / fps_stat_bin_size;
00292 fps_stat_map::iterator it(fps_stat.find(hbin));
00293 if (it != fps_stat.end()) {
00294 it->second.first = (it->second.second*it->second.first + fr_ms) / (it->second.second+1);
00295 it->second.second++;
00296 } else {
00297 fps_stat[hbin] = pair<double,unsigned>(fr_ms,1);
00298 }
00299 }
00300
00301
00302
00303 void VSView::saveCurrentFrame(const char *filename)
00304 {
00305 cvSaveImage(filename, image);
00306 }
00307 static const char *help =
00308 "Key mapping:\n"
00309 "--- Database editing ---\n"
00310 "a: add current view without geometric check\n"
00311 "h: add current view with Homography check\n"
00312 "f: add current view with F-Mat check\n"
00313 "backspace - delete visible object(s) from DB\n"
00314 "+/-: increase/decrease detection threshold\n"
00315 "\n--- Video/Processing control ---\n"
00316 "tab - pause/resume video input\n"
00317 "space - pause/resume processing\n"
00318 "\n--- Display ---\n"
00319 "1: Normal display\n"
00320 "2: Keypoint display\n"
00321 "3: Track display\n"
00322 "4: Show annotations\n"
00323 "d: toggles image darkening for better constrast\n"
00324 "l/L: increase/decrease displayed pyramid level\n"
00325 "\n--- Keypoint selection ---\n"
00326 "click - select a point\n"
00327 "esc - unselect point\n"
00328 "\n--- Miscellaneous ---\n"
00329 "s: save a screen shot as 'shot0000.png'\n"
00330 "r: toggle track recording\n"
00331 "p: toggle descriptor recording\n"
00332 "q: quit the program\n"
00333 "z: reset view\n";
00334
00335 void VSView::show_help()
00336 {
00337 if (help_window==0) {
00338 QMessageBox *box = new QMessageBox(QMessageBox::NoIcon,
00339 "Visual Object Tracker Help", help,
00340 QMessageBox::Ok, this,
00341 Qt::Dialog);
00342 box->resize(100,600);
00343 help_window = box;
00344 }
00345 help_window->show();
00346 help_window->raise();
00347 help_window->activateWindow();
00348 }
00349
00350
00351 void VSView::keyPressEvent(QKeyEvent *k)
00352 {
00353 static int n=0;
00354 char fn[256];
00355 pyr_frame *frame = (pyr_frame *) tracker->get_nth_frame(0);
00356
00357 switch (k->key()) {
00358 case Qt::Key_D: dark = !dark; break;
00359
00360 case Qt::Key_S: sprintf(fn,"shot%04d.png", n++); renderAndSave(fn, im->width*2, im->height); break;
00361 case Qt::Key_Tab: if (vs->isPlaying()) vs->stop(); else vs->start(); break;
00362 case Qt::Key_R: record = !record; record_pts=false; break;
00363 case Qt::Key_L: if (k->modifiers() && Qt::ShiftModifier) {
00364 if (viewlevel<nbLev-1) viewlevel++;
00365 } else {
00366 if (viewlevel>0) viewlevel--;
00367 }
00368 break;
00369
00370
00371
00372
00373
00374
00375
00376
00377 case Qt::Key_M: if(k->modifiers() & Qt::ShiftModifier) {
00378 record_movie = !record_movie;
00379 break;
00380 }
00381
00382
00383
00384
00385
00386
00387 break;
00388
00389
00390
00391
00392
00393
00394
00395 case Qt::Key_Space: if (timer) {killTimer(timer); timer=0; }
00396 else { timer = startTimer(0); } break;
00397 case Qt::Key_Q: summary(); close(); break;
00398 case Qt::Key_Escape: selected_kpt=0; break;
00399
00400 case Qt::Key_A: add_current_frame_to_db("Interactive, no geometry checking", 0); break;
00401 case Qt::Key_F: add_current_frame_to_db("Interactive, F-Mat checking", visual_object::VERIFY_FMAT); break;
00402 case Qt::Key_H: add_current_frame_to_db("Interactive, homography checking", visual_object::VERIFY_HOMOGRAPHY); break;
00403 case Qt::Key_P: record_pts = !record_pts; record=false; break;
00404 case Qt::Key_C: entry = 0; init_query_with_frame(*query, frame); break;
00405 case Qt::Key_1: view_mode = VIEW_AUTO; break;
00406 case Qt::Key_2: view_mode = VIEW_KEYPOINTS; break;
00407 case Qt::Key_3: view_mode = VIEW_TRACKS; break;
00408 case Qt::Key_4: view_mode = VIEW_ANNOTATIONS; break;
00409 case Qt::Key_I: auto_index = !auto_index; break;
00410 case Qt::Key_Plus: threshold += .005; cout << "T=" << threshold << endl; break;
00411 case Qt::Key_Minus: threshold -= .005; cout << "T=" << threshold << endl; break;
00412 case Qt::Key_Z: zoom(.5,1); translate(0,0); break;
00413 default: if ((k->key()>= Qt::Key_F1 && k->key()<=Qt::Key_F12) || k->text().size() > 0)
00414 show_help();
00415 }
00416 update();
00417 }
00418
00419 void VSView::segment_scene()
00420 {
00421
00422 pyr_frame *lf= (pyr_frame *)tracker->get_nth_frame(1);
00423 if (!lf) return;
00424
00425
00426
00427
00428 for (tracks::keypoint_frame_iterator it(lf->points.begin()); !it.end(); ++it) {
00429 pyr_keypoint *k = (pyr_keypoint *) it.elem();
00430 if (k->track && k->track->length > 20) {
00431 if (k->matches.next==0) nlost++;
00432 }
00433 }
00434
00435 if (nlost > 30) {
00436 nlost = 0;
00437 cout << "scene change " << endl;
00438 for (ttrack *t= tracker->all_tracks; t!=0; t=t->track_node.next) {
00439 if (t->length > 10) {
00440 pyr_keypoint *p= (pyr_keypoint *)t->keypoints;
00441 cout << p->cid << ",";
00442 }
00443 }
00444 tracks::frame_iterator it = tracker->get_nth_frame_it(1);
00445 tracker->remove_frame(it);
00446 }
00447
00448 }
00449
00450 void VSView::add_current_frame_to_db(const char *name, int flags)
00451 {
00452 pyr_frame *frame = (pyr_frame *)tracker->get_nth_frame(0);
00453 if (auto_index) {
00454
00455 int n=0;
00456 for (tracks::keypoint_frame_iterator it(frame->points.begin()); !it.end(); ++it) {
00457 pyr_keypoint *k = (pyr_keypoint *) it.elem();
00458 if (k->track_is_longer(10)) n++;
00459 }
00460 if (n < 30) return;
00461 cout << "Auto-indexing a frame with " << n << " tracks longer than 4 frames.\n";
00462 }
00463
00464 cout << "Adding object " << name << endl;
00465 visual_object *obj = database.create_object(name, flags);
00466 obj->add_frame(frame);
00467 obj->prepare();
00468 database.add_to_index(obj);
00469 init_query_with_frame(*query, frame);
00470 add_frame_time.restart();
00471 }
00472
00473 bool VSView::selectKeypoint(QMouseEvent *event)
00474 {
00475 point2d c;
00476 screenToImageCoord(event->x(), event->y(), &c.u, &c.v);
00477
00478 pyr_frame *frame = (pyr_frame *) tracker->get_nth_frame(0);
00479
00480 int w = frame->pyr->images[0]->width;
00481 if (c.u > w) {
00482 addAnnotation(c.u-w,c.v);
00483 return false;
00484 }
00485
00486 bucket2d<tkeypoint>::iterator it = frame->points.search(c.u,c.v,5);
00487 if (it.end()) return false;
00488
00489 float dist = c.dist(*it.elem());
00490 bucket2d<tkeypoint>::iterator best = it;
00491 for(++it; !it.end(); ++it) {
00492 float d= c.dist(*it.elem());
00493 if (d<dist) {
00494 dist = d;
00495 best = it;
00496 }
00497 }
00498 selected_kpt = (pyr_keypoint *) best.elem();
00499 show_track(selected_kpt);
00500
00501 return true;
00502 }
00503
00504 void VSView::mouseDoubleClickEvent ( QMouseEvent * ) {
00505 selected_kpt=0;
00506 update();
00507 }
00508
00509 void VSView::mousePressEvent ( QMouseEvent * event )
00510 {
00511 switch (event->button()) {
00512 case Qt::LeftButton:
00513 if (!selected_kpt) {
00514 selectKeypoint(event);
00515 }
00516 break;
00517 default:
00518 break;
00519 }
00520 GLBox::mousePressEvent(event);
00521 update();
00522 }
00523
00524 void VSView::mouseReleaseEvent ( QMouseEvent * event )
00525 {
00526 GLBox::mouseReleaseEvent(event);
00527 }
00528
00529 static inline void glVertex(cv::Point_<float> p)
00530 {
00531 glVertex2f(p.x,p.y);
00532 }
00533
00534 void draw_keypoint(const pyr_keypoint *k) {
00535 float x = k->u;
00536 float y = k->v;
00537 float angle = k->descriptor.orientation;
00538 float len=5 + (2 << k->scale);
00539 float dx = len * cosf(angle);
00540 float dy = len * sinf(angle);
00541
00542 if (k->cid) {
00543 gl_hash_mark(k->cid, k->u, k->v, k->descriptor.orientation, len);
00544 } else {
00545 #ifdef WITH_MSER
00546 glBegin(GL_LINE_STRIP);
00547 glVertex(k->mser.c -(k->mser.e1) -(k->mser.e2));
00548 glVertex(k->mser.c -k->mser.e1 +k->mser.e2);
00549 glVertex(k->mser.c +k->mser.e1 +k->mser.e2);
00550 glVertex(k->mser.c +k->mser.e1 -k->mser.e2);
00551 glVertex(k->mser.c -k->mser.e1 -k->mser.e2);
00552 glEnd();
00553 #endif
00554 glBegin(GL_LINES);
00555 glVertex2f(x,y);
00556 glVertex2f(x+dx,y+dy);
00557 glVertex2f(x-dy/4,y+dx/4);
00558 glVertex2f(x+dy/4,y-dx/4);
00559 glEnd();
00560 }
00561 }
00562
00563 void VSView::createTracker()
00564 {
00565 if (tracker==0) {
00566 if (im==0) return;
00567
00568
00569 makeCurrent();
00570 tracker = new kpt_tracker(im->width,im->height,nbLev, (int)(16), true);
00571
00572 database.open(visual_db_fn);
00573
00574 if (tree_fn) {
00575 tracker->load_tree(tree_fn);
00576 tracker->load_clusters(clusters_fn);
00577 } else {
00578 tracker->load_from_db(database.get_sqlite3_db());
00579 }
00580
00581 cout << "Press F1 for help.\n";
00582
00583 add_frame_tex.setImage(cvLoadImage("add_frame.png"));
00584 }
00585 }
00586
00587 static void HSVtoRGB( float *r, float *g, float *b, float h, float s, float v )
00588 {
00589 int i;
00590 float f, p, q, t;
00591
00592 if( s == 0 ) {
00593
00594 *r = *g = *b = v;
00595 return;
00596 }
00597
00598 h /= 60;
00599 i = floor( h );
00600 f = h - i;
00601 p = v * ( 1 - s );
00602 q = v * ( 1 - s * f );
00603 t = v * ( 1 - s * ( 1 - f ) );
00604
00605 switch( i ) {
00606 case 0: *r = v; *g = t; *b = p; break;
00607 case 1: *r = q; *g = v; *b = p; break;
00608 case 2: *r = p; *g = v; *b = t; break;
00609 case 3: *r = p; *g = q; *b = v; break;
00610 case 4: *r = t; *g = p; *b = v; break;
00611 default:
00612 *r = v; *g = p; *b = q; break;
00613 }
00614 }
00615
00616 static void gl_hash_color(unsigned key)
00617 {
00618 float c[3];
00619 HSVtoRGB(c,c+1,c+2, fmod((float)key, 360), 1, 1);
00620 glColor3fv(c);
00621 }
00622
00623 void gl_hash_mark(unsigned code, float x, float y, float orient, float r)
00624 {
00625 gl_hash_color(code);
00626
00627 unsigned char c = (code^(code>>8)^(code>>16)^(code>>24))&0xff;
00628 int n = 4 + (c&0x7);
00629 float f = 1.5f + ((c>>3)&0x3)/2.0f;
00630
00631 float step_angle = M_PI*2.0f/n;
00632 float angle=orient;
00633
00634 glBegin(GL_LINE_STRIP);
00635
00636 for (int i=0; i<n; i++) {
00637
00638 float r2 = (i&1 ? r*f : r);
00639 float sin = sinf(angle);
00640 float cos = cosf(angle);
00641 angle+=step_angle;
00642
00643 glVertex2f(x+r2*cos,y+r2*sin);
00644 }
00645 float sin = sinf(angle);
00646 float cos = cosf(angle);
00647 glVertex2f(x+r*cos,y+r*sin);
00648
00649 glEnd();
00650 }
00651
00652 void VSView::draw_selected_track()
00653 {
00654 if (!selected_kpt) return;
00655
00656
00657 tracks::keypoint_match_iterator it(selected_kpt);
00658 while (it.elem()->matches.next) ++it;
00659 tracks::keypoint_match_iterator first(it);
00660
00661 pyr_frame *frame = (pyr_frame *) tracker->get_nth_frame(0);
00662
00663 if (it.elem()->frame != frame) {
00664 glColor4f(1,0,0,1);
00665 selected_kpt=0;
00666 } else {
00667 glColor4f(0,1,0,1);
00668 }
00669
00670 for (it=first; !it.end(); --it) {
00671 pyr_keypoint *p = (pyr_keypoint *)it.elem();
00672 draw_keypoint(p);
00673 }
00674
00675 float r = 16;
00676 point2d pos(0,image->height);
00677 for (it=first; !it.end(); --it) {
00678 #ifndef WITH_SURF
00679 pyr_keypoint *k = (pyr_keypoint *) it.elem();
00680
00681 if (k->node) {
00682 CvMat mat; cvInitMatHeader(&mat, patch_tagger::patch_size, patch_tagger::patch_size, CV_32FC1,
00683 k->node->mean.mean);
00684 point2d pos_down(pos.u, pos.v+r);
00685 draw_icon(&pos_down, &mat, r, r, image->width, 0, r);
00686 }
00687 draw_icon(&pos, &k->descriptor.rotated, r, r, image->width, 0, r);
00688 #endif
00689 }
00690 glPopMatrix();
00691 glPopMatrix();
00692 }
00693
00694 void VSView::draw_icon(point2d *c, const CvArr *image, float w, float h, float max_width, int margin_x, int margin_y)
00695 {
00696 if (!image) return;
00697
00698 if (icon_texture_available.begin() == icon_texture_available.end()) {
00699 IplTexture t;
00700 icon_texture_available.push_back(t);
00701 }
00702 icon_texture_used.splice(icon_texture_used.begin(), icon_texture_available, icon_texture_available.begin());
00703 IplTexture &t(icon_texture_used.front());
00704 CvMat m;
00705 t.setImage( cvGetMat(image, &m));
00706 glColor4f(1,1,1,1);
00707 t.drawQuad(c->u, c->v, w, h);
00708 c->u += w + margin_x;
00709 if (c->u>=max_width) {
00710 c->u = 0;
00711 c->v += h + margin_y;
00712 }
00713 }
00714
00715 void VSView::draw_all_tracks(pyr_frame *frame)
00716 {
00717 glColor4f(0,1,0,1);
00718
00719 for (tracks::keypoint_frame_iterator it(frame->points.begin()); !it.end(); ++it) {
00720 pyr_keypoint *k = (pyr_keypoint *) it.elem();
00721
00722 if (k->track_is_longer(2)) {
00723 glBegin(GL_LINE_STRIP);
00724
00725 int n=0;
00726
00727
00728 std::map<int, pyr_keypoint *> map;
00729 int track_len=0;
00730 for (tracks::keypoint_match_iterator it(k); !it.end(); --it) {
00731 pyr_keypoint *p = (pyr_keypoint *)it.elem();
00732 map[p->id] = p;
00733 track_len++;
00734 }
00735
00736 float c =(float)map.size()/(float)track_len;
00737 if (c<.1) c =1;
00738 else c =0;
00739
00740
00741 for (tracks::keypoint_match_iterator it(k); !it.end(); --it) {
00742 pyr_keypoint *p = (pyr_keypoint *)it.elem();
00743
00744 float alpha = 1.0f-(n++)/256.0f;
00745
00746
00747 if (p->matches.prev) {
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766 glColor4f(1-c,c,0,alpha);
00767 }
00768 else glColor4f(0,1,0,alpha);
00769 glVertex2f(p->u, p->v);
00770 }
00771 glEnd();
00772 }
00773 }
00774 }
00775
00776 void VSView::draw_keypoints(pyr_frame *frame)
00777 {
00778 for (tracks::keypoint_frame_iterator it(frame->points.begin()); !it.end(); ++it) {
00779 pyr_keypoint *k = (pyr_keypoint *) it.elem();
00780
00781
00782
00783 glColor4f(0,1,0,.5);
00784 draw_keypoint(k);
00785
00786 }
00787 }
00788
00789 void VSView::draw_entry_image()
00790 {
00791 if (!entry) return;
00792
00793 IplImage *entry_image = database.get_image(entry->representative_image);
00794 entry_tex.setImage(entry_image);
00795
00796 if (entry_image)
00797 entry_tex.drawQuad(image->width,0);
00798 }
00799
00800 void VSView::draw_matches(pyr_frame *frame)
00801 {
00802 if (!entry || entry->get_total() ==0) return;
00803
00804 IplImage *entry_image = database.get_image(entry->representative_image);
00805
00806 if (!entry_image)
00807 entry_image = image;
00808
00809 point2d cursor(0,image->height);
00810 if (0)
00811 for (tracks::keypoint_frame_iterator it(frame->points.begin()); !it.end(); ++it) {
00812 pyr_keypoint *k = (pyr_keypoint *) it.elem();
00813
00814 visual_object::db_keypoint_vector::iterator begin, end, i;
00815 entry->find(k->cid,begin,end);
00816
00817 if (begin==end) continue;
00818
00819 if (!selected_kpt || selected_kpt == k)
00820 draw_keypoint(k);
00821
00822 glPushMatrix();
00823 glTranslatef(image->width,0,0);
00824 for (i=begin; i!=end; i++) {
00825 assert(i->cid == k->cid);
00826 if (!selected_kpt || selected_kpt->cid == i->cid)
00827 draw_keypoint(&(*i));
00828
00829 if (k==selected_kpt && i->node) {
00830 point2d down(cursor.u, cursor.v+16);
00831 CvMat mat;
00832 cvInitMatHeader(&mat, patch_tagger::patch_size, patch_tagger::patch_size, CV_32FC1,
00833 i->node->mean.mean);
00834 draw_icon(&down, &mat, 16, 16, entry_image->width,0,16);
00835
00836 draw_icon(&cursor, &i->descriptor.rotated, 16, 16, entry_image->width,0,16);
00837 }
00838 }
00839 glPopMatrix();
00840 }
00841
00842 for (visual_object::correspondence_vector::iterator it(corresp.begin()); it!= corresp.end(); ++it)
00843 {
00844 pyr_keypoint *k = it->frame_kpt;
00845 pyr_keypoint *o = it->obj_kpt;
00846
00847
00848
00849 if (!selected_kpt || selected_kpt == k) {
00850 draw_keypoint(k);
00851 }
00852
00853 glPushMatrix();
00854 glTranslatef(image->width,0,0);
00855
00856 if (!selected_kpt || selected_kpt == k) {
00857 draw_keypoint(o);
00858 }
00859
00860 if (k==selected_kpt) {
00861 if (o->node) {
00862 point2d down(cursor.u, cursor.v+16);
00863 CvMat mat;
00864 cvInitMatHeader(&mat, patch_tagger::patch_size, patch_tagger::patch_size, CV_32FC1,
00865 o->node->mean.mean);
00866 draw_icon(&down, &mat, 16, 16, entry_image->width,0,16);
00867 }
00868
00869 draw_icon(&cursor, &o->descriptor.rotated, 16, 16, entry_image->width,0,16);
00870 }
00871 glPopMatrix();
00872 }
00873 }
00874
00875 void VSView::drawAnnotations(float dx, float dy)
00876 {
00877 if (!entry) return;
00878
00879 QFont font;
00880 font.setPointSize(12);
00881 QFontMetrics metric(font);
00882
00883 int hl = metric.xHeight()/2;
00884
00885 int text_win_width=0;
00886 int n=0;
00887 for (visual_object::annotation_iterator it(entry->annotation_begin()); it!= entry->annotation_end(); ++it, ++n)
00888 {
00889 QRect r = metric.boundingRect(QString::fromUtf8(it->descr.c_str()));
00890 if (r.width() > text_win_width) text_win_width = r.width();
00891 }
00892
00893 int text_win_height = (n-1)*metric.lineSpacing() + metric.height();
00894 int tx = width() - text_win_width - 3*hl;
00895 int ty = 3*hl;
00896
00897 float top, bottom, right, left;
00898 screenToImageCoord(tx-hl,ty-hl, &left, &top);
00899 screenToImageCoord(tx+hl+text_win_width,ty+hl+text_win_height, &right, &bottom);
00900 glColor4f(0,0,0,.5);
00901 glEnable(GL_BLEND);
00902 glBegin(GL_QUADS);
00903 glVertex2f(left,top);
00904 glVertex2f(right,top);
00905 glVertex2f(right,bottom);
00906 glVertex2f(left,bottom);
00907 glEnd();
00908
00909 glEnable(GL_LINE_SMOOTH);
00910
00911 n=0;
00912 for (visual_object::annotation_iterator it(entry->annotation_begin()); it!= entry->annotation_end(); ++it, ++n)
00913 {
00914 glColor4f(1,1,1,1);
00915 int y = ty + n*metric.lineSpacing() + metric.ascent();
00916 renderText(tx, y, QString::fromUtf8(it->descr.c_str()), font);
00917
00918 float txim, tyim;
00919 screenToImageCoord(tx,y-hl , &txim, &tyim);
00920
00921 glBegin(GL_LINES);
00922 glVertex2f(txim,tyim);
00923 glVertex2f(it->x+dx, it->y+dy);
00924 glEnd();
00925
00926 }
00927 }
00928
00929 void VSView::paintGL()
00930 {
00931 TaskTimer::pushTask("Display");
00932
00933 #ifdef WITH_SIFTGPU
00934 glDisable(GL_TEXTURE_RECTANGLE_ARB);
00935 #endif
00936 icon_texture_available.splice(icon_texture_available.begin(), icon_texture_used);
00937
00938 glDisable(GL_DEPTH_TEST);
00939 resizeGL(width(),height());
00940
00941 if (dark) glColor4f(.5,.5,.5,1);
00942 else glColor4f(1,1,1,1);
00943 GLBox::paintGL();
00944
00945 if (tracker==0) {
00946 TaskTimer::popTask();
00947 return;
00948 }
00949
00950 pyr_frame *frame = (pyr_frame *) tracker->get_nth_frame(0);
00951 if (!frame) {
00952 TaskTimer::popTask();
00953 return;
00954 }
00955
00956 glEnable(GL_BLEND);
00957 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00958
00959 setAxisUp(false);
00960 setImageSpace();
00961
00962 draw_entry_image();
00963
00964 if (view_mode == VIEW_KEYPOINTS) {
00965 draw_keypoints(frame);
00966 } else if (view_mode== VIEW_TRACKS) {
00967 draw_all_tracks(frame);
00968 } else if (view_mode != VIEW_ANNOTATIONS) {
00969 if (entry && entry->get_total() >0)
00970 draw_matches(frame);
00971 else {
00972 if (!selected_kpt) {
00973 draw_keypoints(frame);
00974
00975 }
00976 }
00977
00978 if (selected_kpt) {
00979 draw_selected_track();
00980 }
00981 }
00982
00983 drawAnnotations(frame->pyr->images[0]->width, 0);
00984
00985 if (add_frame_tex.getIm()) {
00986 int t = add_frame_time.elapsed();
00987 if (t>0 && t< 1200) {
00988 glColor4f(1,1,1,1);
00989 add_frame_tex.drawQuad(10,10,256,64);
00990 }
00991 }
00992 glDisable(GL_BLEND);
00993 glEnable(GL_DEPTH_TEST);
00994 #ifdef WITH_SIFTGPU
00995 glEnable(GL_TEXTURE_RECTANGLE_ARB);
00996 #endif
00997 TaskTimer::popTask();
00998 }
00999
01000 void VSView::write_descriptor(pyr_keypoint *k, long ptr)
01001 {
01002 static const unsigned descr_size=kmean_tree::descriptor_size;
01003 if ((sizeof(long)+descr_size*sizeof(float)) != sizeof(kmean_tree::descr_file_packet)) {
01004 cerr << "wrong structure size!!\n";
01005 exit(-1);
01006 }
01007
01008 #ifdef WITH_SURF
01009 if (k->surf_descriptor.descriptor[0]==-1) return;
01010 for (unsigned i=0;i<64;i++) {
01011 if (!finite(k->surf_descriptor.descriptor[i])) {
01012 cerr << "surf descr[" << i << "] = " << k->surf_descriptor.descriptor[i] << endl;
01013 return;
01014 }
01015 }
01016
01017 if (fwrite(&ptr, sizeof(long), 1, descrf)!=1 ||
01018 fwrite(k->surf_descriptor.descriptor, 64*sizeof(float), 1, descrf)!=1) {
01019 cerr << "write error!\n";
01020 return;
01021 }
01022 #endif
01023 #ifdef WITH_SIFTGPU
01024 if (fwrite(&ptr, sizeof(long), 1, descrf)!=1 ||
01025 fwrite(k->sift_descriptor.descriptor, 128*sizeof(float), 1, descrf)!=1) {
01026 cerr << "write error!\n";
01027 return;
01028 }
01029 #endif
01030 #ifdef WITH_PATCH_TAGGER_DESCRIPTOR
01031 if (k->descriptor.total==0) {
01032 std::cout << "save_descriptors: total==0!\n";
01033 return;
01034 }
01035
01036 size_t n = fwrite(&ptr, sizeof(long), 1, descrf);
01037 float _array[descr_size];
01038 k->descriptor.array(_array);
01039
01040 n = fwrite(_array, descr_size * sizeof(float), 1,descrf);
01041 #endif
01042
01043 }
01044
01045 void VSView::save_tracks()
01046 {
01047 if (descrf==0)
01048 descrf = fopen(descriptors_fn, "ab");
01049
01050 pyr_frame *frame = (pyr_frame *) tracker->get_nth_frame(2);
01051 if (!frame) return;
01052
01053 for (tracks::keypoint_frame_iterator it(frame->points.begin()); !it.end(); ++it) {
01054 pyr_keypoint *k = (pyr_keypoint *) it.elem();
01055
01056 if (k->matches.next!=0 || !k->track_is_longer(4)) continue;
01057
01058
01059
01060 long lastpos = -1;
01061 for (tracks::keypoint_match_iterator it(k); !it.end(); --it) {
01062 pyr_keypoint *p = (pyr_keypoint *)it.elem();
01063
01064 long pos = ftell(descrf);
01065 write_descriptor(p,lastpos);
01066 lastpos=pos;
01067 }
01068 }
01069 }
01070
01071 void VSView::save_descriptors(pyr_frame *frame)
01072 {
01073 if (!frame) return;
01074
01075 if (descrf==0)
01076 descrf = fopen(descriptors_fn, "ab");
01077
01078 for (tracks::keypoint_frame_iterator it(frame->points.begin()); !it.end(); ++it) {
01079 pyr_keypoint *k = (pyr_keypoint *) it.elem();
01080
01081
01082 write_descriptor(k,-1);
01083 }
01084 }
01085
01086 void VSView::cmp_affinity() {
01087
01088 pyr_frame *frame = (pyr_frame *) tracker->get_nth_frame(0);
01089 for (tracks::keypoint_frame_iterator it(frame->points.begin()); !it.end(); ++it) {
01090 pyr_keypoint *k = (pyr_keypoint *) it.elem();
01091
01092 if (k->matches.prev) {
01093 id_pair pair(k->id,((pyr_keypoint *)k->matches.prev)->id);
01094 map<id_pair,unsigned>::iterator it = affinity_matrix.find(pair);
01095 if (it==affinity_matrix.end())
01096 affinity_matrix[pair]=1;
01097 else
01098 it->second++;
01099 }
01100 }
01101 }
01102
01103 struct upair {
01104 unsigned good, bad;
01105 upair() : good(0),bad(0) {}
01106 };
01107
01108
01109 void VSView::print_affinity() {
01110 map<unsigned, upair> total;
01111 for (map<id_pair,unsigned>::iterator it = affinity_matrix.begin();
01112 it != affinity_matrix.end(); ++it)
01113 {
01114 cout << it->first.a << "," << it->first.b << ": " << it->second << endl;
01115
01116 if (it->first.a == it->first.b) {
01117 total[it->first.a].good += it->second;
01118 } else {
01119 total[it->first.a].bad += it->second;
01120 total[it->first.b].bad += it->second;
01121 }
01122 }
01123
01124 cout << "total:\n";
01125 for (map<unsigned, upair>::iterator it=total.begin(); it!=total.end(); ++it)
01126 {
01127 cout << "id: " << it->first << " has " << 100.0f*(float)it->second.good/(it->second.good+it->second.bad) << "% success rate, detected " << it->second.good+it->second.bad << " times.\n";
01128 }
01129 }
01130
01131 void VSView::show_track(pyr_keypoint *k)
01132 {
01133
01134 std::map<unsigned, unsigned> map, cmap;
01135 int track_len= 0;
01136 if (k->track) track_len = k->track->length;
01137 cout << "Track has " << track_len << " frames:\n";
01138 for (tracks::keypoint_match_iterator it(k); !it.end(); --it) {
01139 pyr_keypoint *p = (pyr_keypoint *)it.elem();
01140 cout << " " << p->id << ":" << p->cid << "("<<p->cscore<<")";
01141
01142 std::map<unsigned, unsigned>::iterator id_it = map.find(p->id);
01143 if (id_it == map.end()) map[p->id] = 1;
01144 else id_it->second++;
01145
01146 id_it = cmap.find(p->cid);
01147 if (id_it == cmap.end()) cmap[p->cid] = 1;
01148 else id_it->second++;
01149
01150 }
01151 cout << endl << "ID histogram:\n";
01152
01153 for (std::map<unsigned,unsigned>::iterator id_it = map.begin();
01154 id_it != map.end(); ++id_it)
01155 {
01156 cout << " id:" << id_it->first << " on " << id_it->second << " frames.\n";
01157 }
01158 if (k->track) {
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168 float d;
01169 pyr_track *track = (pyr_track *) k->track;
01170 if (tracker->id_clusters) {
01171 id_cluster *c = tracker->id_clusters->get_best_cluster(&track->id_histo.query_cluster, &d);
01172 cout << "Best cluster: " << c->id << " score= " << d << endl;
01173 }
01174 } else {
01175 cout << "pointer to track is 0\n";
01176 }
01177
01178 for (std::map<unsigned,unsigned>::iterator id_it = cmap.begin();
01179 id_it != cmap.end(); ++id_it)
01180 {
01181 cout << " cid:" << id_it->first << " on " << id_it->second << " frames.\n";
01182 }
01183
01184
01185 }
01186
01187 void VSView::show_tracks()
01188 {
01189 int t=1;
01190 pyr_frame *frame = (pyr_frame *) tracker->get_nth_frame(0);
01191
01192 std::map<unsigned, unsigned> full_map;
01193
01194 for (tracks::keypoint_frame_iterator it(frame->points.begin()); !it.end(); ++it) {
01195 pyr_keypoint *k = (pyr_keypoint *) it.elem();
01196
01197 if (k->track_is_longer(10)) {
01198
01199
01200 std::map<unsigned, unsigned> map;
01201 int track_len=0;
01202 for (tracks::keypoint_match_iterator it(k); !it.end(); --it) {
01203 pyr_keypoint *p = (pyr_keypoint *)it.elem();
01204 std::map<unsigned, unsigned>::iterator id_it = map.find(p->id);
01205 if (id_it == map.end())
01206 map[p->id] = 1;
01207 else
01208 id_it->second++;
01209
01210 track_len++;
01211 }
01212 cout << "Track " << t++ << " " << track_len << " frames:\n";
01213 for (std::map<unsigned,unsigned>::iterator id_it = map.begin();
01214 id_it != map.end(); ++id_it)
01215 {
01216 cout << " id:" << id_it->first << " on " << id_it->second << " frames.\n";
01217 std::map<unsigned, unsigned>::iterator f_it = full_map.find(id_it->first);
01218 if (f_it == full_map.end())
01219 full_map[id_it->first] = id_it->second;
01220 else
01221 f_it->second += id_it->second;
01222
01223 }
01224 }
01225 }
01226
01227 cout << "total, " << full_map.size() << " different ids detected:\n";
01228 for (std::map<unsigned,unsigned>::iterator id_it = full_map.begin();
01229 id_it != full_map.end(); ++id_it)
01230 {
01231 cout << " id:" << id_it->first << " on " << id_it->second << " frames.\n";
01232 }
01233 }
01234
01235 void trim(string& str)
01236 {
01237 const char* spaces = " \r\f\n\t\v";
01238 string::size_type pos = str.find_last_not_of(spaces);
01239 if(pos != string::npos) {
01240 str.erase(pos + 1);
01241 pos = str.find_first_not_of(spaces);
01242 if(pos != string::npos) str.erase(0, pos);
01243 }
01244 else str.erase(str.begin(), str.end());
01245 }
01246
01247 bool VSView::load_script(const char *fn)
01248 {
01249 ifstream f(fn);
01250
01251 if (!f.good()) return false;
01252
01253 while (f.good()) {
01254 script_instruction instr;
01255
01256 string s_id, s_instr;
01257 f >> s_id;
01258 f >> s_instr;
01259 getline(f, instr.arg);
01260 trim(instr.arg);
01261 if (!f.good()) break;
01262
01263 if (s_id.length() <1 || s_instr.length() < 1) break;
01264
01265 int id = atoi(s_id.c_str());
01266
01267 if (s_instr.compare("add")==0) {
01268 instr.instr = INSTR_ADD;
01269 } else if (s_instr.compare("addH")==0) {
01270 instr.instr = INSTR_ADDH;
01271 } else if (s_instr.compare("addF")==0) {
01272 instr.instr = INSTR_ADDF;
01273 } else if (s_instr.compare("echo")==0) {
01274 instr.instr = INSTR_ECHO;
01275 }else if (s_instr.compare("check")==0) {
01276 instr.instr = INSTR_CHECK;
01277 } else {
01278 cerr << fn << ": unknown instruction: " << s_instr;
01279 continue;
01280 }
01281 script[id].push_back(instr);
01282 }
01283 return true;
01284 }
01285
01286 void VSView::summary()
01287 {
01288
01289 TaskTimer::printStats();
01290
01291 cout <<"FPS vs number of features:\n";
01292 for (fps_stat_map::iterator it(fps_stat.begin()); it!=fps_stat.end(); ++it)
01293 {
01294 cout << it->first*fps_stat_bin_size << ".." << ((1+it->first)*fps_stat_bin_size)-1 << ": "
01295 << it->second.first << " ms (count=" << it->second.second << ")\n";
01296 }
01297 cout << endl;
01298
01299 float nframes = (gt_success+gt_fail);
01300 cout << gt_success << " successfull frames (" << true_neg << " true neg), " << gt_fail << " wrong ones. Ratio: " <<
01301 (float)gt_success / nframes << endl;
01302 cout << "false pos: " << false_pos << ", false neg: " << false_neg << endl;
01303 float sec = total_time.elapsed() / 1000.0f;
01304 cout << "Video processed in " << sec << "s, average fps: " << nframes/sec << endl;
01305
01306 }
01307
01308 void VSView::script_exec(int id)
01309 {
01310 if ((entry == 0 && (ground_truth.compare("none")==0 || ground_truth.length()==0))
01311 || (entry && ground_truth.compare(entry->get_comment())==0))
01312 {
01313 gt_success++;
01314 if (entry==0) true_neg++;
01315 } else {
01316
01317 gt_fail++;
01318 if (entry==0 && !(ground_truth.compare("none")==0 || ground_truth.length()==0))
01319 false_neg++;
01320 if (entry && (ground_truth.compare("none")==0 || ground_truth.length()==0))
01321 false_pos++;
01322 }
01323
01324 script_map::iterator frame_it = script.find(id);
01325 if (frame_it == script.end()) return;
01326 for (instr_list::iterator it(frame_it->second.begin()); it!= frame_it->second.end(); ++it)
01327 {
01328 switch (it->instr) {
01329 case INSTR_ECHO: cout << id << ": " << it->arg << endl; break;
01330 case INSTR_ADD: add_current_frame_to_db(it->arg.c_str(), 0); break;
01331 case INSTR_ADDH: add_current_frame_to_db(it->arg.c_str(), visual_object::VERIFY_HOMOGRAPHY); break;
01332 case INSTR_ADDF: add_current_frame_to_db(it->arg.c_str(), visual_object::VERIFY_FMAT); break;
01333 case INSTR_CHECK: ground_truth = it->arg; break;
01334 }
01335 }
01336
01337 }
01338
01339 void VSView::addAnnotation(float x, float y)
01340 {
01341 if (!entry) return;
01342 bool restart_timer = false;
01343 if (timer) {
01344 restart_timer=true;
01345 killTimer(timer);
01346 }
01347 timer=0;
01348
01349 bool ok;
01350 QString text = QInputDialog::getText(this, "Annotation",
01351 "Message:", QLineEdit::Normal, "", &ok);
01352 if (ok && !text.isEmpty()) {
01353 entry->add_annotation(x,y, 0, (const char *) text.toUtf8());
01354 }
01355
01356 if ( restart_timer ) {
01357 timer = startTimer(0);
01358 }
01359 }
01360