ViSP  2.9.0
vpPlanarObjectDetector.cpp
1 /****************************************************************************
2  *
3  * $Id: vpPlanarObjectDetector.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.txt 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  * Planar surface detection tool.
36  *
37  * Authors:
38  * Romain Tallonneau
39  *
40  *****************************************************************************/
41 
42 #include <visp/vpPlanarObjectDetector.h>
43 
44 #if (VISP_HAVE_OPENCV_VERSION >= 0x020000) // Require opencv >= 2.0.0
45 
46 #include <visp/vpImageConvert.h>
47 #include <visp/vpException.h>
48 #include <visp/vpImagePoint.h>
49 #include <visp/vpDisplay.h>
50 #include <visp/vpDisplayX.h>
51 #include <visp/vpColor.h>
52 #include <visp/vpImageTools.h>
53 
54 #include <vector>
55 #include <iostream>
56 
63  : fern(), homography(), H(), dst_corners(), isCorrect(false), ref_corners(), modelROI(), currentImagePoints(),
64  refImagePoints(), minNbMatching(10)
65 {
66 }
67 
76 vpPlanarObjectDetector::vpPlanarObjectDetector(const std::string& _dataFile, const std::string& _objectName)
77  : fern(), homography(), H(), dst_corners(), isCorrect(false), ref_corners(), modelROI(), currentImagePoints(),
78  refImagePoints(), minNbMatching(10)
79 {
80  load(_dataFile, _objectName);
81 }
82 
86 void
88 {
89 }
90 
97 {
98 
99 }
100 
108 void
110 {
111  if(nbpt < 3){
112  throw vpException(vpException::badValue, "Not enough point to compute the region of interest.");
113  }
114 
115  std::vector < vpImagePoint > ptsx(nbpt);
116  std::vector < vpImagePoint > ptsy(nbpt);
117  for(unsigned int i=0; i<nbpt; i++){
118  ptsx[i] = ptsy[i] = ip[i];
119  }
120 
121  for(unsigned int i=0; i<nbpt; i++){
122  for(unsigned int j=0; j<nbpt-1; j++){
123  if(ptsx[j].get_j() > ptsx[j+1].get_j()){
124  double tmp = ptsx[j+1].get_j();
125  ptsx[j+1].set_j(ptsx[j].get_j());
126  ptsx[j].set_j(tmp);
127  }
128  }
129  }
130  for(unsigned int i=0; i<nbpt; i++){
131  for(unsigned int j=0; j<nbpt-1; j++){
132  if(ptsy[j].get_i() > ptsy[j+1].get_i()){
133  double tmp = ptsy[j+1].get_i();
134  ptsy[j+1].set_i(ptsy[j].get_i());
135  ptsy[j].set_i(tmp);
136  }
137  }
138  }
139 
140 }
141 
142 
153 unsigned int
155 {
156  modelROI.x = 0;
157  modelROI.y = 0;
158  modelROI.width = (int)_I.getWidth();
159  modelROI.height = (int)_I.getHeight();
160 
162 
163  return fern.buildReference(_I);
164 }
165 
166 
180 unsigned int
182  const vpImagePoint &_iP,
183  unsigned int _height, unsigned int _width)
184 {
185  unsigned int res = fern.buildReference(_I, _iP, _height, _width);
186  modelROI.x = (int)_iP.get_u();
187  modelROI.y = (int)_iP.get_v();
188  modelROI.width = (int)_width;
189  modelROI.height = (int)_height;
190 
192 
193  return res;
194 }
195 
196 
197 
208 unsigned int
210  const vpRect _rectangle)
211 {
212  unsigned int res = fern.buildReference(_I, _rectangle);
213 
214  vpImagePoint iP = _rectangle.getTopLeft();
215 
216  modelROI.x = (int)iP.get_u();
217  modelROI.y = (int)iP.get_v();
218  modelROI.width = (int)_rectangle.getWidth();
219  modelROI.height = (int)_rectangle.getHeight();
220 
222 
223  return res;
224 }
225 
226 
237 bool
239 {
240  fern.matchPoint(I);
241 
242  /* compute homography */
243  std::vector<cv::Point2f> refPts = fern.getRefPt();
244  std::vector<cv::Point2f> curPts = fern.getCurPt();
245 
246  for(unsigned int i=0; i<refPts.size(); ++i){
247  refPts[i].x += modelROI.x;
248  refPts[i].y += modelROI.y;
249  }
250  for(unsigned int i=0; i<curPts.size(); ++i){
251  curPts[i].x += modelROI.x;
252  curPts[i].y += modelROI.y;
253  }
254 
255  if(curPts.size() < 4){
256  for (unsigned int i = 0; i < 3; i += 1){
257  for (unsigned int j = 0; j < 3; j += 1){
258  if(i == j){
259  homography[i][j] = 1;
260  }
261  else{
262  homography[i][j] = 0;
263  }
264  }
265  }
266  return false;
267  }
268 
269  /* part of code from OpenCV planarObjectDetector */
270  std::vector<unsigned char> mask;
271  H = cv::findHomography(cv::Mat(refPts), cv::Mat(curPts), mask, cv::RANSAC, 10);
272 
273  if( H.data )
274  {
275  const cv::Mat_<double>& H_tmp = H;
276  dst_corners.resize(4);
277  for(unsigned int i = 0; i < 4; i++ )
278  {
279  cv::Point2f pt = ref_corners[i];
280 
281  double w = 1./(H_tmp(2,0)*pt.x + H_tmp(2,1)*pt.y + H_tmp(2,2));
282  dst_corners[i] = cv::Point2f((float)((H_tmp(0,0)*pt.x + H_tmp(0,1)*pt.y + H_tmp(0,2))*w),
283  (float)((H_tmp(1,0)*pt.x + H_tmp(1,1)*pt.y + H_tmp(1,2))*w));
284  }
285 
286  double* ptr = (double*)H_tmp.data;
287  for(unsigned int i=0; i<9; i++){
288  this->homography[(unsigned int)(i/3)][i%3] = *(ptr++);
289  }
290  isCorrect = true;
291  }
292  else{
293  isCorrect = false;
294  }
295 
296 
297  currentImagePoints.resize(0);
298  refImagePoints.resize(0);
299  for (unsigned int i = 0; i < mask.size(); i += 1){
300  if(mask[i] != 0){
301  vpImagePoint ip;
302  ip.set_i(curPts[i].y);
303  ip.set_j(curPts[i].x);
304  currentImagePoints.push_back(ip);
305  ip.set_i(refPts[i].y);
306  ip.set_j(refPts[i].x);
307  refImagePoints.push_back(ip);
308  }
309  }
310 
311  if(currentImagePoints.size() < minNbMatching){
312  isCorrect = false;
313  }
314 
315  return isCorrect;
316 }
317 
318 
319 
333 bool
335  const vpImagePoint &iP, const unsigned int height, const unsigned int width)
336 {
337  if((iP.get_i()+height) >= I.getHeight()
338  || (iP.get_j()+width) >= I.getWidth()) {
339  vpTRACE("Bad size for the subimage");
341  "Bad size for the subimage"));
342  }
343 
344  vpImage<unsigned char> subImage;
345 
347  (unsigned int)iP.get_i(),
348  (unsigned int)iP.get_j(),
349  height, width, subImage);
350 
351  return this->matchPoint(subImage);
352 }
353 
365 bool
367 {
368  vpImagePoint iP;
369  iP.set_i(rectangle.getTop());
370  iP.set_j(rectangle.getLeft());
371  return (this->matchPoint(I, iP,
372  (unsigned int)rectangle.getHeight(),
373  (unsigned int)rectangle.getWidth()));
374 }
375 
376 
386 void
388 {
389  for(unsigned int i=0; i<dst_corners.size(); i++){
390  vpImagePoint ip1(
391  dst_corners[i].y - modelROI.y,
392  dst_corners[i].x - modelROI.x);
393  vpImagePoint ip2(
394  dst_corners[(i+1)%dst_corners.size()].y - modelROI.y,
395  dst_corners[(i+1)%dst_corners.size()].x - modelROI.x);
396  vpDisplay::displayLine(I, ip1, ip2, vpColor::red) ;
397  }
398 
399  if(displayKpts){
400  for(unsigned int i=0; i<currentImagePoints.size(); ++i){
401  vpImagePoint ip(
402  currentImagePoints[i].get_i() - modelROI.y,
403  currentImagePoints[i].get_j() - modelROI.x);
405  }
406  }
407 }
408 
409 
426 void
428  vpImage<unsigned char> &Icurrent, bool displayKpts)
429 {
430  display(Icurrent, displayKpts);
431 
432  if(displayKpts){
433  for(unsigned int i=0; i<refImagePoints.size(); ++i){
435  }
436  }
437 }
438 
439 
450 void
451 vpPlanarObjectDetector::load(const std::string& dataFilename, const std::string& objName)
452 {
453  fern.load(dataFilename, objName);
456 }
457 
458 
466 void
467 vpPlanarObjectDetector::recordDetector(const std::string& objectName, const std::string& dataFile )
468 {
469  fern.record(objectName, dataFile);
470 }
471 
472 
473 
479 std::vector<vpImagePoint>
481  vpImagePoint ip;
482  std::vector <vpImagePoint> corners;
483  corners.clear();
484  for(unsigned int i=0; i<dst_corners.size(); i++){
485  ip.set_uv( dst_corners[i].x, dst_corners[i].y);
486  corners.push_back(ip);
487  }
488 
489  return corners;
490 }
491 
497 void
499 {
500  cv::Point2f ip;
501 
502  ip.y = (float)_modelROI.y;
503  ip.x = (float)_modelROI.x;
504  ref_corners.push_back(ip);
505 
506  ip.y = (float)(_modelROI.y+_modelROI.height);
507  ip.x = (float)_modelROI.x;
508  ref_corners.push_back(ip);
509 
510  ip.y = (float)(_modelROI.y+_modelROI.height);
511  ip.x = (float)(_modelROI.x+_modelROI.width);
512  ref_corners.push_back(ip);
513 
514  ip.y = (float)_modelROI.y;
515  ip.x = (float)(_modelROI.x+_modelROI.width);
516  ref_corners.push_back(ip);
517 }
518 
519 
520 void
522 {
523  if(_i >= refImagePoints.size()){
524  throw vpException(vpException::fatalError, "index out of bound in getMatchedPoints.");
525  }
526  _imPoint = refImagePoints[_i];
527 }
528 
529 void
530 vpPlanarObjectDetector::getMatchedPoints(const unsigned int _index, vpImagePoint& _referencePoint, vpImagePoint& _currentPoint)
531 {
532 // fern.getMatchedPoints(_index, _referencePoint, _currentPoint);
533  if(_index >= currentImagePoints.size()){
534  throw vpException(vpException::fatalError, "index out of bound in getMatchedPoints.");
535  }
536 
537  _referencePoint = refImagePoints[_index];
538  _currentPoint = currentImagePoints[_index];
539 }
540 
541 #endif
542 
void initialiseRefCorners(const cv::Rect &_modelROI)
double getTop() const
Definition: vpRect.h:174
double get_v() const
Definition: vpImagePoint.h:263
double get_i() const
Definition: vpImagePoint.h:194
unsigned int getWidth() const
Definition: vpImage.h:159
virtual unsigned int matchPoint(const vpImage< unsigned char > &I)
#define vpTRACE
Definition: vpDebug.h:418
void computeRoi(vpImagePoint *ip, const unsigned int nbpt)
void getMatchedPoints(const unsigned int _index, vpImagePoint &_referencePoint, vpImagePoint &_currentPoint)
double get_u() const
Definition: vpImagePoint.h:252
std::vector< cv::Point2f > ref_corners
The corners in the reference image.
void load(const std::string &dataFilename, const std::string &objName)
Load the Fern classifier.
error that can be emited by ViSP classes.
Definition: vpException.h:76
void getReferencePoint(const unsigned int _i, vpImagePoint &_imPoint)
double getHeight() const
Definition: vpRect.h:155
cv::Rect modelROI
The ROI for the reference image.
const std::vector< cv::Point2f > & getRefPt() const
static const vpColor green
Definition: vpColor.h:170
double get_j() const
Definition: vpImagePoint.h:205
vpImagePoint getTopLeft() const
Definition: vpRect.h:180
cv::Mat H
Computed homography in the OpenCV format.
static const vpColor red
Definition: vpColor.h:167
bool matchPoint(const vpImage< unsigned char > &I)
virtual unsigned int buildReference(const vpImage< unsigned char > &I)
std::vector< cv::Point2f > dst_corners
The estimated new coordinates of the corners (reprojected using the homography).
void set_i(const double ii)
Definition: vpImagePoint.h:158
void display(vpImage< unsigned char > &I, bool displayKpts=false)
double getWidth() const
Definition: vpRect.h:193
vpFernClassifier fern
Fern Classifier used to match the points between a reference image and the current image...
std::vector< vpImagePoint > currentImagePoints
Vector of the image point in the current image that match after the deletion of the outliers with the...
vpHomography homography
Computed homography in the ViSP format.
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
unsigned int buildReference(const vpImage< unsigned char > &I)
const std::vector< cv::Point2f > & getCurPt() const
void record(const std::string &_objectName, const std::string &_dataFile)
record the Ferns classifier in the text file
bool isCorrect
Flag to indicate wether the last computed homography is correct or not.
void set_j(const double jj)
Definition: vpImagePoint.h:169
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::Rect getModelROI() const
void recordDetector(const std::string &objectName, const std::string &dataFile)
Record the Ferns classifier in the text file.
unsigned int minNbMatching
Minimal number of point to after the ransac needed to suppose that the homography has been correctly ...
unsigned int getHeight() const
Definition: vpImage.h:150
void set_uv(const double u, const double v)
Definition: vpImagePoint.h:238
Defines a rectangle in the plane.
Definition: vpRect.h:85
std::vector< vpImagePoint > getDetectedCorners() const
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:92
virtual void displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)=0
void load(const std::string &_dataFile, const std::string &)
load the Fern classifier
std::vector< vpImagePoint > refImagePoints
Vector of the image point in the reference image that match after the deletion of the outliers with t...
double getLeft() const
Definition: vpRect.h:161