CLAHE Python bindings
[profile/ivi/opencv.git] / samples / ocl / surf_matcher.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
14 // Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // @Authors
18 //    Peng Xiao, pengxiao@multicorewareinc.com
19 //
20 // Redistribution and use in source and binary forms, with or without modification,
21 // are permitted provided that the following conditions are met:
22 //
23 //   * Redistribution's of source code must retain the above copyright notice,
24 //     this list of conditions and the following disclaimer.
25 //
26 //   * Redistribution's in binary form must reproduce the above copyright notice,
27 //     this list of conditions and the following disclaimer in the documentation
28 //     and/or other oclMaterials provided with the distribution.
29 //
30 //   * The name of the copyright holders may not be used to endorse or promote products
31 //     derived from this software without specific prior written permission.
32 //
33 // This software is provided by the copyright holders and contributors as is and
34 // any express or implied warranties, including, but not limited to, the implied
35 // warranties of merchantability and fitness for a particular purpose are disclaimed.
36 // In no event shall the Intel Corporation or contributors be liable for any direct,
37 // indirect, incidental, special, exemplary, or consequential damages
38 // (including, but not limited to, procurement of substitute goods or services;
39 // loss of use, data, or profits; or business interruption) however caused
40 // and on any theory of liability, whether in contract, strict liability,
41 // or tort (including negligence or otherwise) arising in any way out of
42 // the use of this software, even if advised of the possibility of such damage.
43 //
44 //M*/
45
46 #include <iostream>
47 #include <stdio.h>
48 #include "opencv2/core/core.hpp"
49 #include "opencv2/highgui/highgui.hpp"
50 #include "opencv2/ocl/ocl.hpp"
51 #include "opencv2/nonfree/ocl.hpp"
52 #include "opencv2/calib3d/calib3d.hpp"
53 #include "opencv2/nonfree/nonfree.hpp"
54
55 using namespace cv;
56 using namespace cv::ocl;
57
58 const int LOOP_NUM = 10;
59 const int GOOD_PTS_MAX = 50;
60 const float GOOD_PORTION = 0.15f;
61
62 namespace
63 {
64 void help();
65
66 void help()
67 {
68     std::cout << "\nThis program demonstrates using SURF_OCL features detector and descriptor extractor" << std::endl;
69     std::cout << "\nUsage:\n\tsurf_matcher --left <image1> --right <image2> [-c]" << std::endl;
70     std::cout << "\nExample:\n\tsurf_matcher --left box.png --right box_in_scene.png" << std::endl;
71 }
72
73 int64 work_begin = 0;
74 int64 work_end = 0;
75
76 void workBegin() 
77
78     work_begin = getTickCount();
79 }
80 void workEnd()
81 {
82     work_end = getTickCount() - work_begin;
83 }
84 double getTime(){
85     return work_end /((double)cvGetTickFrequency() * 1000.);
86 }
87
88 template<class KPDetector>
89 struct SURFDetector
90 {
91     KPDetector surf;
92     SURFDetector(double hessian = 800.0)
93         :surf(hessian)
94     {
95     }
96     template<class T>
97     void operator()(const T& in, const T& mask, vector<cv::KeyPoint>& pts, T& descriptors, bool useProvided = false)
98     {
99         surf(in, mask, pts, descriptors, useProvided);
100     }
101 };
102
103 template<class KPMatcher>
104 struct SURFMatcher
105 {
106     KPMatcher matcher;
107     template<class T>
108     void match(const T& in1, const T& in2, vector<cv::DMatch>& matches)
109     {
110         matcher.match(in1, in2, matches);
111     }
112 };
113
114 Mat drawGoodMatches(
115     const Mat& cpu_img1,
116     const Mat& cpu_img2,
117     const vector<KeyPoint>& keypoints1, 
118     const vector<KeyPoint>& keypoints2, 
119     vector<DMatch>& matches,
120     vector<Point2f>& scene_corners_
121     )
122 {
123     //-- Sort matches and preserve top 10% matches 
124     std::sort(matches.begin(), matches.end());
125     std::vector< DMatch > good_matches;
126     double minDist = matches.front().distance,
127         maxDist = matches.back().distance;
128
129     const int ptsPairs = std::min(GOOD_PTS_MAX, (int)(matches.size() * GOOD_PORTION));
130     for( int i = 0; i < ptsPairs; i++ )
131     {
132         good_matches.push_back( matches[i] );
133     }
134     std::cout << "\nMax distance: " << maxDist << std::endl;
135     std::cout << "Min distance: " << minDist << std::endl;
136
137     std::cout << "Calculating homography using " << ptsPairs << " point pairs." << std::endl;
138
139     // drawing the results
140     Mat img_matches;
141     drawMatches( cpu_img1, keypoints1, cpu_img2, keypoints2,
142         good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
143         vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS  );
144
145     //-- Localize the object
146     std::vector<Point2f> obj;
147     std::vector<Point2f> scene;
148
149     for( size_t i = 0; i < good_matches.size(); i++ )
150     {
151         //-- Get the keypoints from the good matches
152         obj.push_back( keypoints1[ good_matches[i].queryIdx ].pt );
153         scene.push_back( keypoints2[ good_matches[i].trainIdx ].pt );
154     }
155     //-- Get the corners from the image_1 ( the object to be "detected" )
156     std::vector<Point2f> obj_corners(4);
157     obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint( cpu_img1.cols, 0 );
158     obj_corners[2] = cvPoint( cpu_img1.cols, cpu_img1.rows ); obj_corners[3] = cvPoint( 0, cpu_img1.rows );
159     std::vector<Point2f> scene_corners(4);
160     
161     Mat H = findHomography( obj, scene, CV_RANSAC );
162     perspectiveTransform( obj_corners, scene_corners, H);
163
164     scene_corners_ = scene_corners;
165     
166     //-- Draw lines between the corners (the mapped object in the scene - image_2 )
167     line( img_matches, 
168         scene_corners[0] + Point2f( (float)cpu_img1.cols, 0), scene_corners[1] + Point2f( (float)cpu_img1.cols, 0), 
169         Scalar( 0, 255, 0), 2, CV_AA );
170     line( img_matches, 
171         scene_corners[1] + Point2f( (float)cpu_img1.cols, 0), scene_corners[2] + Point2f( (float)cpu_img1.cols, 0), 
172         Scalar( 0, 255, 0), 2, CV_AA );
173     line( img_matches, 
174         scene_corners[2] + Point2f( (float)cpu_img1.cols, 0), scene_corners[3] + Point2f( (float)cpu_img1.cols, 0), 
175         Scalar( 0, 255, 0), 2, CV_AA );
176     line( img_matches, 
177         scene_corners[3] + Point2f( (float)cpu_img1.cols, 0), scene_corners[0] + Point2f( (float)cpu_img1.cols, 0), 
178         Scalar( 0, 255, 0), 2, CV_AA );
179     return img_matches;
180 }
181
182 }
183 ////////////////////////////////////////////////////
184 // This program demonstrates the usage of SURF_OCL.
185 // use cpu findHomography interface to calculate the transformation matrix
186 int main(int argc, char* argv[])
187 {
188     vector<cv::ocl::Info> info;
189     if(cv::ocl::getDevice(info) == 0)
190     {
191         std::cout << "Error: Did not find a valid OpenCL device!" << std::endl;
192         return -1;
193     }
194     ocl::setDevice(info[0]);
195
196     Mat cpu_img1, cpu_img2, cpu_img1_grey, cpu_img2_grey;
197     oclMat img1, img2;
198     bool useCPU = false;
199     bool useGPU = false;
200     bool useALL = false;
201
202     for (int i = 1; i < argc; ++i)
203     {
204         if (string(argv[i]) == "--left")
205         {
206             cpu_img1 = imread(argv[++i]);
207             CV_Assert(!cpu_img1.empty());
208             cvtColor(cpu_img1, cpu_img1_grey, CV_BGR2GRAY);
209             img1 = cpu_img1_grey;
210         }
211         else if (string(argv[i]) == "--right")
212         {
213             cpu_img2 = imread(argv[++i]);
214             CV_Assert(!cpu_img2.empty());
215             cvtColor(cpu_img2, cpu_img2_grey, CV_BGR2GRAY);
216             img2 = cpu_img2_grey;
217         }
218         else if (string(argv[i]) == "-c")
219         {
220             useCPU = true;
221             useGPU = false;
222             useALL = false;
223         }else if(string(argv[i]) == "-g")
224         {
225             useGPU = true;
226             useCPU = false;
227             useALL = false;
228         }else if(string(argv[i]) == "-a")
229         {
230             useALL = true;
231             useCPU = false;
232             useGPU = false;
233         }
234         else if (string(argv[i]) == "--help")
235         {
236             help();
237             return -1;
238         }
239     }
240     if(!useCPU)
241     {
242         std::cout
243             << "Device name:"
244             << info[0].DeviceName[0]
245         << std::endl;
246     }
247     double surf_time = 0.;
248
249     //declare input/output
250     vector<KeyPoint> keypoints1, keypoints2;
251     vector<DMatch> matches;
252
253     vector<KeyPoint> gpu_keypoints1;
254     vector<KeyPoint> gpu_keypoints2;
255     vector<DMatch> gpu_matches;
256
257     Mat descriptors1CPU, descriptors2CPU;
258
259     oclMat keypoints1GPU, keypoints2GPU;
260     oclMat descriptors1GPU, descriptors2GPU;
261
262     //instantiate detectors/matchers
263     SURFDetector<SURF>     cpp_surf;
264     SURFDetector<SURF_OCL> ocl_surf;
265     
266     SURFMatcher<BFMatcher>      cpp_matcher;
267     SURFMatcher<BFMatcher_OCL>  ocl_matcher;
268
269     //-- start of timing section
270     if (useCPU) 
271     {
272         for (int i = 0; i <= LOOP_NUM; i++)
273         {
274             if(i == 1) workBegin();
275             cpp_surf(cpu_img1_grey, Mat(), keypoints1, descriptors1CPU);
276             cpp_surf(cpu_img2_grey, Mat(), keypoints2, descriptors2CPU);
277             cpp_matcher.match(descriptors1CPU, descriptors2CPU, matches);
278         }
279         workEnd();
280         std::cout << "CPP: FOUND " << keypoints1.size() << " keypoints on first image" << std::endl;
281         std::cout << "CPP: FOUND " << keypoints2.size() << " keypoints on second image" << std::endl;
282
283         surf_time = getTime();
284         std::cout << "SURF run time: " << surf_time / LOOP_NUM << " ms" << std::endl<<"\n";
285     }
286     else if(useGPU)
287     {
288         for (int i = 0; i <= LOOP_NUM; i++)
289         {
290             if(i == 1) workBegin();
291             ocl_surf(img1, oclMat(), keypoints1, descriptors1GPU);
292             ocl_surf(img2, oclMat(), keypoints2, descriptors2GPU);
293             ocl_matcher.match(descriptors1GPU, descriptors2GPU, matches);
294         }
295         workEnd();
296         std::cout << "OCL: FOUND " << keypoints1.size() << " keypoints on first image" << std::endl;
297         std::cout << "OCL: FOUND " << keypoints2.size() << " keypoints on second image" << std::endl;
298
299         surf_time = getTime();
300         std::cout << "SURF run time: " << surf_time / LOOP_NUM << " ms" << std::endl<<"\n";
301     }else
302     {
303         //cpu runs
304         for (int i = 0; i <= LOOP_NUM; i++)
305         {
306             if(i == 1) workBegin();
307             cpp_surf(cpu_img1_grey, Mat(), keypoints1, descriptors1CPU);
308             cpp_surf(cpu_img2_grey, Mat(), keypoints2, descriptors2CPU);
309             cpp_matcher.match(descriptors1CPU, descriptors2CPU, matches);
310         }
311         workEnd();
312         std::cout << "\nCPP: FOUND " << keypoints1.size() << " keypoints on first image" << std::endl;
313         std::cout << "CPP: FOUND " << keypoints2.size() << " keypoints on second image" << std::endl;
314
315         surf_time = getTime();
316         std::cout << "(CPP)SURF run time: " << surf_time / LOOP_NUM << " ms" << std::endl;
317
318         //gpu runs
319         for (int i = 0; i <= LOOP_NUM; i++)
320         {
321             if(i == 1) workBegin();
322             ocl_surf(img1, oclMat(), gpu_keypoints1, descriptors1GPU);
323             ocl_surf(img2, oclMat(), gpu_keypoints2, descriptors2GPU);
324             ocl_matcher.match(descriptors1GPU, descriptors2GPU, gpu_matches);
325         }
326         workEnd();
327         std::cout << "\nOCL: FOUND " << keypoints1.size() << " keypoints on first image" << std::endl;
328         std::cout << "OCL: FOUND " << keypoints2.size() << " keypoints on second image" << std::endl;
329
330         surf_time = getTime();
331         std::cout << "(OCL)SURF run time: " << surf_time / LOOP_NUM << " ms" << std::endl<<"\n";
332
333     }
334
335     //--------------------------------------------------------------------------
336     std::vector<Point2f> cpu_corner;
337     Mat img_matches = drawGoodMatches(cpu_img1, cpu_img2, keypoints1, keypoints2, matches, cpu_corner);
338
339     std::vector<Point2f> gpu_corner;
340     Mat ocl_img_matches;
341     if(useALL || (!useCPU&&!useGPU))
342     {
343         ocl_img_matches = drawGoodMatches(cpu_img1, cpu_img2, gpu_keypoints1, gpu_keypoints2, gpu_matches, gpu_corner);
344
345         //check accuracy
346         std::cout<<"\nCheck accuracy:\n";
347
348         if(cpu_corner.size()!=gpu_corner.size())
349             std::cout<<"Failed\n";
350         else
351         {
352             bool result = false;
353             for(size_t i = 0; i < cpu_corner.size(); i++)
354             {
355                 if((std::abs(cpu_corner[i].x - gpu_corner[i].x) > 10)
356                     ||(std::abs(cpu_corner[i].y - gpu_corner[i].y) > 10))
357                 {
358                     std::cout<<"Failed\n";
359                     result = false;
360                     break;
361                 }
362                 result = true;
363             } 
364             if(result)
365                 std::cout<<"Passed\n";
366         }
367     }
368
369     //-- Show detected matches
370     if (useCPU)
371     {
372         namedWindow("cpu surf matches", 0);
373         imshow("cpu surf matches", img_matches);
374     }
375     else if(useGPU)
376     {
377         namedWindow("ocl surf matches", 0);
378         imshow("ocl surf matches", img_matches);
379     }else
380     {
381         namedWindow("cpu surf matches", 0);
382         imshow("cpu surf matches", img_matches);
383
384         namedWindow("ocl surf matches", 0);
385         imshow("ocl surf matches", ocl_img_matches);
386     }
387     waitKey(0);
388     return 0;
389 }