tidied up last issues
[The-Artvertiser.git] / artvertiser / calibmodel.cpp
blobea1d42a73557f6c7d1f9e38b744ec8cc69e74c6d
1 #include "calibmodel.h"
2 #include "multigrab.h"
4 char CalibModel::progress_string[2048];
6 CalibModel::CalibModel()
8 image=0;
9 image_width = 0;
10 image_height = 0;
11 win = "The Artvertiser 0.4";
12 train_working_image = 0;
13 interactive_train_running = false;
14 interactive_train_should_stop = false;
15 debounce_green = false;
16 debounce_redblue = false;
17 strcpy(progress_string, "");
19 cvInitFont(&train_font, CV_FONT_HERSHEY_SIMPLEX, .5, .5, 0, 0, CV_AA);
22 CalibModel::~CalibModel()
24 if (image) cvReleaseImage(&image);
25 if ( train_working_image )
27 cvReleaseImage( &train_working_image );
28 cvReleaseImage( &train_shot );
32 void CalibModel::useModelFile(const char* file)
34 modelfile = file;
37 CalibModel *objectPtr=0;
39 void CalibModel::onMouse(int event, int x, int y, int flags)
41 CvPoint* ptr;
42 if ( state == ARTVERT_CORNERS )
43 ptr = artvert_corners;
44 else
45 ptr = corners;
46 if (event == CV_EVENT_LBUTTONDOWN)
48 // try to grab something
49 grab = -1;
50 for (int i=0; i<4; i++)
52 int dx = x-ptr[i].x;
53 int dy = y-ptr[i].y;
54 if (sqrt((double)(dx*dx+dy*dy)) <10) {
55 grab = i;
56 break;
61 if (grab!=-1)
63 ptr[grab].x = x;
64 ptr[grab].y = y;
67 if (event == CV_EVENT_LBUTTONUP)
69 grab=-1;
73 bool CalibModel::buildCached(int nbcam, CvCapture *capture,
74 bool cache, planar_object_recognizer &detector,
75 bool running_on_binoculars )
78 detector.clear();
80 printf("buildCached about to grab a lock\n");
82 detector.lock();
85 detector.ransac_dist_threshold = 5;
86 detector.max_ransac_iterations = 800;
87 //detector.ransac_stop_support = 50;
88 //detector.non_linear_refine_threshold = 15.0f;
89 //detector.point_detector_tau = 10;
91 // A lower threshold will allow detection in harder conditions, but
92 // might lead to false positives.
93 detector.match_score_threshold=.03f;
95 detector.min_view_rate=.1;
96 detector.views_number = 1000;
97 // damian below
98 //detector.min_view_rate = .2;
100 static const int MAX_MODEL_KEYPOINTS = 500; // maximum number of keypoints on the model
101 static const int PATCH_SIZE = 32; // patch size in pixels
102 static const int YAPE_RADIUS = 5; // yape radius
103 static const int NUM_TREES = 12; // num classifier trees
104 static const int NUM_GAUSSIAN_LEVELS = 3; // num gaussian levels
105 /*static const int MAX_MODEL_KEYPOINTS = 500; // maximum number of keypoints on the model
106 static const int PATCH_SIZE = 32; // patch size in pixels
107 static const int YAPE_RADIUS = 5; // yape radius
108 static const int NUM_TREES = 12; // num classifier trees
109 static const int NUM_GAUSSIAN_LEVELS = 3; // num gaussian levels*/
112 // Should we train or load the classifier ?
113 if ( cache )
114 printf("model.buildCached() trying to load from %s...\n", modelfile );
115 if(cache && detector.build_with_cache(
116 string(modelfile), // mode image file name
117 /*500, // maximum number of keypoints on the model
118 //200, // maximum number of keypoints on the model
119 32, // patch size in pixels
120 5, // yape radius. Use 3,5 or 7.
121 //3, // yape radius. Use 3,5 or 7.
122 12, // number of trees for the classifier. Somewhere between 12-50
123 //20, // number of trees for the classifier. Somewhere between 12-50
124 3*/ // number of levels in the gaussian pyramid
125 // damian below
126 MAX_MODEL_KEYPOINTS, // max keypoints
127 PATCH_SIZE, // patch size
128 YAPE_RADIUS, // yape radius. Use 3,5 or 7.
129 NUM_TREES, // number of trees for the classifier. Somewhere between 12-50
130 NUM_GAUSSIAN_LEVELS // number of levels in the gaussian pyramid
134 // loading worked. Remember the region of interest.
135 corners[0].x = detector.new_images_generator.u_corner1;
136 corners[0].y = detector.new_images_generator.v_corner1;
137 corners[1].x = detector.new_images_generator.u_corner2;
138 corners[1].y = detector.new_images_generator.v_corner2;
139 corners[2].x = detector.new_images_generator.u_corner3;
140 corners[2].y = detector.new_images_generator.v_corner3;
141 corners[3].x = detector.new_images_generator.u_corner4;
142 corners[3].y = detector.new_images_generator.v_corner4;
144 MultiThreadCapture* mtc = MultiThreadCaptureManager::getInstance()->getCaptureForCam(capture);
146 IplImage* init_image = NULL;
147 int timeout = 10000;
148 bool got = false;
149 do {
150 got = mtc->getCopyOfLastFrame( &init_image );
152 while ( !got &&
153 !usleep( 10*1000 ) &&
154 (timeout-=10) > 0 );
155 if ( init_image == NULL )
157 printf("getCopyOfLastFrame timed out: capture failed\n");
158 detector.unlock();
159 detector.clear();
160 return false;
162 if ( image != 0 )
163 cvReleaseImage( &image );
164 image = cvLoadImage(modelfile, mtc->getNumChannelsRaw()==3 );
165 image_width = image->width;
166 image_height = image->height;
167 //cvReleaseImage(&init_image);
169 /*printf("dumping loaded cache:\n");
170 detector.dump();
174 else
176 if ( image != 0 )
177 cvReleaseImage( &image );
178 image =0;
179 // ask the user the take a shot of the model
180 bool result = false;
181 if( running_on_binoculars )
182 result = interactiveTrainBinoculars();
183 else
184 result = interactiveSetup(capture);
185 if (!result)
187 printf("interactiveSetup failed\n");
188 detector.unlock();
189 detector.clear();
190 return false;
192 else
194 printf("interactiveSetup succeeded\n");
197 image_width = image->width;
198 image_height = image->height;
200 // train the classifier to detect this model
201 //if (!detector.build(image, 500, 32, 3, 12, 3,0, 0))
202 //if (!detector.build(image, 200, 32, 5, 20, 3,0, 0))
203 int working_roi[8] = { corners[0].x, corners[0].y,
204 corners[1].x, corners[1].y,
205 corners[2].x, corners[2].y,
206 corners[3].x, corners[3].y
208 //LEARNPROGRESSION progress;
209 //LEARNPROGRESSION progress = 0;
211 printf("about to call detector.build...\n");
212 learn_running = true;
213 strcpy(progress_string, "preparing..");
214 if (!detector.build(image,
215 MAX_MODEL_KEYPOINTS, // max keypoints
216 PATCH_SIZE, // patch size
217 YAPE_RADIUS, // yape radius. Use 3,5 or 7.
218 NUM_TREES, // number of trees for the classifier. Somewhere between 12-50
219 NUM_GAUSSIAN_LEVELS, // number of levels in the gaussian pyramid
220 &learnProgressionFunc,
221 working_roi
224 learn_running = false;
225 printf("build based on interactiveSetup failed\n");
226 detector.unlock();
227 detector.clear();
228 return false;
231 printf("detector.build succeeded\n");
232 strcpy( progress_string, "saving..\n");
233 // save the image
234 if (!cvSaveImage(modelfile, image))
236 printf("saving input image failed\n");
237 learn_running = false;
238 detector.unlock();
239 detector.clear();
240 return false;
243 // and the region of interest (ROI)
244 string roifn = string(modelfile) + ".roi";
245 ofstream roif(roifn.c_str());
246 if (!roif.good())
248 learn_running = false;
249 detector.unlock();
250 detector.clear();
251 printf("saving .roi file failed\n");
252 return false;
254 for (int i=0;i<4; i++)
255 roif << corners[i].x << " " << corners[i].y << "\n";
256 roif.close();
258 // and the artvert corners
259 roifn = string(modelfile) + ".artvertroi";
260 ofstream artvert_roif(roifn.c_str());
261 if (!artvert_roif.good())
263 learn_running = false;
264 detector.unlock();
265 detector.clear();
266 printf("saving .artvertroi file failed\n");
267 return false;
269 for (int i=0;i<4; i++)
270 artvert_roif << artvert_corners[i].x << " " << artvert_corners[i].y << "\n";
271 artvert_roif.close();
273 // and the trained classifier
274 string classifier_directory = string(modelfile)+".classifier";
275 detector.save(classifier_directory);
277 string stable_points_filename = string(modelfile)+"_stable_points.bmp";
278 printf("saving stable points to %s\n", stable_points_filename.c_str());
279 detector.save_image_of_model_points(PATCH_SIZE, stable_points_filename.c_str() );
281 const char* initial_points_filename = "initial_model_points.bmp";
282 string initial_points_new_filename = string(modelfile)+"_initial_points.bmp";
283 printf("renaming %s to %s\n", initial_points_filename, initial_points_new_filename.c_str() );
284 rename(initial_points_filename, initial_points_new_filename.c_str() );
286 /*printf("dumping trained cache:\n");
287 detector.dump();*/
289 learn_running = false;
292 detector.unlock();
293 assert( detector.isReady() );
295 float cn[4][2];
296 for (int i=0; i<4; i++)
298 cn[i][0] = corners[i].x;
299 cn[i][1] = corners[i].y;
300 cout << corners[i].x << " " << corners[i].y << endl;
303 // prepare the light calibration reference
304 return map.init(nbcam, image, cn, 8, 6);
307 static void putText(IplImage *im, const char *text, CvPoint p, CvFont *f1)
309 cvPutText(im,text,p,f1, cvScalar(0,255, 255));
313 IplImage *myRetrieveFrame(CvCapture *capture)
315 #ifdef USE_MULTITHREADCAPTURE
316 assert(false && "don't call myRetrieveFrame when USE_MULTITHREADCAPTURE");
317 #endif
319 static IplImage *s=0;
320 IplImage *frame =cvRetrieveFrame(capture);
321 if (frame == 0) return 0;
322 IplImage *ret=frame;
323 if (frame->nChannels==1) {
324 printf(" PERFORMANCE WARNING: myRetrieveFrame converting colour\n");
325 if (!s) s=cvCreateImage(cvSize(frame->width,frame->height), IPL_DEPTH_8U, 3);
326 cvCvtColor(frame,s,CV_GRAY2BGR);
327 ret = s;
329 if (ret->origin) {
330 printf(" PERFORMANCE WARNING: myRetrieveFrame flipping\n");
331 if (!s) s=cvCreateImage(cvSize(frame->width,frame->height), IPL_DEPTH_8U, 3);
332 cvFlip(ret, s);
333 ret->origin=0;
334 ret = s;
336 return ret;
339 IplImage *myQueryFrame(CvCapture *capture)
341 #ifdef USE_MULTITHREADCAPTURE
342 assert(false && "don't call myQueryFrame when USE_MULTITHREADCAPTURE");
343 #endif
345 cvGrabFrame(capture);
346 return myRetrieveFrame(capture);
350 bool CalibModel::interactiveTrainBinoculars()
352 // setup
353 state = TAKE_SHOT;
354 train_should_proceed = false;
355 // we want the interactive training to run
356 interactive_train_running = true;
357 interactive_train_should_stop = false;
358 debounce_green = true;
359 debounce_redblue = true;
361 // wait until done
362 int timeout =5*60;
363 // 5 minute time out
364 while ( interactive_train_running && !interactive_train_should_stop && timeout>0 )
366 printf("waiting for interactiveTrainBinoculars to complete .. %i\n", timeout );
367 timeout-=5;
368 sleep(5);
371 return train_should_proceed;
374 void CalibModel::interactiveTrainBinocularsUpdate( IplImage* frame,
375 bool button_red,
376 bool button_green,
377 bool button_blue )
379 if ( !interactive_train_running )
380 return;
382 if ( interactive_train_should_stop )
384 interactive_train_running = false;
385 return;
388 // copy to training
389 if ( train_working_image == 0 )
391 train_working_image = cvCreateImage( cvGetSize( frame ), frame->depth, frame->nChannels );
392 train_shot = cvCreateImage( cvGetSize( frame ), frame->depth, frame->nChannels );
395 // inputs
396 bool R__ = ( button_red&&!button_green&&!button_blue);
397 bool _G_ = (!button_red&& button_green&&!button_blue);
398 bool __B = (!button_red&&!button_green&& button_blue);
399 bool RG_ = ( button_red&& button_green&&!button_blue);
400 bool _GB = (!button_red&& button_green&& button_blue);
401 bool R_B = ( button_red&&!button_green&& button_blue);
402 bool RGB = ( button_red&& button_green&& button_blue);
404 // debounce
406 // don't allow just green if we're trying to debounce
407 if ( !button_green )
408 debounce_green = false;
409 else if ( debounce_green && _G_ )
410 _G_ = false;
412 // don't allow red+blue if we're trying to debounce
413 if ( !button_red || !button_blue )
414 debounce_redblue = false;
415 else if ( debounce_redblue && R_B )
416 R_B = false;
418 // for drawing
419 int four = 4;
420 CvPoint *ptr;
421 int oldx, oldy;
423 // update
424 switch( state )
426 case TAKE_SHOT:
427 if ( _G_ )
429 // advance
430 cvCopy( frame, train_shot );
431 state = CORNERS;
432 int d = 30;
433 corners[0].x = d;
434 corners[0].y = d;
435 corners[1].x = frame->width-d;
436 corners[1].y = d;
437 corners[2].x = frame->width-d;
438 corners[2].y = frame->height-d;
439 corners[3].x = d;
440 corners[3].y = frame->height-d;
441 // setup index
442 corner_index=0;
443 x = corners[corner_index].x;
444 y = corners[corner_index].y;
445 // debounce the green button
446 debounce_green = true;
448 else if ( R_B )
450 // abort
451 interactive_train_running = false;
452 debounce_redblue = true;
454 else
456 cvCopy( frame, train_working_image );
457 putText(train_working_image, modelfile, cvPoint(3,20), &train_font );
458 putText(train_working_image,"Please take a frontal view", cvPoint(3,40), &train_font);
459 putText(train_working_image,"of a textured planar surface", cvPoint(3,60), &train_font);
460 putText(train_working_image,"and press green", cvPoint(3,80), &train_font);
461 putText(train_working_image,"Press red+blue to abort", cvPoint(3,100), &train_font);
463 break;
464 case CORNERS:
465 cvCopy( train_shot, train_working_image );
466 putText(train_working_image, modelfile, cvPoint(3,20), &train_font);
467 putText(train_working_image, "Move green corners to match the", cvPoint(3,40), &train_font);
468 putText(train_working_image, "calibration target", cvPoint(3,60), &train_font);
469 putText(train_working_image, "Press red+blue to restart", cvPoint(3,80), &train_font);
470 putText(train_working_image, "Press green when ready", cvPoint(3,100), &train_font);
472 oldx=x; oldy=y;
473 if ( R__ )
474 x += 1;
475 else if ( __B )
476 x -= 1;
477 else if ( RG_ )
478 y += 1;
479 else if ( _GB )
480 y -= 1;
481 // update corner if necessary
482 if ( oldx != x )
483 corners[corner_index].x = x;
484 if ( oldy != y )
485 corners[corner_index].y = y;
486 // continue checking buttons
487 if ( _G_ )
489 // accept
490 corners[corner_index].x = x;
491 corners[corner_index].y = y;
492 corner_index++;
493 if ( corner_index > 3 )
495 // next
496 corner_index = 0;
497 for ( int i=0; i<4; i++ )
498 artvert_corners[i] = corners[i];
499 state = ARTVERT_CORNERS;
501 // setup index
502 corner_index=0;
503 x = artvert_corners[corner_index].x;
504 y = artvert_corners[corner_index].y;
506 else
508 x = corners[corner_index].x;
509 y = corners[corner_index].y;
512 debounce_green = true;
514 else if ( R_B )
516 // back
517 corner_index--;
518 if ( corner_index < 0 )
519 state = TAKE_SHOT;
520 else
522 x = corners[corner_index].x;
523 y = corners[corner_index].y;
525 debounce_redblue = true;
528 ptr = corners;
529 cvPolyLine(train_working_image, &ptr, &four, 1, 1,
530 cvScalar(0,255,0));
531 cvCircle( train_working_image, corners[corner_index], 10, cvScalar(0,255,0));
533 break;
535 case ARTVERT_CORNERS:
536 cvCopy( train_shot, train_working_image );
537 putText(train_working_image, modelfile, cvPoint(3,20), &train_font);
538 putText(train_working_image, "Move red corners to match the", cvPoint(3,40), &train_font);
539 putText(train_working_image, "artvert target area;", cvPoint(3,60), &train_font);
540 putText(train_working_image, "Press red+blue to restart", cvPoint(3,80), &train_font);
541 putText(train_working_image, "Press green when ready", cvPoint(3,100), &train_font);
543 oldx = x; oldy = y;
544 if ( R__ )
545 x += 1;
546 else if ( __B )
547 x -= 1;
548 else if ( RG_ )
549 y += 1;
550 else if ( _GB )
551 y -= 1;
552 // update corner if necessary
553 if ( oldx != x )
554 artvert_corners[corner_index].x = x;
555 if ( oldy != y )
556 artvert_corners[corner_index].y = y;
557 // continue checking buttons
558 if ( _G_ )
560 // accept
561 artvert_corners[corner_index].x = x;
562 artvert_corners[corner_index].y = y;
563 corner_index++;
564 if ( corner_index > 3 )
566 // finished
567 if ( image != 0 )
568 cvReleaseImage( &image );
569 image = cvCreateImage( cvGetSize( train_shot), train_shot->depth, train_shot->nChannels );
570 cvCopy( train_shot, image );
571 train_should_proceed = true;
572 interactive_train_running = false;
574 else
576 x = artvert_corners[corner_index].x;
577 y = artvert_corners[corner_index].y;
579 debounce_green = true;
581 else if ( R_B )
583 // back
584 corner_index--;
585 if ( corner_index < 0 )
586 state = CORNERS;
587 else
589 x = artvert_corners[corner_index].x;
590 y = artvert_corners[corner_index].y;
592 debounce_redblue = true;
596 ptr = corners;
597 cvPolyLine(train_working_image, &ptr, &four, 1, 1,
598 cvScalar(0,255,0));
599 ptr = artvert_corners;
600 cvPolyLine(train_working_image, &ptr, &four, 1, 1,
601 cvScalar(0,0,255));
602 cvCircle( train_working_image, artvert_corners[corner_index], 10, cvScalar(0,0,255));
604 break;
607 train_texture.setImage( train_working_image );
611 void CalibModel::interactiveTrainBinocularsDraw()
613 if ( !interactive_train_running )
614 return;
616 IplTexture* tex = &train_texture;
618 IplImage *im = tex->getIm();
619 int w = im->width-1;
620 int h = im->height-1;
622 glMatrixMode(GL_PROJECTION);
623 glLoadIdentity();
624 glMatrixMode(GL_MODELVIEW);
625 glLoadIdentity();
627 glDisable(GL_BLEND);
628 glDisable(GL_DEPTH_TEST);
630 tex->loadTexture();
632 glBegin(GL_QUADS);
633 glColor4f(1,1,1,1);
635 glTexCoord2f(tex->u(0), tex->v(0));
636 glVertex2f(-1, 1);
637 glTexCoord2f(tex->u(w), tex->v(0));
638 glVertex2f(1, 1);
639 glTexCoord2f(tex->u(w), tex->v(h));
640 glVertex2f(1, -1);
641 glTexCoord2f(tex->u(0), tex->v(h));
642 glVertex2f(-1, -1);
643 glEnd();
645 tex->disableTexture();
650 bool CalibModel::interactiveSetup(CvCapture *capture )
656 CvFont font, fontbold;
658 cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, .5, .5, 0, 0, CV_AA);
660 cvNamedWindow(win, CV_WINDOW_AUTOSIZE);
661 grab=-1;
663 objectPtr = this;
664 cvSetMouseCallback(win, onMouseStatic, this);
666 bool pause=false;
668 IplImage *frame_gray, *frame = NULL;
669 FTime timestamp;
670 MultiThreadCapture* mtc = MultiThreadCaptureManager::getInstance()->getCaptureForCam(capture);
671 int timeout = 10000;
672 bool got = false;
673 do {
674 got = mtc->getLastDetectFrame( &frame_gray, &frame, &timestamp, /*blocking*/true );
676 while ( !got &&
677 !usleep( 100000 ) &&
678 (timeout-=100) > 0 );
679 if ( frame == NULL )
681 printf("capture failed\n");
682 return false;
685 IplImage *shot=0, *text=0;
687 state = TAKE_SHOT;
689 bool accepted =false;
690 bool artvert_accepted = false;
691 while (!accepted) {
693 // wait for a key
694 char k = cvWaitKey(10);
696 if (k==27 || k=='q') {
697 if (shot) cvReleaseImage(&shot);
698 if (text) cvReleaseImage(&text);
699 return false;
702 // clear text or grab the image to display
703 if (!pause || shot==0) {
704 bool got = mtc->getLastDetectFrame( &frame_gray, &frame, NULL,/*block until available*/true );
705 if ( !got )
706 continue;
707 if (!text) {
708 text=cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);
709 int d = 30;
710 corners[0].x = d;
711 corners[0].y = d;
712 corners[1].x = frame->width-d;
713 corners[1].y = d;
714 corners[2].x = frame->width-d;
715 corners[2].y = frame->height-d;
716 corners[3].x = d;
717 corners[3].y = frame->height-d;
719 if (frame->nChannels==1)
720 cvCvtColor(frame, text, CV_GRAY2BGR);
721 else
722 cvCopy(frame,text);
723 } else {
724 if (shot->nChannels==1)
725 cvCvtColor(shot, text, CV_GRAY2BGR);
726 else
727 cvCopy(shot, text);
730 int four = 4;
731 CvPoint *ptr;
732 // display text / react to keyboard
733 switch (state) {
734 default:
735 case TAKE_SHOT:
736 if (k==' ') {
737 if (shot) cvCopy(frame,shot);
738 else shot = cvCloneImage(frame);
739 pause = true;
740 state = CORNERS;
741 k=-1;
742 } else {
743 putText(text, modelfile, cvPoint(3,20), &font);
744 putText(text,"Please take a frontal view", cvPoint(3,40), &font);
745 putText(text,"of a textured planar surface", cvPoint(3,60), &font);
746 putText(text,"and press space", cvPoint(3,80), &font);
747 break;
749 case CORNERS:
750 putText(text, modelfile, cvPoint(3,20), &font);
751 putText(text, "Drag green corners to match the", cvPoint(3,40), &font);
752 putText(text, "calibration target", cvPoint(3,60), &font);
753 putText(text, "press 'r' to restart", cvPoint(3,80), &font);
754 putText(text, "press space when ready", cvPoint(3,100), &font);
755 if (k=='r') {
756 pause = false;
757 state = TAKE_SHOT;
759 if (k==' ') {
760 for ( int i=0;i<4; i++ )
762 artvert_corners[i].x = corners[i].x;
763 artvert_corners[i].y = corners[i].y;
765 state = ARTVERT_CORNERS;
767 ptr = corners;
768 cvPolyLine(text, &ptr, &four, 1, 1,
769 cvScalar(0,255,0));
770 break;
771 case ARTVERT_CORNERS:
772 putText(text, "Drag red corners to match the", cvPoint(3,20), &font);
773 putText(text, "artvert target area;", cvPoint(3,40), &font);
774 putText(text, "press 'r' to restart", cvPoint(3,60), &font);
775 putText(text, "press space when ready", cvPoint(3,80), &font);
776 if (k=='r') {
777 pause = false;
778 state = TAKE_SHOT;
780 if (k==' ') {
781 accepted = true;
783 ptr = corners;
784 cvPolyLine(text, &ptr, &four, 1, 1,
785 cvScalar(0,255,0));
786 ptr = artvert_corners;
787 cvPolyLine(text, &ptr, &four, 1, 1,
788 cvScalar(0,0,255));
789 break;
791 cvShowImage(win, text);
794 cvReleaseImage(&text);
795 image = shot;
797 cvDestroyWindow( win );
798 // make sure the destroy window succeeds
799 cvWaitKey(0);
801 return true;
804 void CalibModel::onMouseStatic(int event, int x, int y, int flags, void* param)
806 if (param)
807 ((CalibModel *)param)->onMouse(event,x,y,flags);
808 if (objectPtr)
809 objectPtr->onMouse(event,x,y,flags);
810 else
811 cerr << "onMouseStatic(): null-pointer.\n";
815 void CalibModel::learnProgressionFunc( int phase, int current, int total )
817 sprintf(progress_string, "learning, phase %i/4: %4.1f%%", phase+1, 100.0f*float(current)/total );
818 if ( current==0 )
819 printf("\n");
820 printf("\rphase %i/4: %4i/%4i ", phase+1, current, total);
821 fflush(stdout);
823 /*for ( int i=0; i<4; i++ )
825 if ( phase > i )
826 strcat(progress_string, "[----------------------------------------]\n" );
827 else if ( phase == i )
829 float finishedPct = float(current)/float(total);
830 int count = finishedPct*40;
831 strcat(progress_string, "[");
832 for ( int j=0; j<count; j++ )
834 strcat(progress_string, "-");
836 for ( int j=0; j<40-count; j++ )
838 strcat(progress_string, " ");
840 strcat(progress_string, "]\n");
842 else
843 strcat( progress_string, "[ ]\n");