1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Planar surface detection tool.
33  *
34  * Authors:
35  * Romain Tallonneau
36  *
37  *****************************************************************************/
38 
39 #ifndef VPPLANAROBJECTDETECTOR_H_
40 #define VPPLANAROBJECTDETECTOR_H_
41 
42 #include <visp3/core/vpConfig.h>
43 
44 #if (VISP_HAVE_OPENCV_VERSION >= 0x020000) &&                                                                          \
45     (VISP_HAVE_OPENCV_VERSION < 0x030000) // Require opencv >= 2.0.0 and < 3.0.0
46 
47 #if (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
48 #include <opencv2/calib3d/calib3d.hpp>
49 #include <opencv2/features2d/features2d.hpp>
50 #include <opencv2/imgproc/imgproc.hpp>
51 #elif (VISP_HAVE_OPENCV_VERSION >= 0x020000) // Require opencv >= 2.0.0
52 #include <cv.h>
53 #include <cvaux.hpp>
54 #endif
55 
56 #include <visp3/core/vpCameraParameters.h>
57 #include <visp3/core/vpHomogeneousMatrix.h>
58 #include <visp3/core/vpImage.h>
59 #include <visp3/core/vpImagePoint.h>
60 #include <visp3/core/vpPoint.h>
61 #include <visp3/core/vpRect.h>
62 #include <visp3/vision/vpFernClassifier.h>
63 #include <visp3/vision/vpHomography.h>
64 
65 /*!
66   \class vpPlanarObjectDetector
67   \ingroup group_vision_keypoints
68 
69   \brief Class used to detect a planar surface.
70 
71   \deprecated This class is deprecated with OpenCV 3.0.0 or more recent.
72 
73   This class allows to learn and recognise a surface in an image based on the
74   Fern Classifier or any other point of interest matching class.
75 
76   It uses the class vpFernClassifier to extract points of interest in a
77   reference image. These points are recorded and a classifier is trained to
78   recognises them.
79 
80   In this class the points detected are assumed to belong to a planar surface.
81   Therefore an homography can be computed between the reference image and the
82   current image if the object is detected in the image.
83 
84   A robust method (RANSAC) is used to remove outliers in the matching process.
85 
86   The following example shows how to use the class.
87 
88   \code
89 #include <visp3/core/vpDisplay.h>
90 #include <visp3/core/vpImage.h>
91 #include <visp3/vision/vpPlanarObjectDetector.h>
92 
93 #if VISP_HAVE_OPENCV_VERSION >= 0x020000 // Surf Fern classifier only
94 available since 2.1.0 int main()
95 {
96   vpImage<unsigned char> Ireference;
97   vpImage<unsigned char> Icurrent;
98   vpPlanarObjectDetector planar;
99 
100   //First grab the reference image Ireference
101 
102   //Select a part of the image by clincking on two points which define a rectangle
103   vpImagePoint corners[2];
104   for (int i=0 ; i < 2 ; i++) {
105     vpDisplay::getClick(Ireference, corners[i]);
106   }
107 
108   //Build the reference points (and train the classifier).
109   int nbrRef;
110   unsigned int height, width;
111   height = (unsigned int)(corners[1].get_i() - corners[0].get_i());
112   width = (unsigned int)(corners[1].get_j() - corners[0].get_j());
113   nbrRef = planar.buildReference(Ireference, corners[0], height, width);
114 
115   //Then grab another image which represents the current image Icurrent
116 
117   //Match points between the reference points and the current points computed in the current image.
118   bool isDetected; height = (unsigned int)(corners[1].get_i() - corners[0].get_i());
119   width = (unsigned int)(corners[1].get_j() - corners[0].get_j());
120   isDetected = planar.matchPoint(Icurrent, corners[0], height, width);
121 
122   //Display the matched points
123   if(isDetected){
124     planar.display(Ireference, Icurrent);
125     vpHomography homography;
126     planar.getHomography(homography);
127   }
128   else{
129     std::cerr << "planar surface not detected in the current image" << std::endl;
130   }
131 
132   return(0);
133 }
134 #else
135 int main() {}
136 #endif
137   \endcode
138 
139 */
140 class VISP_EXPORT vpPlanarObjectDetector
141 {
142 protected:
143   //! Fern Classifier used to match the points between a reference image and
144   //! the current image.
145   vpFernClassifier fern;
146 
147   //! Computed homography in the ViSP format.
148   vpHomography homography;
149   //! Computed homography in the OpenCV format.
150   cv::Mat H;
151 
152   //! The estimated new coordinates of the corners (reprojected using the
153   //! homography).
154   std::vector<cv::Point2f> dst_corners;
155 
156   //! Flag to indicate wether the last computed homography is correct or not.
157   bool isCorrect;
158 
159   //! The corners in the reference image
160   std::vector<cv::Point2f> ref_corners;
161 
162   //! The ROI for the reference image.
163   cv::Rect modelROI;
164 
165   //! Vector of the image point in the current image that match after the
166   //! deletion of the outliers with the RANSAC.
167   std::vector<vpImagePoint> currentImagePoints;
168   //! Vector of the image point in the reference image that match after the
169   //! deletion of the outliers with the RANSAC.
170   std::vector<vpImagePoint> refImagePoints;
171 
172   //! Minimal number of point to after the ransac needed to suppose that the
173   //! homography has been correctly computed.
174   unsigned int minNbMatching;
175 
176 public:
177   // constructors and destructors
178   vpPlanarObjectDetector();
179   vpPlanarObjectDetector(const std::string &dataFile, const std::string &objectName);
180   virtual ~vpPlanarObjectDetector();
181 
182   // main functions
183   // creation of reference
184   unsigned int buildReference(const vpImage<unsigned char> &I);
185   unsigned int buildReference(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int height,
186                               unsigned int width);
187   unsigned int buildReference(const vpImage<unsigned char> &I, const vpRect &rectangle);
188 
189   // matching
190   bool matchPoint(const vpImage<unsigned char> &I);
191   bool matchPoint(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int height,
192                   unsigned int width);
193   bool matchPoint(const vpImage<unsigned char> &I, const vpRect &rectangle);
194   // database management
195   void recordDetector(const std::string &objectName, const std::string &dataFile);
196   void load(const std::string &dataFilename, const std::string &objName);
197 
198   // display
199   void display(vpImage<unsigned char> &I, bool displayKpts = false);
200   void display(vpImage<unsigned char> &Iref, vpImage<unsigned char> &Icurrent, bool displayKpts = false);
201 
202   /*!
203     Return the positions of the detected corners.
204 
205     \return a vector of vpImagePoint containing the position of the corners of
206     the planar surface in the current image.
207   */
208   std::vector<vpImagePoint> getDetectedCorners() const;
209 
210   /*!
211     Return a reference to the classifier.
212 
213     \return The fern classifier.
214   */
getFernClassifier()215   vpFernClassifier &getFernClassifier() { return this->fern; }
216 
217   /*!
218     Return the computed homography between the reference image and the current
219     image.
220 
221     \param _H : The computed homography.
222   */
getHomography(vpHomography & _H)223   inline void getHomography(vpHomography &_H) const { _H = this->homography; }
224 
225   /*!
226     Return the number of reference points
227 
228     \return Number of reference points.
229   */
getNbRefPoints()230   inline unsigned int getNbRefPoints() { return (unsigned int)currentImagePoints.size(); }
231 
232   /*!
233     Get the i-th reference point.
234 
235     \throw vpException if _i is out if bound.
236 
237     \param _i : index of the point to get
238     \param _imPoint : image point returned by the
239   */
240   void getReferencePoint(const unsigned int _i, vpImagePoint &_imPoint);
241 
242   /*!
243     Get the nth couple of reference point and current point which have been
244    matched. These points are copied in the vpImagePoint instances given in
245    argument.
246 
247    \param _index : The index of the desired couple of reference point and
248    current point . The index must be between 0 and the number of matched
249    points - 1. \param _referencePoint : The coordinates of the desired
250    reference point are copied here. \param _currentPoint : The coordinates of
251    the desired current point are copied here.
252   */
253   void getMatchedPoints(const unsigned int _index, vpImagePoint &_referencePoint, vpImagePoint &_currentPoint);
254 
255   /*!
256     Set the threshold for the minimal number of point to validate the
257     homography. Default value is 10.
258 
259     \param _min : the new threshold.
260   */
setMinNbPointValidation(const unsigned int _min)261   void setMinNbPointValidation(const unsigned int _min) { this->minNbMatching = _min; }
262 
263   /*!
264     Get the threshold for the minimal number of point to validate the
265     homography. Default value is 10.
266 
267     \return : the current threshold.
268   */
getMinNbPointValidation()269   unsigned int getMinNbPointValidation() const { return this->minNbMatching; }
270 
271 protected:
272   virtual void init();
273   void computeRoi(vpImagePoint *ip, unsigned int nbpt);
274   void initialiseRefCorners(const cv::Rect &_modelROI);
275 };
276 
277 #endif
278 
279 #endif /* VPPLANAROBJECTDETECTOR_H_ */
280