ViSP  2.9.0
vpFernClassifier.cpp
1 /****************************************************************************
2  *
3  * $Id: vpFernClassifier.cpp 4632 2014-02-03 17:06:40Z 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) // 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 
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), curIplImg(NULL), objKeypoints(), modelROI_Ref(), modelROI(),
63  modelPoints(), imgKeypoints(), refPt(), curPt()
64 {
65 }
66 
77 vpFernClassifier::vpFernClassifier(const std::string& _dataFile, const std::string& _objectName)
78  : vpBasicKeyPoint(),
79  ldetector(), fernClassifier(), gen(0, 256, 5, true, 0.6, 1.5, -CV_PI/2, CV_PI/2, -CV_PI/2, CV_PI/2),
80  hasLearn(false), threshold(20), nbView(2000), dist(2), nbClassfier(100), ClassifierSize(11),
81  nbOctave(2), patchSize(32), radius(7), nbPoints(200), blurImage(true), radiusBlur(7),
82  sigmaBlur(1), nbMinPoint(10), curIplImg(NULL), objKeypoints(), modelROI_Ref(), modelROI(),
83  modelPoints(), imgKeypoints(), refPt(), curPt()
84 {
85  this->load(_dataFile, _objectName);
86 }
87 
93 {
94  if(curIplImg != NULL){
95  if(curIplImg->width % 8 == 0){
96  curIplImg->imageData = NULL;
97  cvReleaseImageHeader(&curIplImg);
98  }else{
99  cvReleaseImage(&curIplImg);
100  }
101  curIplImg = NULL;
102  }
103 }
104 
110 void
112 {
113  hasLearn = false;
114  nbClassfier = 100;
115  ClassifierSize = 11;
116  nbPoints = 200;
117  curIplImg = NULL;
118  blurImage = true;
119  radiusBlur = 7;
120  sigmaBlur = 1;
121  patchSize = 32;
122  radius = 7;
123  threshold = 20;
124  nbOctave = 2;
125  nbView = 2000;
126  dist = 2;
127  nbMinPoint = 10;
128 }
129 
130 
131 
132 
136 void
138 {
139  // initialise detector
140  cv::LDetector d(radius, threshold, nbOctave, nbView, patchSize, dist);
141 
142  //blur
143  cv::Mat obj = (cv::Mat)curIplImg;
144 
145  if(this->getBlurSetting()){
146  cv::GaussianBlur(obj, obj, cv::Size(getBlurSize(), getBlurSize()), getBlurSigma(), getBlurSigma());
147  }
148 
149  // build pyramid
150  std::vector<cv::Mat> objpyr;
151  cv::buildPyramid(obj, objpyr, d.nOctaves-1);
152 
153  // getPoints
154  d.getMostStable2D(obj, objKeypoints, 100, gen);
155 
156  ldetector = d;
157 
158  // train classifier
159  modelROI = cv::Rect(0, 0, objpyr[0].cols, objpyr[0].rows);
160  ldetector.getMostStable2D(objpyr[0], modelPoints, 100, gen);
161 
162  fernClassifier.trainFromSingleView(objpyr[0], modelPoints,
163  patchSize, (int)modelPoints.size(), 100, 11, 10000,
164  cv::FernClassifier::COMPRESSION_NONE, gen);
165 
166  /* from OpenCV format to ViSP format */
167  referenceImagePointsList.resize(0);
168  for (unsigned int i = 0; i < modelPoints.size(); i += 1){
169  vpImagePoint ip(
170  modelPoints[i].pt.y + modelROI_Ref.y,
171  modelPoints[i].pt.x + modelROI_Ref.x);
172  referenceImagePointsList.push_back(ip);
173  }
174 
175  // set flag
176  hasLearn = true;
177 }
178 
192 unsigned int
194 {
195  this->setImage(_I);
196 
197  train();
198 
199  _reference_computed = true;
200  return (unsigned int)objKeypoints.size();
201 }
202 
221 unsigned int
223  const vpImagePoint &_iP,
224  const unsigned int _height, const unsigned int _width)
225 {
226  if((_iP.get_i()+_height) >= _I.getHeight()
227  || (_iP.get_j()+_width) >= _I.getWidth()) {
228  vpTRACE("Bad size for the subimage");
230  "Bad size for the subimage"));
231  }
232 
233  vpImage<unsigned char> subImage;
235  (unsigned int)_iP.get_i(),
236  (unsigned int)_iP.get_j(),
237  _height, _width, subImage);
238  this->setImage(subImage);
239 
240  /* initialise a structure containing the region of interest used in the
241  reference image */
242  modelROI_Ref.x = (int)_iP.get_u();
243  modelROI_Ref.y = (int)_iP.get_v();
244  modelROI_Ref.width = (int)_width;
245  modelROI_Ref.height = (int)_height;
246 
247  train();
248 
249  return (unsigned int)objKeypoints.size();
250 }
251 
268 unsigned int
270  const vpRect& _rectangle)
271 {
272  vpImagePoint iP;
273  iP.set_i(_rectangle.getTop());
274  iP.set_j(_rectangle.getLeft());
275  return (this->buildReference(_I, iP,
276  (unsigned int)_rectangle.getHeight(),
277  (unsigned int)_rectangle.getWidth()));
278 }
279 
291 unsigned int
293 {
294  if(!hasLearn){
295  vpERROR_TRACE("The object has not been learned. ");
296  throw vpException(vpException::notInitialized , "object is not learned, load database or build the reference ");
297  }
298 
299  setImage(_I);
300  // resize image
301 // cv::resize(_image, image, Size(), 1./imgscale, 1./imgscale, INTER_CUBIC);
302  cv::Mat img = this->curIplImg;
303 
304  if(this->getBlurSetting()){
305  cv::GaussianBlur(img, img, cv::Size(this->getBlurSize(), this->getBlurSize()), this->getBlurSigma(), this->getBlurSigma());
306  }
307 
308  std::vector<cv::Mat> imgPyr;
309  cv::buildPyramid(img, imgPyr, ldetector.nOctaves-1);
310 
311 
312  ldetector(imgPyr, imgKeypoints, 500);
313 
314  unsigned int m = (unsigned int)modelPoints.size();
315  unsigned int n = (unsigned int)imgKeypoints.size();
316  std::vector<int> bestMatches(m, -1);
317  std::vector<float> maxLogProb(m, -FLT_MAX);
318  std::vector<float> signature;
319  unsigned int totalMatch = 0;
320 
321 
322  /* part of code from OpenCV planarObjectDetector */
323  currentImagePointsList.resize(0);
324  matchedReferencePoints.resize(0);
325 
326  for(unsigned int i = 0; i < n; i++ ){
327  cv::KeyPoint kpt = imgKeypoints[i];
328  kpt.pt.x /= (float)(1 << kpt.octave);
329  kpt.pt.y /= (float)(1 << kpt.octave);
330  int k = fernClassifier(imgPyr[(unsigned int)kpt.octave], kpt.pt, signature);
331  if( k >= 0 && (bestMatches[(unsigned int)k] < 0 || signature[(unsigned int)k] > maxLogProb[(unsigned int)k]) ){
332  maxLogProb[(unsigned int)k] = signature[(unsigned int)k];
333  bestMatches[(unsigned int)k] = (int)i;
334  totalMatch++;
335 
336  vpImagePoint ip_cur( imgKeypoints[i].pt.y, imgKeypoints[i].pt.x);
337 
338  currentImagePointsList.push_back(ip_cur);
339  matchedReferencePoints.push_back((unsigned int)k);
340 
341  }
342  }
343 
344  refPt.resize(0);
345  curPt.resize(0);
346  for(unsigned int i = 0; i < m; i++ ){
347  if( bestMatches[i] >= 0 ){
348  refPt.push_back(modelPoints[i].pt);
349  curPt.push_back(imgKeypoints[(unsigned int)bestMatches[i]].pt);
350  }
351  }
352 
353  return totalMatch;
354 }
355 
356 
357 
371 unsigned int
373  const vpImagePoint &_iP,
374  const unsigned int _height, const unsigned int _width)
375 {
376  if((_iP.get_i()+_height) >= _I.getHeight()
377  || (_iP.get_j()+_width) >= _I.getWidth()) {
378  vpTRACE("Bad size for the subimage");
380  "Bad size for the subimage"));
381  }
382 
383  vpImage<unsigned char> subImage;
384 
386  (unsigned int)_iP.get_i(),
387  (unsigned int)_iP.get_j(),
388  _height, _width, subImage);
389 
390  return this->matchPoint(subImage);
391 }
392 
404 unsigned int
406  const vpRect& _rectangle)
407 {
408  vpImagePoint iP;
409  iP.set_i(_rectangle.getTop());
410  iP.set_j(_rectangle.getLeft());
411  return (this->matchPoint(_I, iP,
412  (unsigned int)_rectangle.getHeight(),
413  (unsigned int)_rectangle.getWidth()));
414 }
415 
416 
433 void
435  const vpImage<unsigned char> &_Icurrent, unsigned int size)
436 {
437  for (unsigned int i = 0; i < matchedReferencePoints.size(); i++){
440  }
441 
442 }
443 
444 
455 void
456 vpFernClassifier::display(const vpImage<unsigned char> &_Icurrent, unsigned int size,
457  const vpColor &color)
458 {
459  for (unsigned int i = 0; i < matchedReferencePoints.size(); i++){
460  vpDisplay::displayCross (_Icurrent, currentImagePointsList[i], size, color);
461  }
462 }
463 
464 /* IO METHODS */
465 
474 void
475 vpFernClassifier::load(const std::string& _dataFile, const std::string& /*_objectName*/)
476 {
477  std::cout << " > Load data for the planar object detector..." << std::endl;
478 
479  /* part of code from OpenCV planarObjectDetector */
480  cv::FileStorage fs(_dataFile, cv::FileStorage::READ);
481  cv::FileNode node = fs.getFirstTopLevelNode();
482 
483  cv::FileNodeIterator it = node["model-roi"].begin(), it_end;
484  it >> modelROI.x >> modelROI.y >> modelROI.width >> modelROI.height;
485 
486  ldetector.read(node["detector"]);
487  fernClassifier.read(node["fern-classifier"]);
488 
489  const cv::FileNode node_ = node["model-points"];
490  cv::read(node_, modelPoints);
491 
492  cv::LDetector d(radius, threshold, nbOctave, nbView, patchSize, dist);
493  ldetector = d;
494  hasLearn = true;
495 }
496 
497 
504 void
505 vpFernClassifier::record(const std::string& _objectName, const std::string& _dataFile )
506 {
507  /* part of code from OpenCV planarObjectDetector */
508  cv::FileStorage fs(_dataFile, cv::FileStorage::WRITE);
509 
510  cv::WriteStructContext ws(fs, _objectName, CV_NODE_MAP);
511 
512  {
513  cv::WriteStructContext wsroi(fs, "model-roi", CV_NODE_SEQ + CV_NODE_FLOW);
514  cv::write(fs, modelROI_Ref.x);
515  cv::write(fs, modelROI_Ref.y);
516  cv::write(fs, modelROI_Ref.width);
517  cv::write(fs, modelROI_Ref.height);
518  }
519 
520  ldetector.write(fs, "detector");
521  cv::write(fs, "model-points", modelPoints);
522  fernClassifier.write(fs, "fern-classifier");
523 }
524 
525 
526 
533 void
535 {
536  if(curIplImg != NULL){
537  cvResetImageROI(curIplImg);
538  if((curIplImg->width % 8) == 0){
539  curIplImg->imageData = NULL;
540  cvReleaseImageHeader(&curIplImg);
541  }else{
542  cvReleaseImage(&curIplImg);
543  }
544  curIplImg = NULL;
545  }
546 
547  if((_I.getWidth()%8) == 0){
548  curIplImg = cvCreateImageHeader(cvSize((int)_I.getWidth(), (int)_I.getHeight()), IPL_DEPTH_8U, 1);
549  if(curIplImg != NULL){
550  curIplImg->imageData = (char*)_I.bitmap;
551  }else{
552  throw vpException(vpException::memoryAllocationError, "Could not create the image in the OpenCV format.");
553  }
554  }else{
556  }
557  if(curIplImg == NULL){
558  std::cout << "!> conversion failed" << std::endl;
559  throw vpException(vpException::notInitialized , "conversion failed");
560  }
561 }
562 
563 #endif
564 
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:174
double get_v() const
Definition: vpImagePoint.h:263
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:194
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: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.
void setImage(const vpImage< unsigned char > &_I)
double get_u() const
Definition: vpImagePoint.h:252
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:205
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:158
double getWidth() const
Definition: vpRect.h:193
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:169
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:85
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:161
int ClassifierSize
Size of the classifier.
cv::Rect modelROI
the ROI for the reference image.