compiles and seems to run; not properly tested
[The-Artvertiser.git] / artvertiser / calibmodel.cpp
blob07a24028c78e2125ef3bb29d122dddfb8f1e81f8
1 #include "calibmodel.h"
2 #include "multigrab.h"
4 CalibModel::CalibModel()
6 image=0;
7 image_width = 0;
8 image_height = 0;
9 win = "The Artvertiser 0.4";
12 CalibModel::~CalibModel()
14 if (image) cvReleaseImage(&image);
17 void CalibModel::useModelFile(const char* file)
19 modelfile = file;
22 CalibModel *objectPtr=0;
24 void CalibModel::onMouse(int event, int x, int y, int flags)
26 CvPoint* ptr;
27 if ( state == ARTVERT_CORNERS )
28 ptr = artvert_corners;
29 else
30 ptr = corners;
31 if (event == CV_EVENT_LBUTTONDOWN)
33 // try to grab something
34 grab = -1;
35 for (int i=0; i<4; i++)
37 int dx = x-ptr[i].x;
38 int dy = y-ptr[i].y;
39 if (sqrt((double)(dx*dx+dy*dy)) <10) {
40 grab = i;
41 break;
46 if (grab!=-1)
48 ptr[grab].x = x;
49 ptr[grab].y = y;
52 if (event == CV_EVENT_LBUTTONUP)
54 grab=-1;
58 bool CalibModel::buildCached(int nbcam, CvCapture *capture, bool cache, planar_object_recognizer &detector, bool dont_try_to_train )
60 detector.clear();
62 detector.lock();
64 detector.ransac_dist_threshold = 5;
65 detector.max_ransac_iterations = 800;
66 //detector.ransac_stop_support = 50;
67 //detector.non_linear_refine_threshold = 15.0f;
68 //detector.point_detector_tau = 10;
70 // A lower threshold will allow detection in harder conditions, but
71 // might lead to false positives.
72 detector.match_score_threshold=.03f;
74 detector.min_view_rate=.1;
75 detector.views_number = 1000;
76 // damian below
77 //detector.min_view_rate = .2;
79 static const int MAX_MODEL_KEYPOINTS = 500; // maximum number of keypoints on the model
80 static const int PATCH_SIZE = 32; // patch size in pixels
81 static const int YAPE_RADIUS = 5; // yape radius
82 static const int NUM_TREES = 12; // num classifier trees
83 static const int NUM_GAUSSIAN_LEVELS = 3; // num gaussian levels
84 /*static const int MAX_MODEL_KEYPOINTS = 500; // maximum number of keypoints on the model
85 static const int PATCH_SIZE = 32; // patch size in pixels
86 static const int YAPE_RADIUS = 5; // yape radius
87 static const int NUM_TREES = 12; // num classifier trees
88 static const int NUM_GAUSSIAN_LEVELS = 3; // num gaussian levels*/
91 // Should we train or load the classifier ?
92 if ( cache )
93 printf("model.buildCached() trying to load from %s...\n", modelfile );
94 if(cache && detector.build_with_cache(
95 string(modelfile), // mode image file name
96 /*500, // maximum number of keypoints on the model
97 //200, // maximum number of keypoints on the model
98 32, // patch size in pixels
99 5, // yape radius. Use 3,5 or 7.
100 //3, // yape radius. Use 3,5 or 7.
101 12, // number of trees for the classifier. Somewhere between 12-50
102 //20, // number of trees for the classifier. Somewhere between 12-50
103 3*/ // number of levels in the gaussian pyramid
104 // damian below
105 MAX_MODEL_KEYPOINTS, // max keypoints
106 PATCH_SIZE, // patch size
107 YAPE_RADIUS, // yape radius. Use 3,5 or 7.
108 NUM_TREES, // number of trees for the classifier. Somewhere between 12-50
109 NUM_GAUSSIAN_LEVELS // number of levels in the gaussian pyramid
113 // loading worked. Remember the region of interest.
114 corners[0].x = detector.new_images_generator.u_corner1;
115 corners[0].y = detector.new_images_generator.v_corner1;
116 corners[1].x = detector.new_images_generator.u_corner2;
117 corners[1].y = detector.new_images_generator.v_corner2;
118 corners[2].x = detector.new_images_generator.u_corner3;
119 corners[2].y = detector.new_images_generator.v_corner3;
120 corners[3].x = detector.new_images_generator.u_corner4;
121 corners[3].y = detector.new_images_generator.v_corner4;
123 MultiThreadCapture* mtc = MultiThreadCaptureManager::getInstance()->getCaptureForCam(capture);
125 IplImage* init_image = NULL;
126 int timeout = 10000;
127 bool got = false;
128 do {
129 got = mtc->getCopyOfLastFrame( &init_image );
131 while ( !got &&
132 !usleep( 10*1000 ) &&
133 (timeout-=10) > 0 );
134 if ( init_image == NULL )
136 printf("getCopyOfLastFrame timed out: capture failed\n");
137 detector.unlock();
138 detector.clear();
139 return false;
141 if ( image != 0 )
142 cvReleaseImage( &image );
143 image = cvLoadImage(modelfile, mtc->getNumChannelsRaw()==3 );
144 image_width = image->width;
145 image_height = image->height;
146 //cvReleaseImage(&init_image);
148 /*printf("dumping loaded cache:\n");
149 detector.dump();
153 else
155 if ( image != 0 )
156 cvReleaseImage( &image );
157 image =0;
158 // ask the user the take a shot of the model
159 if ( !cache && dont_try_to_train )
161 printf("CalibModel: would normally try to train now but we were told not to\n");
162 detector.clear();
163 detector.unlock();
164 return false;
166 if (!interactiveSetup(capture))
168 printf("interactiveSetup failed\n");
169 detector.unlock();
170 detector.clear();
171 return false;
174 image_width = image->width;
175 image_height = image->height;
177 // train the classifier to detect this model
178 //if (!detector.build(image, 500, 32, 3, 12, 3,0, 0))
179 //if (!detector.build(image, 200, 32, 5, 20, 3,0, 0))
180 int working_roi[8] = { corners[0].x, corners[0].y,
181 corners[1].x, corners[1].y,
182 corners[2].x, corners[2].y,
183 corners[3].x, corners[3].y
185 LEARNPROGRESSION progress;
186 if (!detector.build(image,
187 MAX_MODEL_KEYPOINTS, // max keypoints
188 PATCH_SIZE, // patch size
189 YAPE_RADIUS, // yape radius. Use 3,5 or 7.
190 NUM_TREES, // number of trees for the classifier. Somewhere between 12-50
191 NUM_GAUSSIAN_LEVELS, // number of levels in the gaussian pyramid
192 progress,
193 working_roi
196 printf("build based on interactiveSetup failed\n");
197 detector.unlock();
198 detector.clear();
199 return false;
203 // save the image
204 if (!cvSaveImage(modelfile, image))
206 printf("saving input image failed\n");
207 detector.unlock();
208 detector.clear();
209 return false;
212 // and the region of interest (ROI)
213 string roifn = string(modelfile) + ".roi";
214 ofstream roif(roifn.c_str());
215 if (!roif.good())
217 detector.unlock();
218 detector.clear();
219 printf("saving .roi file failed\n");
220 return false;
222 for (int i=0;i<4; i++)
223 roif << corners[i].x << " " << corners[i].y << "\n";
224 roif.close();
226 // and the artvert corners
227 roifn = string(modelfile) + ".artvertroi";
228 ofstream artvert_roif(roifn.c_str());
229 if (!artvert_roif.good())
231 detector.unlock();
232 detector.clear();
233 printf("saving .artvertroi file failed\n");
234 return false;
236 for (int i=0;i<4; i++)
237 artvert_roif << artvert_corners[i].x << " " << artvert_corners[i].y << "\n";
238 artvert_roif.close();
240 // and the trained classifier
241 string classifier_directory = string(modelfile)+".classifier";
242 detector.save(classifier_directory);
244 string stable_points_filename = string(modelfile)+"_stable_points.bmp";
245 printf("saving stable points to %s\n", stable_points_filename.c_str());
246 detector.save_image_of_model_points(PATCH_SIZE, stable_points_filename.c_str() );
248 const char* initial_points_filename = "initial_model_points.bmp";
249 string initial_points_new_filename = string(modelfile)+"_initial_points.bmp";
250 printf("renaming %s to %s\n", initial_points_filename, initial_points_new_filename.c_str() );
251 rename(initial_points_filename, initial_points_new_filename.c_str() );
253 /*printf("dumping trained cache:\n");
254 detector.dump();*/
258 detector.unlock();
259 assert( detector.isReady() );
261 float cn[4][2];
262 for (int i=0; i<4; i++)
264 cn[i][0] = corners[i].x;
265 cn[i][1] = corners[i].y;
266 cout << corners[i].x << " " << corners[i].y << endl;
269 // prepare the light calibration reference
270 return map.init(nbcam, image, cn, 8, 6);
273 static void putText(IplImage *im, const char *text, CvPoint p, CvFont *f1)
275 cvPutText(im,text,p,f1, cvScalar(0,255, 255));
279 IplImage *myRetrieveFrame(CvCapture *capture)
281 #ifdef USE_MULTITHREADCAPTURE
282 assert(false && "don't call myRetrieveFrame when USE_MULTITHREADCAPTURE");
283 #endif
285 static IplImage *s=0;
286 IplImage *frame =cvRetrieveFrame(capture);
287 if (frame == 0) return 0;
288 IplImage *ret=frame;
289 if (frame->nChannels==1) {
290 printf(" PERFORMANCE WARNING: myRetrieveFrame converting colour\n");
291 if (!s) s=cvCreateImage(cvSize(frame->width,frame->height), IPL_DEPTH_8U, 3);
292 cvCvtColor(frame,s,CV_GRAY2BGR);
293 ret = s;
295 if (ret->origin) {
296 printf(" PERFORMANCE WARNING: myRetrieveFrame flipping\n");
297 if (!s) s=cvCreateImage(cvSize(frame->width,frame->height), IPL_DEPTH_8U, 3);
298 cvFlip(ret, s);
299 ret->origin=0;
300 ret = s;
302 return ret;
305 IplImage *myQueryFrame(CvCapture *capture)
307 #ifdef USE_MULTITHREADCAPTURE
308 assert(false && "don't call myQueryFrame when USE_MULTITHREADCAPTURE");
309 #endif
311 cvGrabFrame(capture);
312 return myRetrieveFrame(capture);
317 bool CalibModel::interactiveSetup(CvCapture *capture )
320 CvFont font, fontbold;
322 cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, .5, .5, 0, 0, CV_AA);
324 cvNamedWindow(win, CV_WINDOW_AUTOSIZE);
325 grab=-1;
327 objectPtr = this;
328 cvSetMouseCallback(win, onMouseStatic, this);
330 bool pause=false;
331 #ifdef USE_MULTITHREADCAPTURE
332 IplImage *frame_gray, *frame = NULL;
333 FTime timestamp;
334 MultiThreadCapture* mtc = MultiThreadCaptureManager::getInstance()->getCaptureForCam(capture);
335 int timeout = 10000;
336 bool got = false;
337 do {
338 got = mtc->getLastDetectFrame( &frame_gray, &frame, &timestamp, /*blocking*/true );
340 while ( !got &&
341 !usleep( 100000 ) &&
342 (timeout-=100) > 0 );
343 if ( frame == NULL )
345 printf("capture failed\n");
346 return false;
348 #else
349 IplImage *frame = myQueryFrame(capture);
350 #endif
351 IplImage *shot=0, *text=0;
353 state = TAKE_SHOT;
355 bool accepted =false;
356 bool artvert_accepted = false;
357 while (!accepted) {
359 // wait for a key
360 char k = cvWaitKey(10);
362 if (k==27 || k=='q') {
363 if (shot) cvReleaseImage(&shot);
364 if (text) cvReleaseImage(&text);
365 return false;
368 // clear text or grab the image to display
369 if (!pause || shot==0) {
370 #ifdef USE_MULTITHREADCAPTURE
371 bool got = mtc->getLastDetectFrame( &frame_gray, &frame, NULL,/*block until available*/true );
372 if ( !got )
373 continue;
374 #else
375 frame = myQueryFrame(capture);
376 #endif
377 if (!text) {
378 text=cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);
379 int d = 30;
380 corners[0].x = d;
381 corners[0].y = d;
382 corners[1].x = frame->width-d;
383 corners[1].y = d;
384 corners[2].x = frame->width-d;
385 corners[2].y = frame->height-d;
386 corners[3].x = d;
387 corners[3].y = frame->height-d;
389 if (frame->nChannels==1)
390 cvCvtColor(frame, text, CV_GRAY2BGR);
391 else
392 cvCopy(frame,text);
393 } else {
394 if (shot->nChannels==1)
395 cvCvtColor(shot, text, CV_GRAY2BGR);
396 else
397 cvCopy(shot, text);
400 int four = 4;
401 CvPoint *ptr;
402 // display text / react to keyboard
403 switch (state) {
404 default:
405 case TAKE_SHOT:
406 if (k==' ') {
407 if (shot) cvCopy(frame,shot);
408 else shot = cvCloneImage(frame);
409 pause = true;
410 state = CORNERS;
411 k=-1;
412 } else {
413 putText(text, modelfile, cvPoint(3,20), &font);
414 putText(text,"Please take a frontal view", cvPoint(3,40), &font);
415 putText(text,"of a textured planar surface", cvPoint(3,60), &font);
416 putText(text,"and press space", cvPoint(3,80), &font);
417 break;
419 case CORNERS:
420 putText(text, modelfile, cvPoint(3,20), &font);
421 putText(text, "Drag yellow corners to match the", cvPoint(3,40), &font);
422 putText(text, "calibration target", cvPoint(3,60), &font);
423 putText(text, "press 'r' to restart", cvPoint(3,80), &font);
424 putText(text, "press space when ready", cvPoint(3,100), &font);
425 if (k=='r') {
426 pause = false;
427 state = TAKE_SHOT;
429 if (k==' ') {
430 for ( int i=0;i<4; i++ )
432 artvert_corners[i].x = corners[i].x;
433 artvert_corners[i].y = corners[i].y;
435 state = ARTVERT_CORNERS;
437 ptr = corners;
438 cvPolyLine(text, &ptr, &four, 1, 1,
439 cvScalar(0,255,0));
440 break;
441 case ARTVERT_CORNERS:
442 putText(text, "Drag red corners to match the", cvPoint(3,20), &font);
443 putText(text, "artvert target area;", cvPoint(3,40), &font);
444 putText(text, "press 'r' to restart", cvPoint(3,60), &font);
445 putText(text, "press space when ready", cvPoint(3,80), &font);
446 if (k=='r') {
447 pause = false;
448 state = TAKE_SHOT;
450 if (k==' ') {
451 accepted = true;
453 ptr = corners;
454 cvPolyLine(text, &ptr, &four, 1, 1,
455 cvScalar(0,255,0));
456 ptr = artvert_corners;
457 cvPolyLine(text, &ptr, &four, 1, 1,
458 cvScalar(0,0,255));
459 break;
461 cvShowImage(win, text);
464 cvReleaseImage(&text);
465 image = shot;
467 cvDestroyWindow( win );
468 // make sure the destroy window succeeds
469 cvWaitKey(0);
471 return true;
474 void CalibModel::onMouseStatic(int event, int x, int y, int flags, void* param)
476 if (param)
477 ((CalibModel *)param)->onMouse(event,x,y,flags);
478 if (objectPtr)
479 objectPtr->onMouse(event,x,y,flags);
480 else
481 cerr << "onMouseStatic(): null-pointer.\n";