Fawkes API Fawkes Development Version
surf.cpp
1
2/***************************************************************************
3 * surf.cpp - SURF based classifier
4 *
5 * Created: Tue Apr 01 10:15:23 2008
6 * Copyright 2008 Stefan Schiffer [stefanschiffer.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24#include <fvclassifiers/surf.h>
25
26#include <iostream>
27#include <math.h>
28#include <vector>
29//#ifdef SURF_TIMETRACKER
30#include <utils/time/clock.h>
31#include <utils/time/tracker.h>
32//#endif
33#include <surf/surflib.h>
34
35#include <fstream>
36#include <string>
37//#include <surf/ipoint.h>
38//#include <surf/image.h>
39//#include <surf/imload.h>
40
41#include <core/exception.h>
42#include <core/exceptions/software.h>
43#include <fvutils/color/colorspaces.h>
44#include <fvutils/color/conversions.h>
45#include <fvutils/readers/png.h>
46#include <utils/logging/liblogger.h>
47#include <utils/system/console_colors.h>
48
49#include <dirent.h>
50
51#define BVERBOSE true
52
53//#include <fvutils/writers/pnm.h>
54//#include <fvutils/writers/png.h>
55
56namespace firevision {
57
58/** @class SurfClassifier <fvclassifiers/surf.h>
59 * SURF classifier.
60 *
61 * This class provides a classifier that uses SURF to detect objects in a given
62 * image by matching features. The objects are reported back as regions of interest.
63 * Each ROI contains an object. ROIs with 11x11 are matched features.
64 *
65 * This code uses libSurf from http://www.vision.ee.ethz.ch/~surf/
66 * and is partly based on code from their package.
67 *
68 * @author Stefan Schiffer
69 */
70
71/** saveIpoints
72 * save Surf points
73 * @param sFileName surf file name
74 * @param ipts surf ipoints (surf::iPoint)
75 * @param bVerbose verbose mode
76 * @param bLaplacian laplacian mode
77 */
78
79void
80saveIpoints(std::string sFileName,
81 const std::vector<surf::Ipoint> &ipts,
82 bool bVerbose,
83 bool bLaplacian,
84 int VLength)
85{
86 std::cout << "Attempting to save interest points" << std::endl;
87
88 std::ofstream ipfile(sFileName.c_str());
89 if (!ipfile) {
90 std::cerr << "ERROR in loadIpoints(): "
91 << "Couldn't open file '" << sFileName.c_str() << "'!" << std::endl; //STS
92 return;
93 }
94
95 double sc;
96 unsigned count = ipts.size();
97
98 // Write the file header
99 if (bLaplacian)
100 ipfile << VLength + 1 << std::endl << count << std::endl;
101 else
102 ipfile << VLength << std::endl << count << std::endl;
103 // In order to just save the interest points without descriptor, comment
104 // the above and uncomment the following command.
105 // ipfile << 1.0 << std::endl << count << std::endl;
106 // Save interest point with descriptor in the format of Krystian Mikolajczyk
107 // for reasons of comparison with other descriptors. As our interest points
108 // are circular in any case, we use the second component of the ellipse to
109 // provide some information about the strength of the interest point. This is
110 // important for 3D reconstruction as only the strongest interest points are
111 // considered. Replace the strength with 0.0 in order to perform Krystian's
112 // comparisons.
113 for (unsigned n = 0; n < ipts.size(); n++) {
114 // circular regions with diameter 5 x scale
115 sc = 2.5 * ipts[n].scale;
116 sc *= sc;
117 ipfile << ipts[n].x /* x-location of the interest point */
118 << " " << ipts[n].y /* y-location of the interest point */
119 << " " << 1.0 / sc /* 1/r^2 */
120 << " " << 0.0 //(*ipts)[n]->strength /* 0.0 */
121 << " " << 1.0 / sc; /* 1/r^2 */
122
123 if (bLaplacian)
124 ipfile << " " << ipts[n].laplace;
125
126 // Here comes the descriptor
127 for (int i = 0; i < VLength; i++) {
128 ipfile << " " << ipts[n].ivec[i];
129 }
130 ipfile << std::endl;
131 }
132
133 // Write message to terminal.
134 if (bVerbose)
135 std::cout << count << " interest points found" << std::endl;
136}
137
138/** loadIpoints
139 * load interest points
140 * @param sFileName location of the interest points
141 * @param ipts vector to store interest points
142 * @param bVerbose if the saveIpoints was carried out with verbose mode
143 */
144void
145loadIpoints(std::string sFileName, std::vector<surf::Ipoint> &ipts, bool bVerbose, int &vlen_)
146{
147 std::ifstream ipfile(sFileName.c_str());
148
149 if (!ipfile) {
150 std::cerr << "ERROR in loadIpoints(): "
151 << "Couldn't open file '" << sFileName.c_str() << "'!" << std::endl; //STS
152 return;
153 }
154
155 // Load the file header
156
157 unsigned count;
158 ipfile >> vlen_ >> count;
159
160 vlen_--;
161
162 // create a new interest point vector
163 ipts.clear();
164 ipts.resize(count);
165
166 // Load the interest points in Mikolajczyk's format
167 for (unsigned n = 0; n < count; n++) {
168 // circular regions with diameter 5 x scale
169 float x, y, a, b, c;
170 ipfile >> x >> y >> a >> b >> c;
171
172 float det = sqrt((a - c) * (a - c) + 4.0 * b * b);
173 float e1 = 0.5 * (a + c + det);
174 float e2 = 0.5 * (a + c - det);
175 float l1 = (1.0 / sqrt(e1));
176 float l2 = (1.0 / sqrt(e2));
177 float sc = sqrt(l1 * l2);
178
179 ipts[n].x = x;
180 ipts[n].y = y;
181 ipts[n].scale = sc / 2.5;
182 ipfile >> ipts[n].laplace;
183
184 //ipts[n].allocIvec( VLength );
185 ipts[n].ivec = new double[vlen_];
186
187 for (int j = 0; j < vlen_; j++) {
188 ipfile >> ipts[n].ivec[j];
189
190 // std::cout << ipts[n].ivec[j] << " ";
191 }
192 }
193
194 // close the interest point file again
195 ipfile.close();
196
197 // Write message to terminal.
198 if (bVerbose)
199 std::cout << "read in " << count << " interest points." << std::endl;
200}
201
202/** Constructor.
203 * @param keypoints_dir location of the keypoints (descriptor file as a txt file) for the reference objects
204 * @param samplingStep Initial sampling step
205 * @param min_match minimum number of features that have to be matched per ROI
206 * @param min_match_ratio minimum ratio of features matched per object to be matched per ROI
207 * @param octaves Number of analysed octaves
208 * @param thres Blob response treshold
209 * @param doubleImageSize true to double the image size, false to keep original
210 * @param initLobe Initial lobe size, default 3 and 5 (with double image size)
211 * @param upright rotation invariance (fasle) or upright (true)
212 * @param extended true to use the extended descriptor (SURF 128)
213 * @param indexSize Spatial size of the descriptor window (default 4)
214
215 */
216SurfClassifier::SurfClassifier(std::string keypoints_dir,
217 unsigned int min_match,
218 float min_match_ratio,
219 int samplingStep,
220 int octaves,
221 double thres,
222 bool doubleImageSize,
223 int initLobe,
224 bool upright,
225 bool extended,
226 int indexSize)
227: Classifier("SurfClassifier")
228{
229 obj_features_.clear();
230 obj_features_.reserve(1000);
231 // matching constraints
232 min_match_ = min_match;
233 min_match_ratio_ = min_match_ratio;
234 // params for FastHessian
235 samplingStep_ = samplingStep;
236 octaves_ = octaves;
237 thres_ = thres;
238 doubleImageSize_ = doubleImageSize;
239 initLobe_ = initLobe;
240 // params for Descriptors
241 upright_ = upright;
242 extended_ = extended;
243 indexSize_ = indexSize;
244
245 // descriptor vector length
246 vlen_ = 0;
247
248 //#ifdef SURF_TIMETRACKER
249 tt_ = new fawkes::TimeTracker();
250 loop_count_ = 0;
251 ttc_objconv_ = tt_->add_class("ObjectConvert");
252 ttc_objfeat_ = tt_->add_class("ObjectFeatures");
253 ttc_imgconv_ = tt_->add_class("ImageConvert");
254 ttc_imgfeat_ = tt_->add_class("ImageFeatures");
255 ttc_matchin_ = tt_->add_class("Matching");
256 ttc_roimerg_ = tt_->add_class("MergeROIs");
257 //#endif
258
259 //#ifdef SURF_TIMETRACKER
260 tt_->ping_start(ttc_objconv_);
261 //#endif
262
263 DIR *dir = 0;
264
265 if ((dir = opendir(keypoints_dir.c_str())) == NULL) {
266 char *buffer = new char[256];
267 sprintf(buffer, "The directory %s does not exist!", keypoints_dir.c_str());
268 fawkes::LibLogger::log_error("SurfClassifier", buffer);
269 }
270
271 struct dirent *ent;
272 std::string object_file;
273 int num_obj_index = 0;
274
275 while ((ent = readdir(dir)) != NULL) {
276 if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0
277 || strcmp(ent->d_name, ".svn") == 0)
278 continue;
279
280 object_file = keypoints_dir + ent->d_name;
281 std::cout << "SurfClassifier: reading the following descriptor file" << object_file
282 << std::endl;
283
284 obj_names_.push_back(object_file);
285
286 bool b_verbose = BVERBOSE;
287 loadIpoints(object_file, obj_features_[num_obj_index], b_verbose, vlen_);
288 num_obj_index++;
289 }
290
291 closedir(dir);
292 delete ent;
293
294 num_obj_ = num_obj_index;
295
296 if (num_obj_index != 0) {
297 std::cout << "SurfClassifier: Reading successful" << std::endl;
298 //#ifdef SURF_TIMETRACKER
299 tt_->ping_end(ttc_objconv_);
300 //#endif
301 } else {
302 // if no objects were read, then the descriptor files were probably not created still. We can create them now!
303 std::cout <<"SurfClassifier: The descriptor directory is probably empty since no objects were read off. Will instantiate a Surfclassifier with the png images directory") << std::endl;
304 return new SurfClassifier("../res/opx/objects/", 5);
305 }
306
307 // save object image for debugging
308 ///surf::ImLoad::saveImage( "obj.pgm", obj_img_);
309
310 //#ifdef SURF_TIMETRACKER
311 tt_->ping_start(ttc_objfeat_);
312 //#endif
313 //#ifdef SURF_TIMETRACKER
314 tt_->ping_end(ttc_objfeat_);
315 //#endif
316}
317
318/** Constructor.
319 * @param object_dir file that contains an image of the object to detect
320 * @param samplingStep Initial sampling step
321 * @param min_match minimum number of features that have to be matched per ROI
322 * @param min_match_ratio minimum ratio of features matched per object to be matched per ROI
323 * @param octaves Number of analysed octaves
324 * @param thres Blob response treshold
325 * @param doubleImageSize true to double the image size, false to keep original
326 * @param initLobe Initial lobe size, default 3 and 5 (with double image size)
327 * @param upright rotation invariance (fasle) or upright (true)
328 * @param extended true to use the extended descriptor (SURF 128)
329 * @param indexSize Spatial size of the descriptor window (default 4)
330 */
331
332SurfClassifier::SurfClassifier(const char * object_dir,
333 unsigned int min_match,
334 float min_match_ratio,
335 int samplingStep,
336 int octaves,
337 double thres,
338 bool doubleImageSize,
339 int initLobe,
340 bool upright,
341 bool extended,
342 int indexSize)
343: Classifier("SurfClassifier")
344{
345 obj_features_.clear();
346 obj_features_.reserve(1000);
347 // matching constraints
348 min_match_ = min_match;
349 min_match_ratio_ = min_match_ratio;
350 // params for FastHessian
351 samplingStep_ = samplingStep;
352 octaves_ = octaves;
353 thres_ = thres;
354 doubleImageSize_ = doubleImageSize;
355 initLobe_ = initLobe;
356 // params for Descriptors
357 upright_ = upright;
358 extended_ = extended;
359 indexSize_ = indexSize;
360
361 // descriptor vector length
362 vlen_ = 0;
363
364 //#ifdef SURF_TIMETRACKER
365 tt_ = new fawkes::TimeTracker();
366 loop_count_ = 0;
367 ttc_objconv_ = tt_->add_class("ObjectConvert");
368 ttc_objfeat_ = tt_->add_class("ObjectFeatures");
369 ttc_imgconv_ = tt_->add_class("ImageConvert");
370 ttc_imgfeat_ = tt_->add_class("ImageFeatures");
371 ttc_matchin_ = tt_->add_class("Matching");
372 ttc_roimerg_ = tt_->add_class("MergeROIs");
373 //#endif
374
375 //#ifdef SURF_TIMETRACKER
376 tt_->ping_start(ttc_objconv_);
377 //#endif
378
379 DIR *dir = 0;
380
381 std::string dir_path = object_dir;
382
383 if ((dir = opendir(dir_path.c_str())) == NULL) {
384 char *buffer = new char[256];
385 sprintf(buffer, "The directory %s does not exist!", dir_path.c_str());
386
387 fawkes::LibLogger::log_error("SurfClassifier", buffer);
388 }
389
390 struct dirent *ent;
391 std::string object_file;
392 int num_obj_index = 0;
393
394 while ((ent = readdir(dir)) != NULL) {
395 if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0
396 || strcmp(ent->d_name, ".svn") == 0)
397 continue;
398
399 object_file = dir_path + ent->d_name;
400
401 // if( !object_file && strcmp( object_file, "" ) == 0 ) {
402 // throw fawkes::Exception("empty object file");
403 // }
404
405 std::cout << "SurfClassifier(classify): opening object image file '" << object_file << "'"
406 << std::endl;
407
408 PNGReader pngr(object_file.c_str());
409 unsigned char *buf = malloc_buffer(pngr.colorspace(), pngr.pixel_width(), pngr.pixel_height());
410 pngr.set_buffer(buf);
411 pngr.read();
412
413 unsigned int lwidth = pngr.pixel_width();
414 unsigned int lheight = pngr.pixel_height();
415 surf::Image *simage_ = new surf::Image(lwidth, lheight);
416 for (unsigned int h = 0; h < lheight; ++h) {
417 for (unsigned int w = 0; w < lwidth; ++w) {
418 simage_->setPix(w, h, (double)buf[h * lwidth + w] / 255.f);
419 }
420 }
421 // make integral image
422 obj_img_ = new surf::Image(simage_, doubleImageSize_);
423
424 // NOT WORKING
425 //obj_img_ = new surf::Image( pngr.pixel_width(), pngr.pixel_height());
426 //obj_img_->setFrame( buf );
427
428 if (!obj_img_) {
429 throw fawkes::Exception("Could not load object file '%s'", object_file.c_str());
430 }
431
432 //#ifdef SURF_TIMETRACKER
433 tt_->ping_end(ttc_objconv_);
434 //#endif
435
436 // save object image for debugging
437 ///surf::ImLoad::saveImage( "obj.pgm", obj_img_);
438
439 //#ifdef SURF_TIMETRACKER
440 tt_->ping_start(ttc_objfeat_);
441 //#endif
442
443 // COMPUTE OBJECT FEATURES
444
445 std::vector<surf::Ipoint> obj_feature;
446 obj_features_.push_back(obj_feature);
447 obj_features_[num_obj_index].clear();
448 obj_features_[num_obj_index].reserve(1000);
449 obj_num_features_ = 0;
450 // Extract interest points with Fast-Hessian
451 surf::FastHessian fh(obj_img_, /* pointer to integral image */
452 obj_features_[num_obj_index],
453 thres_, /* blob response threshold */
454 doubleImageSize_, /* double image size flag */
455 initLobe_ * 3 /* 3 times lobe size equals the mask size */,
456 samplingStep_, /* subsample the blob response map */
457 octaves_ /* number of octaves to be analysed */);
458 // Extract them and get their pointer
459 fh.getInterestPoints();
460 // Initialise the SURF descriptor
461 surf::Surf des(obj_img_, /* pointer to integral image */
462 doubleImageSize_, /* double image size flag */
463 upright_, /* rotation invariance or upright */
464 extended_, /* use the extended descriptor */
465 indexSize_ /* square size of the descriptor window (default 4x4)*/);
466 // Get the length of the descriptor vector
467 // resulting from the parameters
468 vlen_ = des.getVectLength();
469
470 //printf("vlen=%i\n", vlen_);
471
472 // Compute the orientation and the descriptor for every interest point
473 for (unsigned n = 0; n < obj_features_[num_obj_index].size(); n++) {
474 // set the current interest point
475 des.setIpoint(&(obj_features_.at(num_obj_index).at(n)));
476 // assign reproducible orientation
477 des.assignOrientation();
478 // make the SURF descriptor
479 des.makeDescriptor();
480 }
481
482 obj_num_features_ = obj_features_[num_obj_index].size();
483 if (!obj_num_features_ > 0) {
484 throw fawkes::Exception("Could not compute object features");
485 }
486 std::cout << "SurfClassifier(classify): computed '" << obj_num_features_
487 << "' features from object" << std::endl;
488
489 char buffer[256];
490 sprintf(buffer, "descriptors/%s-%d.surf", ent->d_name, num_obj_index);
491 std::string des_file_name = buffer;
492
493 bool b_verbose = BVERBOSE;
494 bool b_laplacian = true;
495
496 obj_names_.push_back(des_file_name);
497
498 // save descriptor
499 saveIpoints(des_file_name, obj_features_[num_obj_index], b_verbose, b_laplacian, vlen_);
500
501 // CleanUp
502 delete simage_;
503
504 //#ifdef SURF_TIMETRACKER
505 tt_->ping_end(ttc_objfeat_);
506 //#endif
507
508 num_obj_index++;
509 }
510
511 num_obj_ = num_obj_index;
512}
513
514/** Destructor. */
516{
517 //
518}
519
520std::list<ROI> *
522{
523 // std::cout<<"SurfClassifier: Entering classification:-"<< std::endl;
524 //#ifdef SURF_TIMETRACKER
525 tt_->ping_start(0);
526 //#endif
527
528 // list of ROIs to return
529
530 std::list<ROI> rv[num_obj_];
531 float match_ratios[num_obj_];
532
533 // std::list< ROI > *rv = new std::list< ROI >();
534
535 // for ROI calculation
536 int x_min = _width;
537 int y_min = _height;
538 int x_max = 0;
539 int y_max = 0;
540
541 //#ifdef SURF_TIMETRACKER
542 tt_->ping_start(ttc_imgconv_);
543 //#endif
544 std::cout << "SurfClassifier(classify): copy imgdat to SURF Image" << std::endl;
545
546 /*
547 // NOT WOKRING ALTERNATIVE
548 double *tmpb = (double *)malloc(_width * _height * sizeof(double));
549 for (unsigned int h = 0; h < _height; ++h) {
550 for (unsigned int w = 0; w < _width; ++w) {
551 tmpb[h * _width + w] = (double)_src[h * _width + w] / 255;
552 }
553 }
554 simage_->setFrame( (unsigned char*)tmpb );
555 //surf::ImLoad::saveImage( "stst.pgm", simage_);
556 image_ = new surf::Image(simage_, doubleImageSize_);
557 //image_ = new surf::Image( _width, _height);
558 //image_->setFrame( (unsigned char *)tmpb );
559 */
560
561 surf::Image *simage_ = new surf::Image(_width, _height);
562 for (unsigned int h = 0; h < _height; ++h) {
563 for (unsigned int w = 0; w < _width; ++w) {
564 simage_->setPix(w, h, (double)_src[h * _width + w] / 255.f);
565 }
566 }
567 // create integral image
568 image_ = new surf::Image(simage_, doubleImageSize_);
569
570 //#ifdef SURF_TIMETRACKER
571 tt_->ping_end(ttc_imgconv_);
572 //#endif
573
574 /*
575 /// write pnm (with surf-routine) for debugging
576 //surf::ImLoad::saveImage( "tst.pgm", simage_);
577 /// write integral pnm (with surf-routine) for debugging
578 //surf::ImLoad::saveImage( "tst.pgm", image_);
579 /// write pgm (with fv-routine) for debugging
580 PNMWriter pnm(PNM_PGM, "fvimg.pgm", _width, _height);
581 pnm.set_buffer(YUV422_PLANAR, _src );
582 pnm.write();
583 /// write png (with fv-routine) for debugging
584 PNGWriter pngw("fvimg.png", _width, _height);
585 pngw.set_buffer(YUV422_PLANAR, _src );
586 pngw.write();
587 */
588
589 //#ifdef SURF_TIMETRACKER
590 tt_->ping_start(ttc_imgfeat_);
591 //#endif
592
593 // COMPUTE OBJECT FEATURES
594 img_features_.clear();
595 img_features_.reserve(1000);
596 img_num_features_ = 0;
597 // Extract interest points with Fast-Hessian
598 surf::FastHessian fh(image_, /* pointer to integral image */
599 img_features_,
600 thres_, /* blob response threshold */
601 doubleImageSize_, /* double image size flag */
602 initLobe_ * 3 /* 3 times lobe size equals the mask size */,
603 samplingStep_, /* subsample the blob response map */
604 octaves_ /* number of octaves to be analysed */);
605 // Extract them and get their pointer
606 std::cout << "surfclassifer/classify : getting interest points" << std::endl;
607 fh.getInterestPoints();
608 // Initialise the SURF descriptor
609 surf::Surf des(image_, /* pointer to integral image */
610 doubleImageSize_, /* double image size flag */
611 upright_, /* rotation invariance or upright */
612 extended_, /* use the extended descriptor */
613 indexSize_ /* square size of the descriptor window (default 4x4)*/);
614 // Get the length of the descriptor vector
615 // resulting from the parameters
616 // NOT NEEDED HERE!
617 //vlen_ = des.getVectLength();
618 //printf("img vlen=%i\n", vlen_);
619
620 // Compute the orientation and the descriptor for every interest point
621 for (unsigned n = 0; n < img_features_.size(); n++) {
622 //for (Ipoint *k = ipts; k != NULL; k = k->next){
623 // set the current interest point
624 des.setIpoint(&img_features_[n]);
625 // assign reproducible orientation
626 des.assignOrientation();
627 // make the SURF descriptor
628 des.makeDescriptor();
629 }
630 img_num_features_ = img_features_.size();
631 //#ifdef SURF_TIMETRACKER
632 tt_->ping_end(ttc_imgfeat_);
633 //#endif
634
635 std::cout << "Extracted '" << img_num_features_ << "' image features" << std::endl;
636
637 //#ifdef SURF_TIMETRACKER
638 tt_->ping_start(ttc_matchin_);
639 //#endif
640 std::cout << "SurfClassifier(classify): matching ..." << std::endl;
641
642 for (unsigned j = 0; j < num_obj_; j++) {
643 std::vector<int> matches(obj_features_[j].size());
644 // std::cout<< "SurfClassifier; _debug_ : " << obj_features_[j].size() << "and" << img_features_.size() << std::endl;
645 int c = 0;
646 for (unsigned i = 0; i < obj_features_[j].size(); i++) {
647 int match = findMatch((obj_features_[j])[i], img_features_);
648 matches[i] = match;
649 if (match != -1) {
650 // std::cout << " Matched feature " << i << " in object image with feature " << match << " in image." << std::endl;
651 /// adding feature-ROI
652 ROI r((int)(img_features_[matches[i]].x) - 5,
653 (int)(img_features_[matches[i]].y) - 5,
654 11,
655 11,
656 _width,
657 _height);
658 r.num_hint_points = 0;
659 rv[j].push_back(r);
660 /// increment feature-match-count
661 ++c;
662 }
663 }
664 //#ifdef SURF_TIMETRACKER
665 tt_->ping_end(ttc_matchin_);
666 //#endif
667 if (c == 0)
668 std::cout << "SurfClassifier(classify) matched '" << c << fawkes::cnormal << "' of '"
669 << obj_features_[j].size() << "' features in scene. (for supplied object = " << j
670 << std::endl;
671 else
672 std::cout << "SurfClassifier(classify) matched '" << fawkes::cblue << c << fawkes::cnormal
673 << "' of '" << obj_features_[j].size()
674 << "' features in scene. (for supplied object = " << j << std::endl;
675
676 float match_ratio = ((float)c / (float)obj_features_[j].size());
677 match_ratios[j] = match_ratio;
678
679 std::cout << "SurfClassifier(classify): match_ratio is '" << match_ratio
680 << "' and min_match_ratio is" << min_match_ratio_ << std::endl;
681
682 std::cout << "SurfClassifier(classify): computing ROI" << std::endl;
683 //#ifdef SURF_TIMETRACKER
684 tt_->ping_start(ttc_roimerg_);
685 //#endif
686 for (unsigned i = 0; i < matches.size(); i++) {
687 if (matches[i] != -1) {
688 // //(int)obj_features_[i].x, (int)obj_features_[i].y
689 //(int)img_features_[matches[i]].x, (int)(img_features_[matches[i]].y );
690 if ((int)img_features_[matches[i]].x < x_min)
691 x_min = (int)img_features_[matches[i]].x;
692 if ((int)img_features_[matches[i]].y < y_min)
693 y_min = (int)img_features_[matches[i]].y;
694 if ((int)img_features_[matches[i]].x > x_max)
695 x_max = (int)img_features_[matches[i]].x;
696 if ((int)img_features_[matches[i]].y > y_max)
697 y_max = (int)img_features_[matches[i]].y;
698 }
699 }
700 if ((c != 0) && ((unsigned)c > min_match_) && (match_ratio > min_match_ratio_)
701 && (x_max - x_min != 0) && (y_max - y_min != 0)) {
702 std::cout << "SurfClassifier(classify): c='" << c << "' min_match_='" << min_match_ << "'."
703 << std::endl;
704
705 ROI r(x_min, y_min, x_max - x_min, y_max - y_min, _width, _height);
706 r.num_hint_points = c;
707 rv[j].push_back(r);
708 } else {
709 std::cout << " clearing ROI-list (no or too few matches or [0,0]-roi!)" << std::endl;
710 rv[j].clear();
711 }
712 }
713 //#ifdef SURF_TIMETRACKER
714 tt_->ping_end(ttc_roimerg_);
715 //#endif
716
717 // CleanUp
718 delete image_;
719 delete simage_;
720
721 //#ifdef SURF_TIMETRACKER
722 tt_->ping_end(0);
723 //#endif
724
725 //#ifdef SURF_TIMETRACKER
726 // print timetracker statistics
727 //tt_->print_to_stdout();
728 //#endif
729
730 // histogram comparison of all rois and features detected
731 float min_ratio_tmp = -1.0;
732 int min_ratio_index = -1;
733 for (unsigned int i = 0; i < num_obj_; i++) {
734 if (match_ratios[i] > min_ratio_tmp) {
735 min_ratio_tmp = match_ratios[i];
736 min_ratio_index = i;
737 }
738 }
739
740 std::list<ROI> *final_rv = new std::list<ROI>;
741
742 final_rv->assign(rv[min_ratio_index].begin(), rv[min_ratio_index].end());
743
744 std::string first_not(".-");
745 int first_not_index = obj_names_[min_ratio_index].find_first_of(first_not);
746 std::string obj_name_tmp(obj_names_[min_ratio_index]);
747 obj_name_tmp.erase(first_not_index);
748
749 std::cout << "SurfClassifier(classify): done, ... returning '" << rv->size()
750 << "' ROIs. The object class is " << min_ratio_index << "and object name is "
751 << fawkes::cgreen << obj_name_tmp << fawkes::cnormal << std::endl;
752 return final_rv;
753}
754
755int
756SurfClassifier::findMatch(const surf::Ipoint &ip1, const std::vector<surf::Ipoint> &ipts)
757{
758 double mind = 1e100, second = 1e100;
759 int match = -1;
760
761 // std::cout<< "SurfClassifier/findMatch: " << ipts.size() <<" " << vlen_ << std::endl;
762
763 for (unsigned i = 0; i < ipts.size(); i++) {
764 // Take advantage of Laplacian to speed up matching
765 if (ipts[i].laplace != ip1.laplace)
766 continue;
767
768 double d = distSquare(ipts[i].ivec, ip1.ivec, vlen_);
769
770 if (d < mind) {
771 second = mind;
772 mind = d;
773 match = i;
774 } else if (d < second) {
775 second = d;
776 }
777 }
778
779 if (mind < 0.5 * second)
780 return match;
781
782 return -1;
783}
784
785double
786SurfClassifier::distSquare(double *v1, double *v2, int n)
787{
788 double dsq = 0.;
789 // std::cout<< fawkes::cblue << (*v1) << fawkes::cred << (*v2);
790
791 while (n--) {
792 dsq += (*v1 - *v2) * (*v1 - *v2);
793 v1++;
794 v2++;
795 }
796
797 // std::cout << fawkes::cgreen << " "<<dsq << std::endl;
798
799 return dsq;
800}
801
802} // end namespace firevision
Base class for exceptions in Fawkes.
Definition: exception.h:36
static void log_error(const char *component, const char *format,...)
Log error message.
Definition: liblogger.cpp:174
Time tracking utility.
Definition: tracker.h:37
unsigned int add_class(std::string name)
Add a new class.
Definition: tracker.cpp:149
void ping_end(unsigned int cls)
End of given class task.
Definition: tracker.cpp:243
void ping_start(unsigned int cls)
Start of given class task.
Definition: tracker.cpp:218
Classifier to extract regions of interest.
Definition: classifier.h:36
unsigned int _height
Height in pixels of _src buffer.
Definition: classifier.h:53
unsigned char * _src
Source buffer, encoded as YUV422_PLANAR.
Definition: classifier.h:49
unsigned int _width
Width in pixels of _src buffer.
Definition: classifier.h:51
PNG file reader.
Definition: png.h:34
virtual void set_buffer(unsigned char *yuv422planar_buffer)
Set buffer that the read image should be written to.
Definition: png.cpp:178
virtual unsigned int pixel_height()
Get height of read image in pixels.
Definition: png.cpp:200
virtual colorspace_t colorspace()
Get colorspace from the just read image.
Definition: png.cpp:184
virtual void read()
Read data from file.
Definition: png.cpp:210
virtual unsigned int pixel_width()
Get width of read image in pixels.
Definition: png.cpp:190
Region of interest.
Definition: roi.h:55
unsigned int num_hint_points
Minimum estimate of points in ROI that are attributed to the ROI hint.
Definition: roi.h:135
SurfClassifier(std::string keypoints_descriptor_txt_file, unsigned int min_match=5, float min_match_ratio=MIN_MATCH_RATIO, int samplingStep=2, int octaves=4, double thres=4.0, bool doubleImageSize=false, int initLobe=3, bool upright=false, bool extended=false, int indexSize=4)
Constructor.
Definition: surf.cpp:216
virtual ~SurfClassifier()
Destructor.
Definition: surf.cpp:515
virtual std::list< ROI > * classify()
Classify image.
Definition: surf.cpp:521
static std::string cnormal
Print normal on console, without colors, depends on console settings.
static std::string cblue
Print blue on console.
static std::string cgreen
Print green on console.