ViSP  2.6.2
vpFernClassifier.cpp
1 /****************************************************************************
2  *
3  * $Id: vpFernClassifier.cpp 3730 2012-05-14 17:09:58Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2012 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.GPL at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * Class that implements the Fern classifier and the YAPE detector thanks
36  * to the OpenCV library.
37  *
38  * Authors:
39  * Romain Tallonneau
40  *
41  *****************************************************************************/
42 
43 #include <visp/vpConfig.h>
44 
45 #if (VISP_HAVE_OPENCV_VERSION >= 0x020000) // Require opencv >= 2.0.0
46 
47 #include <visp/vpFernClassifier.h>
48 #include <visp/vpImageTools.h>
49 #include <visp/vpImageConvert.h>
50 #include <visp/vpColor.h>
51 #include <visp/vpDisplay.h>
52 
57 vpFernClassifier::vpFernClassifier():vpBasicKeyPoint(), gen(0, 256, 5, true, 0.6, 1.5, -CV_PI/2, CV_PI/2, -CV_PI/2, CV_PI/2)
58 {
59  init();
60 }
61 
72 vpFernClassifier::vpFernClassifier(const std::string& _dataFile, const std::string& _objectName)
73 {
74  init();
75  this->load(_dataFile, _objectName);
76 }
77 
83 {
84  if(curIplImg != NULL){
85  if(curIplImg->width % 8 == 0){
86  curIplImg->imageData = NULL;
87  cvReleaseImageHeader(&curIplImg);
88  }else{
89  cvReleaseImage(&curIplImg);
90  }
91  curIplImg = NULL;
92  }
93 }
94 
100 void
102 {
103  hasLearn = false;
104  nbClassfier = 100;
105  ClassifierSize = 11;
106  nbPoints = 200;
107  curIplImg = NULL;
108  blurImage = true;
109  radiusBlur = 7;
110  sigmaBlur = 1;
111  patchSize = 32;
112  radius = 7;
113  threshold = 20;
114  nbOctave = 2;
115  nbView = 2000;
116  dist = 2;
117  nbMinPoint = 10;
118 }
119 
120 
121 
122 
126 void
128 {
129  // initialise detector
130  cv::LDetector d(radius, threshold, nbOctave, nbView, patchSize, dist);
131 
132  //blur
133  cv::Mat obj = (cv::Mat)curIplImg;
134 
135  if(this->getBlurSetting()){
136  cv::GaussianBlur(obj, obj, cv::Size(getBlurSize(), getBlurSize()), getBlurSigma(), getBlurSigma());
137  }
138 
139  // build pyramid
140  std::vector<cv::Mat> objpyr;
141  cv::buildPyramid(obj, objpyr, d.nOctaves-1);
142 
143  // getPoints
144  d.getMostStable2D(obj, objKeypoints, 100, gen);
145 
146  ldetector = d;
147 
148  // train classifier
149  modelROI = cv::Rect(0, 0, objpyr[0].cols, objpyr[0].rows);
150  ldetector.getMostStable2D(objpyr[0], modelPoints, 100, gen);
151 
152  fernClassifier.trainFromSingleView(objpyr[0], modelPoints,
153  patchSize, (int)modelPoints.size(), 100, 11, 10000,
154  cv::FernClassifier::COMPRESSION_NONE, gen);
155 
156  /* from OpenCV format to ViSP format */
157  referenceImagePointsList.resize(0);
158  for (unsigned int i = 0; i < modelPoints.size(); i += 1){
159  vpImagePoint ip(
160  modelPoints[i].pt.y + modelROI_Ref.y,
161  modelPoints[i].pt.x + modelROI_Ref.x);
162  referenceImagePointsList.push_back(ip);
163  }
164 
165  // set flag
166  hasLearn = true;
167 }
168 
182 unsigned int
184 {
185  this->setImage(_I);
186 
187  train();
188 
189  _reference_computed = true;
190  return objKeypoints.size();
191 
192 }
193 
212 unsigned int
214  const vpImagePoint &_iP,
215  const unsigned int _height, const unsigned int _width)
216 {
217  if((_iP.get_i()+_height) >= _I.getHeight()
218  || (_iP.get_j()+_width) >= _I.getWidth()) {
219  vpTRACE("Bad size for the subimage");
221  "Bad size for the subimage"));
222  }
223 
224  vpImage<unsigned char> subImage;
226  (unsigned int)_iP.get_i(),
227  (unsigned int)_iP.get_j(),
228  _height, _width, subImage);
229  this->setImage(subImage);
230 
231  /* initialise a structure containing the region of interest used in the
232  reference image */
233  modelROI_Ref.x = (int)_iP.get_u();
234  modelROI_Ref.y = (int)_iP.get_v();
235  modelROI_Ref.width = (int)_width;
236  modelROI_Ref.height = (int)_height;
237 
238  train();
239 
240  return objKeypoints.size();
241 }
242 
259 unsigned int
261  const vpRect& _rectangle)
262 {
263  vpImagePoint iP;
264  iP.set_i(_rectangle.getTop());
265  iP.set_j(_rectangle.getLeft());
266  return (this->buildReference(_I, iP,
267  (unsigned int)_rectangle.getHeight(),
268  (unsigned int)_rectangle.getWidth()));
269 }
270 
282 unsigned int
284 {
285  if(!hasLearn){
286  vpERROR_TRACE("The object has not been learned. ");
287  throw vpException(vpException::notInitialized , "object is not learned, load database or build the reference ");
288  }
289 
290  setImage(_I);
291  // resize image
292 // cv::resize(_image, image, Size(), 1./imgscale, 1./imgscale, INTER_CUBIC);
293  cv::Mat img = this->curIplImg;
294 
295  if(this->getBlurSetting()){
296  cv::GaussianBlur(img, img, cv::Size(this->getBlurSize(), this->getBlurSize()), this->getBlurSigma(), this->getBlurSigma());
297  }
298 
299  std::vector<cv::Mat> imgPyr;
300  cv::buildPyramid(img, imgPyr, ldetector.nOctaves-1);
301 
302 
303  ldetector(imgPyr, imgKeypoints, 500);
304 
305  unsigned int m = modelPoints.size();
306  unsigned int n = imgKeypoints.size();
307  std::vector<int> bestMatches(m, -1);
308  std::vector<float> maxLogProb(m, -FLT_MAX);
309  std::vector<float> signature;
310  unsigned int totalMatch = 0;
311 
312 
313  /* part of code from OpenCV planarObjectDetector */
314  currentImagePointsList.resize(0);
315  matchedReferencePoints.resize(0);
316 
317  for(unsigned int i = 0; i < n; i++ ){
318  cv::KeyPoint kpt = imgKeypoints[i];
319  kpt.pt.x /= (float)(1 << kpt.octave);
320  kpt.pt.y /= (float)(1 << kpt.octave);
321  int k = fernClassifier(imgPyr[(unsigned int)kpt.octave], kpt.pt, signature);
322  if( k >= 0 && (bestMatches[(unsigned int)k] < 0 || signature[(unsigned int)k] > maxLogProb[(unsigned int)k]) ){
323  maxLogProb[(unsigned int)k] = signature[(unsigned int)k];
324  bestMatches[(unsigned int)k] = (int)i;
325  totalMatch++;
326 
327  vpImagePoint ip_cur( imgKeypoints[i].pt.y, imgKeypoints[i].pt.x);
328 
329  currentImagePointsList.push_back(ip_cur);
330  matchedReferencePoints.push_back((unsigned int)k);
331 
332  }
333  }
334 
335  refPt.resize(0);
336  curPt.resize(0);
337  for(unsigned int i = 0; i < m; i++ ){
338  if( bestMatches[i] >= 0 ){
339  refPt.push_back(modelPoints[i].pt);
340  curPt.push_back(imgKeypoints[(unsigned int)bestMatches[i]].pt);
341  }
342  }
343 
344  return totalMatch;
345 }
346 
347 
348 
362 unsigned int
364  const vpImagePoint &_iP,
365  const unsigned int _height, const unsigned int _width)
366 {
367  if((_iP.get_i()+_height) >= _I.getHeight()
368  || (_iP.get_j()+_width) >= _I.getWidth()) {
369  vpTRACE("Bad size for the subimage");
371  "Bad size for the subimage"));
372  }
373 
374  vpImage<unsigned char> subImage;
375 
377  (unsigned int)_iP.get_i(),
378  (unsigned int)_iP.get_j(),
379  _height, _width, subImage);
380 
381  return this->matchPoint(subImage);
382 }
383 
395 unsigned int
397  const vpRect& _rectangle)
398 {
399  vpImagePoint iP;
400  iP.set_i(_rectangle.getTop());
401  iP.set_j(_rectangle.getLeft());
402  return (this->matchPoint(_I, iP,
403  (unsigned int)_rectangle.getHeight(),
404  (unsigned int)_rectangle.getWidth()));
405 }
406 
407 
424 void
426  const vpImage<unsigned char> &_Icurrent, unsigned int size)
427 {
428  for (unsigned int i = 0; i < matchedReferencePoints.size(); i++){
431  }
432 
433 }
434 
435 
446 void
447 vpFernClassifier::display(const vpImage<unsigned char> &_Icurrent, unsigned int size,
448  const vpColor &color)
449 {
450  for (unsigned int i = 0; i < matchedReferencePoints.size(); i++){
451  vpDisplay::displayCross (_Icurrent, currentImagePointsList[i], size, color);
452  }
453 }
454 
455 /* IO METHODS */
456 
465 void
466 vpFernClassifier::load(const std::string& _dataFile, const std::string& /*_objectName*/)
467 {
468  std::cout << " > Load data for the planar object detector..." << std::endl;
469 
470  /* part of code from OpenCV planarObjectDetector */
471  cv::FileStorage fs(_dataFile, cv::FileStorage::READ);
472  cv::FileNode node = fs.getFirstTopLevelNode();
473 
474  cv::FileNodeIterator it = node["model-roi"].begin(), it_end;
475  it >> modelROI.x >> modelROI.y >> modelROI.width >> modelROI.height;
476 
477  ldetector.read(node["detector"]);
478  fernClassifier.read(node["fern-classifier"]);
479 
480  const cv::FileNode node_ = node["model-points"];
481  cv::read(node_, modelPoints);
482 
483  cv::LDetector d(radius, threshold, nbOctave, nbView, patchSize, dist);
484  ldetector = d;
485  hasLearn = true;
486 }
487 
488 
495 void
496 vpFernClassifier::record(const std::string& _objectName, const std::string& _dataFile )
497 {
498  /* part of code from OpenCV planarObjectDetector */
499  cv::FileStorage fs(_dataFile, cv::FileStorage::WRITE);
500 
501  cv::WriteStructContext ws(fs, _objectName, CV_NODE_MAP);
502 
503  {
504  cv::WriteStructContext wsroi(fs, "model-roi", CV_NODE_SEQ + CV_NODE_FLOW);
505  cv::write(fs, modelROI_Ref.x);
506  cv::write(fs, modelROI_Ref.y);
507  cv::write(fs, modelROI_Ref.width);
508  cv::write(fs, modelROI_Ref.height);
509  }
510 
511  ldetector.write(fs, "detector");
512  cv::write(fs, "model-points", modelPoints);
513  fernClassifier.write(fs, "fern-classifier");
514 }
515 
516 
517 
524 void
526 {
527  if(curIplImg != NULL){
528  cvResetImageROI(curIplImg);
529  if((curIplImg->width % 8) == 0){
530  curIplImg->imageData = NULL;
531  cvReleaseImageHeader(&curIplImg);
532  }else{
533  cvReleaseImage(&curIplImg);
534  }
535  curIplImg = NULL;
536  }
537 
538  if((_I.getWidth()%8) == 0){
539  curIplImg = cvCreateImageHeader(cvSize((int)_I.getWidth(), (int)_I.getHeight()), IPL_DEPTH_8U, 1);
540  if(curIplImg != NULL){
541  curIplImg->imageData = (char*)_I.bitmap;
542  }else{
543  throw vpException(vpException::memoryAllocationError, "Could not create the image in the OpenCV format.");
544  }
545  }else{
547  }
548  if(curIplImg == NULL){
549  std::cout << "!> conversion failed" << std::endl;
550  throw vpException(vpException::notInitialized , "conversion failed");
551  }
552 }
553 
554 #endif
555 
virtual void init()
void set_j(const double j)
Definition: vpImagePoint.h:156
class that defines what is a Keypoint. This class provides all the basic elements to implement classe...
double getTop() const
Definition: vpRect.h:169
double get_v() const
Definition: vpImagePoint.h:250
virtual ~vpFernClassifier()
std::vector< cv::KeyPoint > imgKeypoints
the vector containing the points in the current image.
bool blurImage
Flag to specify whether the reference image have to be blurred or not in order to improve the recogni...
double get_i() const
Definition: vpImagePoint.h:181
unsigned int getWidth() const
Definition: vpImage.h:154
bool hasLearn
Flag to indicate whether the classifier has been trained or not.
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
#define vpERROR_TRACE
Definition: vpDebug.h:379
virtual unsigned int matchPoint(const vpImage< unsigned char > &I)
#define vpTRACE
Definition: vpDebug.h:401
Type * bitmap
points toward the bitmap
Definition: vpImage.h:115
Class to define colors available for display functionnalities.
Definition: vpColor.h:123
int nbClassfier
Number of classifier.
int nbView
Number of view to generate for the training.
cv::Rect modelROI_Ref
the ROI in the reference image.
void setImage(const vpImage< unsigned char > &_I)
double get_u() const
Definition: vpImagePoint.h:239
void set_i(const double i)
Definition: vpImagePoint.h:145
cv::PatchGenerator gen
The patch generator (OpenCV format).
unsigned int nbMinPoint
Number of minimum point below which the homography is not estimated (must be at least four) ...
double getHeight() const
Definition: vpRect.h:150
cv::LDetector ldetector
The points of interest detector.
static const vpColor green
Definition: vpColor.h:168
int radius
Radius for the detector.
int nbPoints
Maximal number of points.
double get_j() const
Definition: vpImagePoint.h:192
static const vpColor red
Definition: vpColor.h:165
std::vector< cv::Point2f > curPt
virtual unsigned int buildReference(const vpImage< unsigned char > &I)
int patchSize
Size of the patch.
double getWidth() const
Definition: vpRect.h:188
int sigmaBlur
Sigma of the kernel used to blur the image.
int nbOctave
Number of octave for the multi scale.
bool _reference_computed
flag to indicate if the reference has been built.
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
std::vector< vpImagePoint > referenceImagePointsList
void record(const std::string &_objectName, const std::string &_dataFile)
record the Ferns classifier in the text file
std::vector< cv::KeyPoint > objKeypoints
keypoints detected in the reference image.
int threshold
Threshold to accept or reject points (usually around 20)
static void createSubImage(const vpImage< Type > &I, unsigned int i_sub, unsigned int j_sub, unsigned int nrow_sub, unsigned int ncol_sub, vpImage< Type > &S)
Definition: vpImageTools.h:129
cv::FernClassifier fernClassifier
The Fern classifier.
int dist
Minimal distance between two points.
std::vector< unsigned int > matchedReferencePoints
std::vector< cv::Point2f > refPt
vector in the OpenCV format to be used by the detector.
unsigned int getHeight() const
Definition: vpImage.h:145
Defines a rectangle in the plane.
Definition: vpRect.h:82
int radiusBlur
Radius of the kernel used to blur the image.
std::vector< vpImagePoint > currentImagePointsList
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:92
IplImage * curIplImg
The current image in the OpenCV format.
void load(const std::string &_dataFile, const std::string &)
load the Fern classifier
virtual void display(const vpImage< unsigned char > &Iref, const vpImage< unsigned char > &Icurrent, unsigned int size=3)
std::vector< cv::KeyPoint > modelPoints
the vector containing the points in the model.
double getLeft() const
Definition: vpRect.h:156
int ClassifierSize
Size of the classifier.
cv::Rect modelROI
the ROI for the reference image.