example/main.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2011-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the name of the Universite de Sherbrooke nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 #include <stdio.h>
29 
30 // Qt stuff
31 #include <QtCore/QTime>
32 #include <QtCore/QTimer>
33 #include <QApplication>
34 #include <QGraphicsRectItem>
35 #include <QPen>
36 #include <QColor>
37 
38 // OpenCV stuff
39 #include <opencv2/core/core.hpp>
40 #include <opencv2/highgui/highgui.hpp>
41 #include <opencv2/features2d/features2d.hpp>
42 #include <opencv2/calib3d/calib3d.hpp> // for homography
43 
44 #include <opencv2/opencv_modules.hpp>
45 
46 #ifdef HAVE_OPENCV_NONFREE
47  #if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >=4
48  #include <opencv2/nonfree/gpu.hpp>
49  #include <opencv2/nonfree/features2d.hpp>
50  #endif
51 #endif
52 #ifdef HAVE_OPENCV_XFEATURES2D
53  #include <opencv2/xfeatures2d.hpp>
54  #include <opencv2/xfeatures2d/cuda.hpp>
55 #endif
56 
57 
58 // From this project
59 #include "find_object/ObjWidget.h"
60 #include "find_object/QtOpenCV.h"
61 
62 using namespace find_object;
63 
64 void showUsage()
65 {
66  printf("\n");
67  printf("Usage :\n");
68  printf(" ./example object.png scene.png\n");
69  exit(1);
70 }
71 
72 int main(int argc, char * argv[])
73 {
74  if(argc<3)
75  {
76  showUsage();
77  }
78  QTime time;
79 
80  // GUI stuff
81  QApplication app(argc, argv);
82 
83  time.start();
84  //Load as grayscale
85  cv::Mat objectImg = cv::imread(argv[1], cv::IMREAD_GRAYSCALE);
86  cv::Mat sceneImg = cv::imread(argv[2], cv::IMREAD_GRAYSCALE);
87 
88  if(!objectImg.empty() && !sceneImg.empty())
89  {
90  printf("Loading images: %d ms\n", time.restart());
91  std::vector<cv::KeyPoint> objectKeypoints;
92  std::vector<cv::KeyPoint> sceneKeypoints;
93  cv::Mat objectDescriptors;
94  cv::Mat sceneDescriptors;
95 
97  // EXTRACT KEYPOINTS
99  cv::Ptr<cv::FeatureDetector> detector;
100  // The detector can be any of (see OpenCV features2d.hpp):
101 #if CV_MAJOR_VERSION == 2
102  // detector = cv::Ptr(new cv::DenseFeatureDetector());
103  // detector = cv::Ptr(new cv::FastFeatureDetector());
104  // detector = cv::Ptr(new cv::GFTTDetector());
105  // detector = cv::Ptr(new cv::MSER());
106  // detector = cv::Ptr(new cv::ORB());
107  detector = cv::Ptr<cv::FeatureDetector>(new cv::SIFT());
108  // detector = cv::Ptr(new cv::StarFeatureDetector());
109  // detector = cv::Ptr(new cv::SURF(600.0));
110  // detector = cv::Ptr(new cv::BRISK());
111 #elif CV_MAJOR_VERSION < 4 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION < 3)
112  detector = cv::xfeatures2d::SIFT::create();
113 #else // >= 4.3.0
114  detector = cv::SIFT::create();
115 #endif
116  detector->detect(objectImg, objectKeypoints);
117  printf("Object: %d keypoints detected in %d ms\n", (int)objectKeypoints.size(), time.restart());
118  detector->detect(sceneImg, sceneKeypoints);
119  printf("Scene: %d keypoints detected in %d ms\n", (int)sceneKeypoints.size(), time.restart());
120 
122  // EXTRACT DESCRIPTORS
124  cv::Ptr<cv::DescriptorExtractor> extractor;
125 #if CV_MAJOR_VERSION == 2
126  // The extractor can be any of (see OpenCV features2d.hpp):
127  // extractor = cv::Ptr(new cv::BriefDescriptorExtractor());
128  // extractor = cv::Ptr(new cv::ORB());
129  extractor = cv::Ptr<cv::DescriptorExtractor>(new cv::SIFT());
130  // extractor = cv::Ptr(new cv::SURF(600.0));
131  // extractor = cv::Ptr(new cv::BRISK());
132  // extractor = cv::Ptr(new cv::FREAK());
133 #elif CV_MAJOR_VERSION < 4 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION < 3)
134  extractor = cv::xfeatures2d::SIFT::create();
135 #else // >= 4.3.0
136  extractor = cv::SIFT::create();
137 #endif
138  extractor->compute(objectImg, objectKeypoints, objectDescriptors);
139  printf("Object: %d descriptors extracted in %d ms\n", objectDescriptors.rows, time.restart());
140  extractor->compute(sceneImg, sceneKeypoints, sceneDescriptors);
141  printf("Scene: %d descriptors extracted in %d ms\n", sceneDescriptors.rows, time.restart());
142 
144  // NEAREST NEIGHBOR MATCHING USING FLANN LIBRARY (included in OpenCV)
146  cv::Mat results;
147  cv::Mat dists;
148  std::vector<std::vector<cv::DMatch> > matches;
149  int k=2; // find the 2 nearest neighbors
150  bool useBFMatcher = false; // SET TO TRUE TO USE BRUTE FORCE MATCHER
151  if(objectDescriptors.type()==CV_8U)
152  {
153  // Binary descriptors detected (from ORB, Brief, BRISK, FREAK)
154  printf("Binary descriptors detected...\n");
155  if(useBFMatcher)
156  {
157  cv::BFMatcher matcher(cv::NORM_HAMMING); // use cv::NORM_HAMMING2 for ORB descriptor with WTA_K == 3 or 4 (see ORB constructor)
158  matcher.knnMatch(objectDescriptors, sceneDescriptors, matches, k);
159  }
160  else
161  {
162  // Create Flann LSH index
163  cv::flann::Index flannIndex(sceneDescriptors, cv::flann::LshIndexParams(12, 20, 2), cvflann::FLANN_DIST_HAMMING);
164  printf("Time creating FLANN LSH index = %d ms\n", time.restart());
165 
166  // search (nearest neighbor)
167  flannIndex.knnSearch(objectDescriptors, results, dists, k, cv::flann::SearchParams() );
168  }
169  }
170  else
171  {
172  // assume it is CV_32F
173  printf("Float descriptors detected...\n");
174  if(useBFMatcher)
175  {
176  cv::BFMatcher matcher(cv::NORM_L2);
177  matcher.knnMatch(objectDescriptors, sceneDescriptors, matches, k);
178  }
179  else
180  {
181  // Create Flann KDTree index
182  cv::flann::Index flannIndex(sceneDescriptors, cv::flann::KDTreeIndexParams(), cvflann::FLANN_DIST_EUCLIDEAN);
183  printf("Time creating FLANN KDTree index = %d ms\n", time.restart());
184 
185  // search (nearest neighbor)
186  flannIndex.knnSearch(objectDescriptors, results, dists, k, cv::flann::SearchParams() );
187  }
188  }
189  printf("Time nearest neighbor search = %d ms\n", time.restart());
190 
191  // Conversion to CV_32F if needed
192  if(dists.type() == CV_32S)
193  {
194  cv::Mat temp;
195  dists.convertTo(temp, CV_32F);
196  dists = temp;
197  }
198 
199 
201  // PROCESS NEAREST NEIGHBOR RESULTS
203  // Set gui data
204  ObjWidget objWidget(0, objectKeypoints, QMultiMap<int,int>(), cvtCvMat2QImage(objectImg));
205  ObjWidget sceneWidget(0, sceneKeypoints, QMultiMap<int,int>(), cvtCvMat2QImage(sceneImg));
206 
207  // Find correspondences by NNDR (Nearest Neighbor Distance Ratio)
208  float nndrRatio = 0.8f;
209  std::vector<cv::Point2f> mpts_1, mpts_2; // Used for homography
210  std::vector<int> indexes_1, indexes_2; // Used for homography
211  std::vector<uchar> outlier_mask; // Used for homography
212  // Check if this descriptor matches with those of the objects
213  if(!useBFMatcher)
214  {
215  for(int i=0; i<objectDescriptors.rows; ++i)
216  {
217  // Apply NNDR
218  //printf("q=%d dist1=%f dist2=%f\n", i, dists.at<float>(i,0), dists.at<float>(i,1));
219  if(results.at<int>(i,0) >= 0 && results.at<int>(i,1) >= 0 &&
220  dists.at<float>(i,0) <= nndrRatio * dists.at<float>(i,1))
221  {
222  mpts_1.push_back(objectKeypoints.at(i).pt);
223  indexes_1.push_back(i);
224 
225  mpts_2.push_back(sceneKeypoints.at(results.at<int>(i,0)).pt);
226  indexes_2.push_back(results.at<int>(i,0));
227  }
228  }
229  }
230  else
231  {
232  for(unsigned int i=0; i<matches.size(); ++i)
233  {
234  // Apply NNDR
235  //printf("q=%d dist1=%f dist2=%f\n", matches.at(i).at(0).queryIdx, matches.at(i).at(0).distance, matches.at(i).at(1).distance);
236  if(matches.at(i).size() == 2 &&
237  matches.at(i).at(0).distance <= nndrRatio * matches.at(i).at(1).distance)
238  {
239  mpts_1.push_back(objectKeypoints.at(matches.at(i).at(0).queryIdx).pt);
240  indexes_1.push_back(matches.at(i).at(0).queryIdx);
241 
242  mpts_2.push_back(sceneKeypoints.at(matches.at(i).at(0).trainIdx).pt);
243  indexes_2.push_back(matches.at(i).at(0).trainIdx);
244  }
245  }
246  }
247 
248  // FIND HOMOGRAPHY
249  unsigned int minInliers = 8;
250  if(mpts_1.size() >= minInliers)
251  {
252  time.start();
253  cv::Mat H = findHomography(mpts_1,
254  mpts_2,
255  cv::RANSAC,
256  1.0,
257  outlier_mask);
258  printf("Time finding homography = %d ms\n", time.restart());
259  int inliers=0, outliers=0;
260  for(unsigned int k=0; k<mpts_1.size();++k)
261  {
262  if(outlier_mask.at(k))
263  {
264  ++inliers;
265  }
266  else
267  {
268  ++outliers;
269  }
270  }
271  QTransform hTransform(
272  H.at<double>(0,0), H.at<double>(1,0), H.at<double>(2,0),
273  H.at<double>(0,1), H.at<double>(1,1), H.at<double>(2,1),
274  H.at<double>(0,2), H.at<double>(1,2), H.at<double>(2,2));
275 
276  // GUI : Change color and add homography rectangle
277  QColor color(Qt::green);
278  int alpha = 130;
279  color.setAlpha(alpha);
280  for(unsigned int k=0; k<mpts_1.size();++k)
281  {
282  if(outlier_mask.at(k))
283  {
284  objWidget.setKptColor(indexes_1.at(k), color);
285  sceneWidget.setKptColor(indexes_2.at(k), color);
286  }
287  else
288  {
289  objWidget.setKptColor(indexes_1.at(k), QColor(255,0,0,alpha));
290  sceneWidget.setKptColor(indexes_2.at(k), QColor(255,0,0,alpha));
291  }
292  }
293  QPen rectPen(color);
294  rectPen.setWidth(4);
295  QGraphicsRectItem * rectItem = new QGraphicsRectItem(objWidget.pixmap().rect());
296  rectItem->setPen(rectPen);
297  rectItem->setTransform(hTransform);
298  sceneWidget.addRect(rectItem);
299  printf("Inliers=%d Outliers=%d\n", inliers, outliers);
300  }
301  else
302  {
303  printf("Not enough matches (%d) for homography...\n", (int)mpts_1.size());
304  }
305 
306  // Wait for gui
307  objWidget.setGraphicsViewMode(false);
308  objWidget.setWindowTitle("Object");
309  if(objWidget.pixmap().width() <= 800)
310  {
311  objWidget.setMinimumSize(objWidget.pixmap().width(), objWidget.pixmap().height());
312  }
313  else
314  {
315  objWidget.setMinimumSize(800, 600);
316  objWidget.setAutoScale(false);
317  }
318 
319  sceneWidget.setGraphicsViewMode(false);
320  sceneWidget.setWindowTitle("Scene");
321  if(sceneWidget.pixmap().width() <= 800)
322  {
323  sceneWidget.setMinimumSize(sceneWidget.pixmap().width(), sceneWidget.pixmap().height());
324  }
325  else
326  {
327  sceneWidget.setMinimumSize(800, 600);
328  sceneWidget.setAutoScale(false);
329  }
330 
331  sceneWidget.show();
332  objWidget.show();
333 
334  int r = app.exec();
335  printf("Closing...\n");
336 
337  return r;
338  }
339  else
340  {
341  printf("Images are not valid!\n");
342  showUsage();
343  }
344 
345  return 1;
346 }
app
const QPixmap & pixmap() const
Definition: ObjWidget.h:83
void setKptColor(int index, const QColor &color)
Definition: ObjWidget.cpp:346
void setAutoScale(bool autoScale)
Definition: ObjWidget.cpp:179
void addRect(QGraphicsRectItem *rect)
Definition: ObjWidget.cpp:377
void showUsage()
void setGraphicsViewMode(bool on)
Definition: ObjWidget.cpp:146
int main(int argc, char *argv[])
FINDOBJECT_EXP QImage cvtCvMat2QImage(const cv::Mat &image, bool isBgr=true)
Definition: QtOpenCV.cpp:34


find_object_2d
Author(s): Mathieu Labbe
autogenerated on Mon Dec 12 2022 03:20:09