ViSP  2.10.0
vpFernClassifier.cpp
1 /****************************************************************************
2  *
3  * $Id: vpFernClassifier.cpp 5023 2014-12-03 16:07:48Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2014 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) && (VISP_HAVE_OPENCV_VERSION < 0x030000) // Require opencv >= 2.0.0 and < 3.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 
58  : vpBasicKeyPoint(),
59  ldetector(), fernClassifier(), gen(0, 256, 5, true, 0.6, 1.5, -CV_PI/2, CV_PI/2, -CV_PI/2, CV_PI/2),
60  hasLearn(false), threshold(20), nbView(2000), dist(2), nbClassfier(100), ClassifierSize(11),
61  nbOctave(2), patchSize(32), radius(7), nbPoints(200), blurImage(true), radiusBlur(7),
62  sigmaBlur(1), nbMinPoint(10),
63  #if (VISP_HAVE_OPENCV_VERSION >= 0x020408)
64  curImg(),
65  #else
66  curImg(NULL),
67  #endif
68  objKeypoints(), modelROI_Ref(), modelROI(),
69  modelPoints(), imgKeypoints(), refPt(), curPt()
70 {
71 }
72 
83 vpFernClassifier::vpFernClassifier(const std::string& _dataFile, const std::string& _objectName)
84  : vpBasicKeyPoint(),
85  ldetector(), fernClassifier(), gen(0, 256, 5, true, 0.6, 1.5, -CV_PI/2, CV_PI/2, -CV_PI/2, CV_PI/2),
86  hasLearn(false), threshold(20), nbView(2000), dist(2), nbClassfier(100), ClassifierSize(11),
87  nbOctave(2), patchSize(32), radius(7), nbPoints(200), blurImage(true), radiusBlur(7),
88  sigmaBlur(1), nbMinPoint(10),
89  #if (VISP_HAVE_OPENCV_VERSION >= 0x020408)
90  curImg(),
91  #else
92  curImg(NULL),
93  #endif
94  objKeypoints(), modelROI_Ref(), modelROI(),
95  modelPoints(), imgKeypoints(), refPt(), curPt()
96 {
97  this->load(_dataFile, _objectName);
98 }
99 
105 {
106 #if (VISP_HAVE_OPENCV_VERSION < 0x020408)
107  if(curImg != NULL){
108  if(curImg->width % 8 == 0){
109  curImg->imageData = NULL;
110  cvReleaseImageHeader(&curImg);
111  }else{
112  cvReleaseImage(&curImg);
113  }
114  curImg = NULL;
115  }
116 #endif
117 }
118 
124 void
126 {
127  hasLearn = false;
128  nbClassfier = 100;
129  ClassifierSize = 11;
130  nbPoints = 200;
131 #if (VISP_HAVE_OPENCV_VERSION < 0x020408)
132  curImg = NULL;
133 #endif
134  blurImage = true;
135  radiusBlur = 7;
136  sigmaBlur = 1;
137  patchSize = 32;
138  radius = 7;
139  threshold = 20;
140  nbOctave = 2;
141  nbView = 2000;
142  dist = 2;
143  nbMinPoint = 10;
144 }
145 
146 
147 
148 
152 void
154 {
155  // initialise detector
156  cv::LDetector d(radius, threshold, nbOctave, nbView, patchSize, dist);
157 
158  //blur
159  cv::Mat obj = (cv::Mat)curImg;
160 
161  if(this->getBlurSetting()){
162  cv::GaussianBlur(obj, obj, cv::Size(getBlurSize(), getBlurSize()), getBlurSigma(), getBlurSigma());
163  }
164 
165  // build pyramid
166  std::vector<cv::Mat> objpyr;
167  cv::buildPyramid(obj, objpyr, d.nOctaves-1);
168 
169  // getPoints
170  d.getMostStable2D(obj, objKeypoints, 100, gen);
171 
172  ldetector = d;
173 
174  // train classifier
175  modelROI = cv::Rect(0, 0, objpyr[0].cols, objpyr[0].rows);
176  ldetector.getMostStable2D(objpyr[0], modelPoints, 100, gen);
177 
178  fernClassifier.trainFromSingleView(objpyr[0], modelPoints,
179  patchSize, (int)modelPoints.size(), 100, 11, 10000,
180  cv::FernClassifier::COMPRESSION_NONE, gen);
181 
182  /* from OpenCV format to ViSP format */
183  referenceImagePointsList.resize(0);
184  for (unsigned int i = 0; i < modelPoints.size(); i += 1){
185  vpImagePoint ip(
186  modelPoints[i].pt.y + modelROI_Ref.y,
187  modelPoints[i].pt.x + modelROI_Ref.x);
188  referenceImagePointsList.push_back(ip);
189  }
190 
191  // set flag
192  hasLearn = true;
193 }
194 
208 unsigned int
210 {
211  this->setImage(_I);
212 
213  train();
214 
215  _reference_computed = true;
216  return (unsigned int)objKeypoints.size();
217 }
218 
237 unsigned int
239  const vpImagePoint &_iP,
240  const unsigned int _height, const unsigned int _width)
241 {
242  if((_iP.get_i()+_height) >= _I.getHeight()
243  || (_iP.get_j()+_width) >= _I.getWidth()) {
244  vpTRACE("Bad size for the subimage");
246  "Bad size for the subimage"));
247  }
248 
249  vpImage<unsigned char> subImage;
251  (unsigned int)_iP.get_i(),
252  (unsigned int)_iP.get_j(),
253  _height, _width, subImage);
254  this->setImage(subImage);
255 
256  /* initialise a structure containing the region of interest used in the
257  reference image */
258  modelROI_Ref.x = (int)_iP.get_u();
259  modelROI_Ref.y = (int)_iP.get_v();
260  modelROI_Ref.width = (int)_width;
261  modelROI_Ref.height = (int)_height;
262 
263  train();
264 
265  return (unsigned int)objKeypoints.size();
266 }
267 
284 unsigned int
286  const vpRect& _rectangle)
287 {
288  vpImagePoint iP;
289  iP.set_i(_rectangle.getTop());
290  iP.set_j(_rectangle.getLeft());
291  return (this->buildReference(_I, iP,
292  (unsigned int)_rectangle.getHeight(),
293  (unsigned int)_rectangle.getWidth()));
294 }
295 
307 unsigned int
309 {
310  if(!hasLearn){
311  vpERROR_TRACE("The object has not been learned. ");
312  throw vpException(vpException::notInitialized , "object is not learned, load database or build the reference ");
313  }
314 
315  setImage(_I);
316  // resize image
317 // cv::resize(_image, image, Size(), 1./imgscale, 1./imgscale, INTER_CUBIC);
318  cv::Mat img = this->curImg;
319 
320  if(this->getBlurSetting()){
321  cv::GaussianBlur(img, img, cv::Size(this->getBlurSize(), this->getBlurSize()), this->getBlurSigma(), this->getBlurSigma());
322  }
323 
324  std::vector<cv::Mat> imgPyr;
325  cv::buildPyramid(img, imgPyr, ldetector.nOctaves-1);
326 
327 
328  ldetector(imgPyr, imgKeypoints, 500);
329 
330  unsigned int m = (unsigned int)modelPoints.size();
331  unsigned int n = (unsigned int)imgKeypoints.size();
332  std::vector<int> bestMatches(m, -1);
333  std::vector<float> maxLogProb(m, -FLT_MAX);
334  std::vector<float> signature;
335  unsigned int totalMatch = 0;
336 
337 
338  /* part of code from OpenCV planarObjectDetector */
339  currentImagePointsList.resize(0);
340  matchedReferencePoints.resize(0);
341 
342  for(unsigned int i = 0; i < n; i++ ){
343  cv::KeyPoint kpt = imgKeypoints[i];
344  kpt.pt.x /= (float)(1 << kpt.octave);
345  kpt.pt.y /= (float)(1 << kpt.octave);
346  int k = fernClassifier(imgPyr[(unsigned int)kpt.octave], kpt.pt, signature);
347  if( k >= 0 && (bestMatches[(unsigned int)k] < 0 || signature[(unsigned int)k] > maxLogProb[(unsigned int)k]) ){
348  maxLogProb[(unsigned int)k] = signature[(unsigned int)k];
349  bestMatches[(unsigned int)k] = (int)i;
350  totalMatch++;
351 
352  vpImagePoint ip_cur( imgKeypoints[i].pt.y, imgKeypoints[i].pt.x);
353 
354  currentImagePointsList.push_back(ip_cur);
355  matchedReferencePoints.push_back((unsigned int)k);
356 
357  }
358  }
359 
360  refPt.resize(0);
361  curPt.resize(0);
362  for(unsigned int i = 0; i < m; i++ ){
363  if( bestMatches[i] >= 0 ){
364  refPt.push_back(modelPoints[i].pt);
365  curPt.push_back(imgKeypoints[(unsigned int)bestMatches[i]].pt);
366  }
367  }
368 
369  return totalMatch;
370 }
371 
372 
373 
387 unsigned int
389  const vpImagePoint &_iP,
390  const unsigned int _height, const unsigned int _width)
391 {
392  if((_iP.get_i()+_height) >= _I.getHeight()
393  || (_iP.get_j()+_width) >= _I.getWidth()) {
394  vpTRACE("Bad size for the subimage");
396  "Bad size for the subimage"));
397  }
398 
399  vpImage<unsigned char> subImage;
400 
402  (unsigned int)_iP.get_i(),
403  (unsigned int)_iP.get_j(),
404  _height, _width, subImage);
405 
406  return this->matchPoint(subImage);
407 }
408 
420 unsigned int
422  const vpRect& _rectangle)
423 {
424  vpImagePoint iP;
425  iP.set_i(_rectangle.getTop());
426  iP.set_j(_rectangle.getLeft());
427  return (this->matchPoint(_I, iP,
428  (unsigned int)_rectangle.getHeight(),
429  (unsigned int)_rectangle.getWidth()));
430 }
431 
432 
449 void
451  const vpImage<unsigned char> &_Icurrent, unsigned int size)
452 {
453  for (unsigned int i = 0; i < matchedReferencePoints.size(); i++){
456  }
457 
458 }
459 
460 
471 void
472 vpFernClassifier::display(const vpImage<unsigned char> &_Icurrent, unsigned int size,
473  const vpColor &color)
474 {
475  for (unsigned int i = 0; i < matchedReferencePoints.size(); i++){
476  vpDisplay::displayCross (_Icurrent, currentImagePointsList[i], size, color);
477  }
478 }
479 
480 /* IO METHODS */
481 
490 void
491 vpFernClassifier::load(const std::string& _dataFile, const std::string& /*_objectName*/)
492 {
493  std::cout << " > Load data for the planar object detector..." << std::endl;
494 
495  /* part of code from OpenCV planarObjectDetector */
496  cv::FileStorage fs(_dataFile, cv::FileStorage::READ);
497  cv::FileNode node = fs.getFirstTopLevelNode();
498 
499  cv::FileNodeIterator it = node["model-roi"].begin(), it_end;
500  it >> modelROI.x >> modelROI.y >> modelROI.width >> modelROI.height;
501 
502  ldetector.read(node["detector"]);
503  fernClassifier.read(node["fern-classifier"]);
504 
505  const cv::FileNode node_ = node["model-points"];
506  cv::read(node_, modelPoints);
507 
508  cv::LDetector d(radius, threshold, nbOctave, nbView, patchSize, dist);
509  ldetector = d;
510  hasLearn = true;
511 }
512 
513 
520 void
521 vpFernClassifier::record(const std::string& _objectName, const std::string& _dataFile )
522 {
523  /* part of code from OpenCV planarObjectDetector */
524  cv::FileStorage fs(_dataFile, cv::FileStorage::WRITE);
525 
526  cv::WriteStructContext ws(fs, _objectName, CV_NODE_MAP);
527 
528  {
529  cv::WriteStructContext wsroi(fs, "model-roi", CV_NODE_SEQ + CV_NODE_FLOW);
530  cv::write(fs, modelROI_Ref.x);
531  cv::write(fs, modelROI_Ref.y);
532  cv::write(fs, modelROI_Ref.width);
533  cv::write(fs, modelROI_Ref.height);
534  }
535 
536  ldetector.write(fs, "detector");
537  cv::write(fs, "model-points", modelPoints);
538  fernClassifier.write(fs, "fern-classifier");
539 }
540 
541 
542 
549 void
551 {
552 #if (VISP_HAVE_OPENCV_VERSION >= 0x020408)
554 #else
555  if(curImg != NULL){
556  cvResetImageROI(curImg);
557  if((curImg->width % 8) == 0){
558  curImg->imageData = NULL;
559  cvReleaseImageHeader(&curImg);
560  }else{
561  cvReleaseImage(&curImg);
562  }
563  curImg = NULL;
564  }
565  if((I.getWidth()%8) == 0){
566  curImg = cvCreateImageHeader(cvSize((int)I.getWidth(), (int)I.getHeight()), IPL_DEPTH_8U, 1);
567  if(curImg != NULL){
568  curImg->imageData = (char*)I.bitmap;
569  }else{
570  throw vpException(vpException::memoryAllocationError, "Could not create the image in the OpenCV format.");
571  }
572  }else{
574  }
575  if(curImg == NULL){
576  std::cout << "!> conversion failed" << std::endl;
577  throw vpException(vpException::notInitialized , "conversion failed");
578  }
579 #endif
580 
581 }
582 
583 #endif
584 
virtual void init()
class that defines what is a Keypoint. This class provides all the basic elements to implement classe...
double getTop() const
Definition: vpRect.h:180
double get_v() const
Definition: vpImagePoint.h:264
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:195
unsigned int getWidth() const
Definition: vpImage.h:161
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:395
virtual unsigned int matchPoint(const vpImage< unsigned char > &I)
#define vpTRACE
Definition: vpDebug.h:418
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.
double get_u() const
Definition: vpImagePoint.h:253
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:76
double getHeight() const
Definition: vpRect.h:155
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:206
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.
void set_i(const double ii)
Definition: vpImagePoint.h:159
double getWidth() const
Definition: vpRect.h:199
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.
void set_j(const double jj)
Definition: vpImagePoint.h:170
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:152
Defines a rectangle in the plane.
Definition: vpRect.h:85
int radiusBlur
Radius of the kernel used to blur the image.
std::vector< vpImagePoint > currentImagePointsList
cv::Mat curImg
The current image in the OpenCV format.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:93
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)
void setImage(const vpImage< unsigned char > &I)
std::vector< cv::KeyPoint > modelPoints
the vector containing the points in the model.
double getLeft() const
Definition: vpRect.h:161
int ClassifierSize
Size of the classifier.
cv::Rect modelROI
the ROI for the reference image.