ViSP  2.8.0
vpFernClassifier.cpp
1 /****************************************************************************
2  *
3  * $Id: vpFernClassifier.cpp 4303 2013-07-04 14:14:00Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2013 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 (unsigned int)objKeypoints.size();
191 }
192 
211 unsigned int
213  const vpImagePoint &_iP,
214  const unsigned int _height, const unsigned int _width)
215 {
216  if((_iP.get_i()+_height) >= _I.getHeight()
217  || (_iP.get_j()+_width) >= _I.getWidth()) {
218  vpTRACE("Bad size for the subimage");
220  "Bad size for the subimage"));
221  }
222 
223  vpImage<unsigned char> subImage;
225  (unsigned int)_iP.get_i(),
226  (unsigned int)_iP.get_j(),
227  _height, _width, subImage);
228  this->setImage(subImage);
229 
230  /* initialise a structure containing the region of interest used in the
231  reference image */
232  modelROI_Ref.x = (int)_iP.get_u();
233  modelROI_Ref.y = (int)_iP.get_v();
234  modelROI_Ref.width = (int)_width;
235  modelROI_Ref.height = (int)_height;
236 
237  train();
238 
239  return (unsigned int)objKeypoints.size();
240 }
241 
258 unsigned int
260  const vpRect& _rectangle)
261 {
262  vpImagePoint iP;
263  iP.set_i(_rectangle.getTop());
264  iP.set_j(_rectangle.getLeft());
265  return (this->buildReference(_I, iP,
266  (unsigned int)_rectangle.getHeight(),
267  (unsigned int)_rectangle.getWidth()));
268 }
269 
281 unsigned int
283 {
284  if(!hasLearn){
285  vpERROR_TRACE("The object has not been learned. ");
286  throw vpException(vpException::notInitialized , "object is not learned, load database or build the reference ");
287  }
288 
289  setImage(_I);
290  // resize image
291 // cv::resize(_image, image, Size(), 1./imgscale, 1./imgscale, INTER_CUBIC);
292  cv::Mat img = this->curIplImg;
293 
294  if(this->getBlurSetting()){
295  cv::GaussianBlur(img, img, cv::Size(this->getBlurSize(), this->getBlurSize()), this->getBlurSigma(), this->getBlurSigma());
296  }
297 
298  std::vector<cv::Mat> imgPyr;
299  cv::buildPyramid(img, imgPyr, ldetector.nOctaves-1);
300 
301 
302  ldetector(imgPyr, imgKeypoints, 500);
303 
304  unsigned int m = (unsigned int)modelPoints.size();
305  unsigned int n = (unsigned int)imgKeypoints.size();
306  std::vector<int> bestMatches(m, -1);
307  std::vector<float> maxLogProb(m, -FLT_MAX);
308  std::vector<float> signature;
309  unsigned int totalMatch = 0;
310 
311 
312  /* part of code from OpenCV planarObjectDetector */
313  currentImagePointsList.resize(0);
314  matchedReferencePoints.resize(0);
315 
316  for(unsigned int i = 0; i < n; i++ ){
317  cv::KeyPoint kpt = imgKeypoints[i];
318  kpt.pt.x /= (float)(1 << kpt.octave);
319  kpt.pt.y /= (float)(1 << kpt.octave);
320  int k = fernClassifier(imgPyr[(unsigned int)kpt.octave], kpt.pt, signature);
321  if( k >= 0 && (bestMatches[(unsigned int)k] < 0 || signature[(unsigned int)k] > maxLogProb[(unsigned int)k]) ){
322  maxLogProb[(unsigned int)k] = signature[(unsigned int)k];
323  bestMatches[(unsigned int)k] = (int)i;
324  totalMatch++;
325 
326  vpImagePoint ip_cur( imgKeypoints[i].pt.y, imgKeypoints[i].pt.x);
327 
328  currentImagePointsList.push_back(ip_cur);
329  matchedReferencePoints.push_back((unsigned int)k);
330 
331  }
332  }
333 
334  refPt.resize(0);
335  curPt.resize(0);
336  for(unsigned int i = 0; i < m; i++ ){
337  if( bestMatches[i] >= 0 ){
338  refPt.push_back(modelPoints[i].pt);
339  curPt.push_back(imgKeypoints[(unsigned int)bestMatches[i]].pt);
340  }
341  }
342 
343  return totalMatch;
344 }
345 
346 
347 
361 unsigned int
363  const vpImagePoint &_iP,
364  const unsigned int _height, const unsigned int _width)
365 {
366  if((_iP.get_i()+_height) >= _I.getHeight()
367  || (_iP.get_j()+_width) >= _I.getWidth()) {
368  vpTRACE("Bad size for the subimage");
370  "Bad size for the subimage"));
371  }
372 
373  vpImage<unsigned char> subImage;
374 
376  (unsigned int)_iP.get_i(),
377  (unsigned int)_iP.get_j(),
378  _height, _width, subImage);
379 
380  return this->matchPoint(subImage);
381 }
382 
394 unsigned int
396  const vpRect& _rectangle)
397 {
398  vpImagePoint iP;
399  iP.set_i(_rectangle.getTop());
400  iP.set_j(_rectangle.getLeft());
401  return (this->matchPoint(_I, iP,
402  (unsigned int)_rectangle.getHeight(),
403  (unsigned int)_rectangle.getWidth()));
404 }
405 
406 
423 void
425  const vpImage<unsigned char> &_Icurrent, unsigned int size)
426 {
427  for (unsigned int i = 0; i < matchedReferencePoints.size(); i++){
430  }
431 
432 }
433 
434 
445 void
446 vpFernClassifier::display(const vpImage<unsigned char> &_Icurrent, unsigned int size,
447  const vpColor &color)
448 {
449  for (unsigned int i = 0; i < matchedReferencePoints.size(); i++){
450  vpDisplay::displayCross (_Icurrent, currentImagePointsList[i], size, color);
451  }
452 }
453 
454 /* IO METHODS */
455 
464 void
465 vpFernClassifier::load(const std::string& _dataFile, const std::string& /*_objectName*/)
466 {
467  std::cout << " > Load data for the planar object detector..." << std::endl;
468 
469  /* part of code from OpenCV planarObjectDetector */
470  cv::FileStorage fs(_dataFile, cv::FileStorage::READ);
471  cv::FileNode node = fs.getFirstTopLevelNode();
472 
473  cv::FileNodeIterator it = node["model-roi"].begin(), it_end;
474  it >> modelROI.x >> modelROI.y >> modelROI.width >> modelROI.height;
475 
476  ldetector.read(node["detector"]);
477  fernClassifier.read(node["fern-classifier"]);
478 
479  const cv::FileNode node_ = node["model-points"];
480  cv::read(node_, modelPoints);
481 
482  cv::LDetector d(radius, threshold, nbOctave, nbView, patchSize, dist);
483  ldetector = d;
484  hasLearn = true;
485 }
486 
487 
494 void
495 vpFernClassifier::record(const std::string& _objectName, const std::string& _dataFile )
496 {
497  /* part of code from OpenCV planarObjectDetector */
498  cv::FileStorage fs(_dataFile, cv::FileStorage::WRITE);
499 
500  cv::WriteStructContext ws(fs, _objectName, CV_NODE_MAP);
501 
502  {
503  cv::WriteStructContext wsroi(fs, "model-roi", CV_NODE_SEQ + CV_NODE_FLOW);
504  cv::write(fs, modelROI_Ref.x);
505  cv::write(fs, modelROI_Ref.y);
506  cv::write(fs, modelROI_Ref.width);
507  cv::write(fs, modelROI_Ref.height);
508  }
509 
510  ldetector.write(fs, "detector");
511  cv::write(fs, "model-points", modelPoints);
512  fernClassifier.write(fs, "fern-classifier");
513 }
514 
515 
516 
523 void
525 {
526  if(curIplImg != NULL){
527  cvResetImageROI(curIplImg);
528  if((curIplImg->width % 8) == 0){
529  curIplImg->imageData = NULL;
530  cvReleaseImageHeader(&curIplImg);
531  }else{
532  cvReleaseImage(&curIplImg);
533  }
534  curIplImg = NULL;
535  }
536 
537  if((_I.getWidth()%8) == 0){
538  curIplImg = cvCreateImageHeader(cvSize((int)_I.getWidth(), (int)_I.getHeight()), IPL_DEPTH_8U, 1);
539  if(curIplImg != NULL){
540  curIplImg->imageData = (char*)_I.bitmap;
541  }else{
542  throw vpException(vpException::memoryAllocationError, "Could not create the image in the OpenCV format.");
543  }
544  }else{
546  }
547  if(curIplImg == NULL){
548  std::cout << "!> conversion failed" << std::endl;
549  throw vpException(vpException::notInitialized , "conversion failed");
550  }
551 }
552 
553 #endif
554 
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:159
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:120
Class to define colors available for display functionnalities.
Definition: vpColor.h:125
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) ...
error that can be emited by ViSP classes.
Definition: vpException.h:75
double getHeight() const
Definition: vpRect.h:150
cv::LDetector ldetector
The points of interest detector.
static const vpColor green
Definition: vpColor.h:170
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:167
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:133
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:150
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.