Commit ade21f14 authored by catree's avatar catree

Add Java and Python code for the following features2d tutorials: Harris corner…

Add Java and Python code for the following features2d tutorials: Harris corner detector, Shi-Tomasi corner detector, Creating your own corner detector, Detecting corners location in subpixels, Feature Detection, Feature Description, Feature Matching with FLANN, Features2D + Homography to find a known object. Use Lowe's ratio test to filter the matches.
parent 0a6d1900
...@@ -20,6 +20,21 @@ ...@@ -20,6 +20,21 @@
volume = {34}, volume = {34},
number = {7} number = {7}
} }
@INPROCEEDINGS{Arandjelovic:2012:TTE:2354409.2355123,
author = {Arandjelovic, Relja},
title = {Three Things Everyone Should Know to Improve Object Retrieval},
booktitle = {Proceedings of the 2012 IEEE Conference on Computer Vision and Pattern Recognition (CVPR)},
series = {CVPR '12},
year = {2012},
isbn = {978-1-4673-1226-4},
pages = {2911--2918},
numpages = {8},
url = {http://dl.acm.org/citation.cfm?id=2354409.2355123},
acmid = {2355123},
publisher = {IEEE Computer Society},
address = {Washington, DC, USA},
keywords = {Vectors,Visualization,Kernel,Standards,Support vector machines,Indexes,Euclidean distance},
}
@ARTICLE{BA83, @ARTICLE{BA83,
author = {Burt, Peter J and Adelson, Edward H}, author = {Burt, Peter J and Adelson, Edward H},
title = {A multiresolution spline with application to image mosaics}, title = {A multiresolution spline with application to image mosaics},
...@@ -515,6 +530,25 @@ ...@@ -515,6 +530,25 @@
volume = {1}, volume = {1},
organization = {IEEE} organization = {IEEE}
} }
@ARTICLE{Lowe:2004:DIF:993451.996342,
author = {Lowe, David G.},
title = {Distinctive Image Features from Scale-Invariant Keypoints},
journal = {Int. J. Comput. Vision},
issue_date = {November 2004},
volume = {60},
number = {2},
month = nov,
year = {2004},
issn = {0920-5691},
pages = {91--110},
numpages = {20},
url = {https://doi.org/10.1023/B:VISI.0000029664.99615.94},
doi = {10.1023/B:VISI.0000029664.99615.94},
acmid = {996342},
publisher = {Kluwer Academic Publishers},
address = {Hingham, MA, USA},
keywords = {image matching, invariant features, object recognition, scale invariance},
}
@INPROCEEDINGS{Lucas81, @INPROCEEDINGS{Lucas81,
author = {Lucas, Bruce D and Kanade, Takeo and others}, author = {Lucas, Bruce D and Kanade, Takeo and others},
title = {An iterative image registration technique with an application to stereo vision.}, title = {An iterative image registration technique with an application to stereo vision.},
......
...@@ -10,74 +10,35 @@ In this tutorial you will learn how to: ...@@ -10,74 +10,35 @@ In this tutorial you will learn how to:
to the keypoints. Specifically: to the keypoints. Specifically:
- Use cv::xfeatures2d::SURF and its function cv::xfeatures2d::SURF::compute to perform the - Use cv::xfeatures2d::SURF and its function cv::xfeatures2d::SURF::compute to perform the
required calculations. required calculations.
- Use a @ref cv::BFMatcher to match the features vector - Use a @ref cv::DescriptorMatcher to match the features vector
- Use the function @ref cv::drawMatches to draw the detected matches. - Use the function @ref cv::drawMatches to draw the detected matches.
\warning You need the <a href="https://github.com/opencv/opencv_contrib">OpenCV contrib modules</a> to be able to use the SURF features
(alternatives are ORB, KAZE, ... features).
Theory Theory
------ ------
Code Code
---- ----
This tutorial code's is shown lines below. @add_toggle_cpp
@code{.cpp} This tutorial code's is shown lines below. You can also download it from
#include <stdio.h> [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/features2D/feature_description/SURF_matching_Demo.cpp)
#include <iostream> @include samples/cpp/tutorial_code/features2D/feature_description/SURF_matching_Demo.cpp
#include "opencv2/core.hpp" @end_toggle
#include "opencv2/features2d.hpp"
#include "opencv2/highgui.hpp" @add_toggle_java
#include "opencv2/xfeatures2d.hpp" This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/features2D/feature_description/SURFMatchingDemo.java)
using namespace cv; @include samples/java/tutorial_code/features2D/feature_description/SURFMatchingDemo.java
using namespace cv::xfeatures2d; @end_toggle
void readme(); @add_toggle_python
This tutorial code's is shown lines below. You can also download it from
/* @function main */ [here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/features2D/feature_description/SURF_matching_Demo.py)
int main( int argc, char** argv ) @include samples/python/tutorial_code/features2D/feature_description/SURF_matching_Demo.py
{ @end_toggle
if( argc != 3 )
{ return -1; }
Mat img_1 = imread( argv[1], IMREAD_GRAYSCALE );
Mat img_2 = imread( argv[2], IMREAD_GRAYSCALE );
if( !img_1.data || !img_2.data )
{ return -1; }
//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
int minHessian = 400;
Ptr<SURF> detector = SURF::create();
detector->setHessianThreshold(minHessian);
std::vector<KeyPoint> keypoints_1, keypoints_2;
Mat descriptors_1, descriptors_2;
detector->detectAndCompute( img_1, Mat(), keypoints_1, descriptors_1 );
detector->detectAndCompute( img_2, Mat(), keypoints_2, descriptors_2 );
//-- Step 2: Matching descriptor vectors with a brute force matcher
BFMatcher matcher(NORM_L2);
std::vector< DMatch > matches;
matcher.match( descriptors_1, descriptors_2, matches );
//-- Draw matches
Mat img_matches;
drawMatches( img_1, keypoints_1, img_2, keypoints_2, matches, img_matches );
//-- Show detected matches
imshow("Matches", img_matches );
waitKey(0);
return 0;
}
/* @function readme */
void readme()
{ std::cout << " Usage: ./SURF_descriptor <img1> <img2>" << std::endl; }
@endcode
Explanation Explanation
----------- -----------
......
...@@ -11,67 +11,32 @@ In this tutorial you will learn how to: ...@@ -11,67 +11,32 @@ In this tutorial you will learn how to:
detection process detection process
- Use the function @ref cv::drawKeypoints to draw the detected keypoints - Use the function @ref cv::drawKeypoints to draw the detected keypoints
\warning You need the <a href="https://github.com/opencv/opencv_contrib">OpenCV contrib modules</a> to be able to use the SURF features
(alternatives are ORB, KAZE, ... features).
Theory Theory
------ ------
Code Code
---- ----
This tutorial code's is shown lines below. @add_toggle_cpp
@code{.cpp} This tutorial code's is shown lines below. You can also download it from
#include <stdio.h> [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/features2D/feature_detection/SURF_detection_Demo.cpp)
#include <iostream> @include samples/cpp/tutorial_code/features2D/feature_detection/SURF_detection_Demo.cpp
#include "opencv2/core.hpp" @end_toggle
#include "opencv2/features2d.hpp"
#include "opencv2/xfeatures2d.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
using namespace cv::xfeatures2d;
void readme();
/* @function main */
int main( int argc, char** argv )
{
if( argc != 3 )
{ readme(); return -1; }
Mat img_1 = imread( argv[1], IMREAD_GRAYSCALE );
Mat img_2 = imread( argv[2], IMREAD_GRAYSCALE );
if( !img_1.data || !img_2.data )
{ std::cout<< " --(!) Error reading images " << std::endl; return -1; }
//-- Step 1: Detect the keypoints using SURF Detector
int minHessian = 400;
Ptr<SURF> detector = SURF::create( minHessian );
std::vector<KeyPoint> keypoints_1, keypoints_2;
detector->detect( img_1, keypoints_1 );
detector->detect( img_2, keypoints_2 );
//-- Draw keypoints
Mat img_keypoints_1; Mat img_keypoints_2;
drawKeypoints( img_1, keypoints_1, img_keypoints_1, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
drawKeypoints( img_2, keypoints_2, img_keypoints_2, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
//-- Show detected (drawn) keypoints
imshow("Keypoints 1", img_keypoints_1 );
imshow("Keypoints 2", img_keypoints_2 );
waitKey(0);
return 0; @add_toggle_java
} This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/features2D/feature_detection/SURFDetectionDemo.java)
@include samples/java/tutorial_code/features2D/feature_detection/SURFDetectionDemo.java
@end_toggle
/* @function readme */ @add_toggle_python
void readme() This tutorial code's is shown lines below. You can also download it from
{ std::cout << " Usage: ./SURF_detector <img1> <img2>" << std::endl; } [here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/features2D/feature_detection/SURF_detection_Demo.py)
@endcode @include samples/python/tutorial_code/features2D/feature_detection/SURF_detection_Demo.py
@end_toggle
Explanation Explanation
----------- -----------
...@@ -79,10 +44,10 @@ Explanation ...@@ -79,10 +44,10 @@ Explanation
Result Result
------ ------
-# Here is the result of the feature detection applied to the first image: -# Here is the result of the feature detection applied to the `box.png` image:
![](images/Feature_Detection_Result_a.jpg) ![](images/Feature_Detection_Result_a.jpg)
-# And here is the result for the second image: -# And here is the result for the `box_in_scene.png` image:
![](images/Feature_Detection_Result_b.jpg) ![](images/Feature_Detection_Result_b.jpg)
...@@ -9,114 +9,57 @@ In this tutorial you will learn how to: ...@@ -9,114 +9,57 @@ In this tutorial you will learn how to:
- Use the @ref cv::FlannBasedMatcher interface in order to perform a quick and efficient matching - Use the @ref cv::FlannBasedMatcher interface in order to perform a quick and efficient matching
by using the @ref flann module by using the @ref flann module
\warning You need the <a href="https://github.com/opencv/opencv_contrib">OpenCV contrib modules</a> to be able to use the SURF features
(alternatives are ORB, KAZE, ... features).
Theory Theory
------ ------
Classical feature descriptors (SIFT, SURF, ...) are usually compared and matched using the Euclidean distance (or L2-norm).
Since SIFT and SURF descriptors represent the histogram of oriented gradient (of the Haar wavelet response for SURF)
in a neighborhood, alternatives of the Euclidean distance are histogram-based metrics (\f$ \chi^{2} \f$, Earth Mover’s Distance (EMD), ...).
Arandjelovic et al. proposed in @cite Arandjelovic:2012:TTE:2354409.2355123 to extend to the RootSIFT descriptor:
> a square root (Hellinger) kernel instead of the standard Euclidean distance to measure the similarity between SIFT descriptors
> leads to a dramatic performance boost in all stages of the pipeline.
Binary descriptors (ORB, BRISK, ...) are matched using the <a href="https://en.wikipedia.org/wiki/Hamming_distance">Hamming distance</a>.
This distance is equivalent to count the number of different elements for binary strings (population count after applying a XOR operation):
\f[ d_{hamming} \left ( a,b \right ) = \sum_{i=0}^{n-1} \left ( a_i \oplus b_i \right ) \f]
To filter the matches, Lowe proposed in @cite Lowe:2004:DIF:993451.996342 to use a distance ratio test to try to eliminate false matches.
The distance ratio between the two nearest matches of a considered keypoint is computed and it is a good match when this value is below
a thresold. Indeed, this ratio allows helping to discriminate between ambiguous matches (distance ratio between the two nearest neighbors is
close to one) and well discriminated matches. The figure below from the SIFT paper illustrates the probability that a match is correct
based on the nearest-neighbor distance ratio test.
![](images/Feature_FlannMatcher_Lowe_ratio_test.png)
Alternative or additional filterering tests are:
- cross check test (good match \f$ \left( f_a, f_b \right) \f$ if feature \f$ f_b \f$ is the best match for \f$ f_a \f$ in \f$ I_b \f$
and feature \f$ f_a \f$ is the best match for \f$ f_b \f$ in \f$ I_a \f$)
- geometric test (eliminate matches that do not fit to a geometric model, e.g. RANSAC or robust homography for planar objects)
Code Code
---- ----
This tutorial code's is shown lines below. @add_toggle_cpp
@code{.cpp} This tutorial code's is shown lines below. You can also download it from
/* [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.cpp)
* @file SURF_FlannMatcher @include samples/cpp/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.cpp
* @brief SURF detector + descriptor + FLANN Matcher @end_toggle
* @author A. Huaman
*/ @add_toggle_java
This tutorial code's is shown lines below. You can also download it from
#include <stdio.h> [here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/features2D/feature_flann_matcher/SURFFLANNMatchingDemo.java)
#include <iostream> @include samples/java/tutorial_code/features2D/feature_flann_matcher/SURFFLANNMatchingDemo.java
#include <stdio.h> @end_toggle
#include <iostream>
#include "opencv2/core.hpp" @add_toggle_python
#include "opencv2/features2d.hpp" This tutorial code's is shown lines below. You can also download it from
#include "opencv2/imgcodecs.hpp" [here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.py)
#include "opencv2/highgui.hpp" @include samples/python/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.py
#include "opencv2/xfeatures2d.hpp" @end_toggle
using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;
void readme();
/*
* @function main
* @brief Main function
*/
int main( int argc, char** argv )
{
if( argc != 3 )
{ readme(); return -1; }
Mat img_1 = imread( argv[1], IMREAD_GRAYSCALE );
Mat img_2 = imread( argv[2], IMREAD_GRAYSCALE );
if( !img_1.data || !img_2.data )
{ std::cout<< " --(!) Error reading images " << std::endl; return -1; }
//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
int minHessian = 400;
Ptr<SURF> detector = SURF::create();
detector->setHessianThreshold(minHessian);
std::vector<KeyPoint> keypoints_1, keypoints_2;
Mat descriptors_1, descriptors_2;
detector->detectAndCompute( img_1, Mat(), keypoints_1, descriptors_1 );
detector->detectAndCompute( img_2, Mat(), keypoints_2, descriptors_2 );
//-- Step 2: Matching descriptor vectors using FLANN matcher
FlannBasedMatcher matcher;
std::vector< DMatch > matches;
matcher.match( descriptors_1, descriptors_2, matches );
double max_dist = 0; double min_dist = 100;
//-- Quick calculation of max and min distances between keypoints
for( int i = 0; i < descriptors_1.rows; i++ )
{ double dist = matches[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
printf("-- Max dist : %f \n", max_dist );
printf("-- Min dist : %f \n", min_dist );
//-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist,
//-- or a small arbitrary value ( 0.02 ) in the event that min_dist is very
//-- small)
//-- PS.- radiusMatch can also be used here.
std::vector< DMatch > good_matches;
for( int i = 0; i < descriptors_1.rows; i++ )
{ if( matches[i].distance <= max(2*min_dist, 0.02) )
{ good_matches.push_back( matches[i]); }
}
//-- Draw only "good" matches
Mat img_matches;
drawMatches( img_1, keypoints_1, img_2, keypoints_2,
good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
//-- Show detected matches
imshow( "Good Matches", img_matches );
for( int i = 0; i < (int)good_matches.size(); i++ )
{ printf( "-- Good Match [%d] Keypoint 1: %d -- Keypoint 2: %d \n", i, good_matches[i].queryIdx, good_matches[i].trainIdx ); }
waitKey(0);
return 0;
}
/*
* @function readme
*/
void readme()
{ std::cout << " Usage: ./SURF_FlannMatcher <img1> <img2>" << std::endl; }
@endcode
Explanation Explanation
----------- -----------
...@@ -124,10 +67,6 @@ Explanation ...@@ -124,10 +67,6 @@ Explanation
Result Result
------ ------
-# Here is the result of the feature detection applied to the first image: - Here is the result of the SURF feature matching using the distance ratio test:
![](images/Featur_FlannMatcher_Result.jpg)
-# Additionally, we get as console output the keypoints filtered:
![](images/Feature_FlannMatcher_Keypoints_Result.jpg) ![](images/Feature_FlannMatcher_Result_ratio_test.jpg)
...@@ -9,125 +9,40 @@ In this tutorial you will learn how to: ...@@ -9,125 +9,40 @@ In this tutorial you will learn how to:
- Use the function @ref cv::findHomography to find the transform between matched keypoints. - Use the function @ref cv::findHomography to find the transform between matched keypoints.
- Use the function @ref cv::perspectiveTransform to map the points. - Use the function @ref cv::perspectiveTransform to map the points.
\warning You need the <a href="https://github.com/opencv/opencv_contrib">OpenCV contrib modules</a> to be able to use the SURF features
(alternatives are ORB, KAZE, ... features).
Theory Theory
------ ------
Code Code
---- ----
This tutorial code's is shown lines below. @add_toggle_cpp
@code{.cpp} This tutorial code's is shown lines below. You can also download it from
#include <stdio.h> [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.cpp)
#include <iostream> @include samples/cpp/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.cpp
#include "opencv2/core.hpp" @end_toggle
#include "opencv2/imgproc.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/calib3d.hpp"
#include "opencv2/xfeatures2d.hpp"
using namespace cv;
using namespace cv::xfeatures2d;
void readme();
/* @function main */
int main( int argc, char** argv )
{
if( argc != 3 )
{ readme(); return -1; }
Mat img_object = imread( argv[1], IMREAD_GRAYSCALE );
Mat img_scene = imread( argv[2], IMREAD_GRAYSCALE );
if( !img_object.data || !img_scene.data )
{ std::cout<< " --(!) Error reading images " << std::endl; return -1; }
//-- Step 1: Detect the keypoints and extract descriptors using SURF
int minHessian = 400;
Ptr<SURF> detector = SURF::create( minHessian );
std::vector<KeyPoint> keypoints_object, keypoints_scene;
Mat descriptors_object, descriptors_scene;
detector->detectAndCompute( img_object, Mat(), keypoints_object, descriptors_object );
detector->detectAndCompute( img_scene, Mat(), keypoints_scene, descriptors_scene );
//-- Step 2: Matching descriptor vectors using FLANN matcher
FlannBasedMatcher matcher;
std::vector< DMatch > matches;
matcher.match( descriptors_object, descriptors_scene, matches );
double max_dist = 0; double min_dist = 100;
//-- Quick calculation of max and min distances between keypoints
for( int i = 0; i < descriptors_object.rows; i++ )
{ double dist = matches[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
printf("-- Max dist : %f \n", max_dist );
printf("-- Min dist : %f \n", min_dist );
//-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
std::vector< DMatch > good_matches;
for( int i = 0; i < descriptors_object.rows; i++ )
{ if( matches[i].distance <= 3*min_dist )
{ good_matches.push_back( matches[i]); }
}
Mat img_matches;
drawMatches( img_object, keypoints_object, img_scene, keypoints_scene,
good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
//-- Localize the object
std::vector<Point2f> obj;
std::vector<Point2f> scene;
for( size_t i = 0; i < good_matches.size(); i++ )
{
//-- Get the keypoints from the good matches
obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
}
Mat H = findHomography( obj, scene, RANSAC );
//-- Get the corners from the image_1 ( the object to be "detected" )
std::vector<Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint( img_object.cols, 0 );
obj_corners[2] = cvPoint( img_object.cols, img_object.rows ); obj_corners[3] = cvPoint( 0, img_object.rows );
std::vector<Point2f> scene_corners(4);
perspectiveTransform( obj_corners, scene_corners, H);
//-- Draw lines between the corners (the mapped object in the scene - image_2 )
line( img_matches, scene_corners[0] + Point2f( img_object.cols, 0), scene_corners[1] + Point2f( img_object.cols, 0), Scalar(0, 255, 0), 4 );
line( img_matches, scene_corners[1] + Point2f( img_object.cols, 0), scene_corners[2] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[2] + Point2f( img_object.cols, 0), scene_corners[3] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[3] + Point2f( img_object.cols, 0), scene_corners[0] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
//-- Show detected matches @add_toggle_java
imshow( "Good Matches & Object detection", img_matches ); This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/features2D/feature_homography/SURFFLANNMatchingHomographyDemo.java)
@include samples/java/tutorial_code/features2D/feature_homography/SURFFLANNMatchingHomographyDemo.java
@end_toggle
waitKey(0); @add_toggle_python
return 0; This tutorial code's is shown lines below. You can also download it from
} [here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.py)
@include samples/python/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.py
@end_toggle
/* @function readme */
void readme()
{ std::cout << " Usage: ./SURF_descriptor <img1> <img2>" << std::endl; }
@endcode
Explanation Explanation
----------- -----------
Result Result
------ ------
-# And here is the result for the detected object (highlighted in green) - And here is the result for the detected object (highlighted in green). Note that since the homography is estimated with a RANSAC approach,
detected false matches will not impact the homography calculation.
![](images/Feature_Homography_Result.jpg) ![](images/Feature_Homography_Result.jpg)
...@@ -6,39 +6,51 @@ OpenCV. ...@@ -6,39 +6,51 @@ OpenCV.
- @subpage tutorial_harris_detector - @subpage tutorial_harris_detector
*Languages:* C++, Java, Python
*Compatibility:* \> OpenCV 2.0 *Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán *Author:* Ana Huamán
Why is it a good idea to track corners? We learn to use the Harris method to detect Why is it a good idea to track corners? We learn how to use the Harris method to detect
corners corners.
- @subpage tutorial_good_features_to_track - @subpage tutorial_good_features_to_track
*Languages:* C++, Java, Python
*Compatibility:* \> OpenCV 2.0 *Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán *Author:* Ana Huamán
Where we use an improved method to detect corners more accuratelyI Where we use an improved method to detect corners more accurately.
- @subpage tutorial_generic_corner_detector - @subpage tutorial_generic_corner_detector
*Languages:* C++, Java, Python
*Compatibility:* \> OpenCV 2.0 *Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán *Author:* Ana Huamán
Here you will learn how to use OpenCV functions to make your personalized corner detector! Here you will learn how to use OpenCV functions to make your personalized corner detector!
- @subpage tutorial_corner_subpixeles *Languages:* C++, Java, Python
- @subpage tutorial_corner_subpixels
*Languages:* C++, Java, Python
*Compatibility:* \> OpenCV 2.0 *Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán *Author:* Ana Huamán
Is pixel resolution enough? Here we learn a simple method to improve our accuracy. Is pixel resolution enough? Here we learn a simple method to improve our corner location accuracy.
- @subpage tutorial_feature_detection - @subpage tutorial_feature_detection
*Languages:* C++, Java, Python
*Compatibility:* \> OpenCV 2.0 *Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán *Author:* Ana Huamán
...@@ -47,6 +59,8 @@ OpenCV. ...@@ -47,6 +59,8 @@ OpenCV.
- @subpage tutorial_feature_description - @subpage tutorial_feature_description
*Languages:* C++, Java, Python
*Compatibility:* \> OpenCV 2.0 *Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán *Author:* Ana Huamán
...@@ -55,6 +69,8 @@ OpenCV. ...@@ -55,6 +69,8 @@ OpenCV.
- @subpage tutorial_feature_flann_matcher - @subpage tutorial_feature_flann_matcher
*Languages:* C++, Java, Python
*Compatibility:* \> OpenCV 2.0 *Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán *Author:* Ana Huamán
...@@ -63,6 +79,8 @@ OpenCV. ...@@ -63,6 +79,8 @@ OpenCV.
- @subpage tutorial_feature_homography - @subpage tutorial_feature_homography
*Languages:* C++, Java, Python
*Compatibility:* \> OpenCV 2.0 *Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán *Author:* Ana Huamán
......
Detecting corners location in subpixeles {#tutorial_corner_subpixeles} Detecting corners location in subpixels {#tutorial_corner_subpixels}
======================================== =======================================
Goal Goal
---- ----
...@@ -15,9 +15,23 @@ Theory ...@@ -15,9 +15,23 @@ Theory
Code Code
---- ----
@add_toggle_cpp
This tutorial code's is shown lines below. You can also download it from This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp) [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp)
@include samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp @include samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp
@end_toggle
@add_toggle_java
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/TrackingMotion/corner_subpixels/CornerSubPixDemo.java)
@include samples/java/tutorial_code/TrackingMotion/corner_subpixels/CornerSubPixDemo.java
@end_toggle
@add_toggle_python
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/TrackingMotion/corner_subpixels/cornerSubPix_Demo.py)
@include samples/python/tutorial_code/TrackingMotion/corner_subpixels/cornerSubPix_Demo.py
@end_toggle
Explanation Explanation
----------- -----------
...@@ -25,8 +39,8 @@ Explanation ...@@ -25,8 +39,8 @@ Explanation
Result Result
------ ------
![](images/Corner_Subpixeles_Original_Image.jpg) ![](images/Corner_Subpixels_Original_Image.jpg)
Here is the result: Here is the result:
![](images/Corner_Subpixeles_Result.jpg) ![](images/Corner_Subpixels_Result.jpg)
Creating yor own corner detector {#tutorial_generic_corner_detector} Creating your own corner detector {#tutorial_generic_corner_detector}
================================ =================================
Goal Goal
---- ----
...@@ -10,7 +10,7 @@ In this tutorial you will learn how to: ...@@ -10,7 +10,7 @@ In this tutorial you will learn how to:
to determine if a pixel is a corner. to determine if a pixel is a corner.
- Use the OpenCV function @ref cv::cornerMinEigenVal to find the minimum eigenvalues for corner - Use the OpenCV function @ref cv::cornerMinEigenVal to find the minimum eigenvalues for corner
detection. detection.
- To implement our own version of the Harris detector as well as the Shi-Tomasi detector, by using - Implement our own version of the Harris detector as well as the Shi-Tomasi detector, by using
the two functions above. the two functions above.
Theory Theory
...@@ -19,10 +19,26 @@ Theory ...@@ -19,10 +19,26 @@ Theory
Code Code
---- ----
@add_toggle_cpp
This tutorial code's is shown lines below. You can also download it from This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp) [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp)
@include cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp @include samples/cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp
@end_toggle
@add_toggle_java
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/TrackingMotion/generic_corner_detector/CornerDetectorDemo.java)
@include samples/java/tutorial_code/TrackingMotion/generic_corner_detector/CornerDetectorDemo.java
@end_toggle
@add_toggle_python
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/TrackingMotion/generic_corner_detector/cornerDetector_Demo.py)
@include samples/python/tutorial_code/TrackingMotion/generic_corner_detector/cornerDetector_Demo.py
@end_toggle
Explanation Explanation
----------- -----------
......
...@@ -6,7 +6,7 @@ Goal ...@@ -6,7 +6,7 @@ Goal
In this tutorial you will learn how to: In this tutorial you will learn how to:
- Use the function @ref cv::goodFeaturesToTrack to detect corners using the Shi-Tomasi method. - Use the function @ref cv::goodFeaturesToTrack to detect corners using the Shi-Tomasi method (@cite Shi94).
Theory Theory
------ ------
...@@ -14,9 +14,23 @@ Theory ...@@ -14,9 +14,23 @@ Theory
Code Code
---- ----
@add_toggle_cpp
This tutorial code's is shown lines below. You can also download it from This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp) [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp)
@include samples/cpp/tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp @include samples/cpp/tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp
@end_toggle
@add_toggle_java
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/TrackingMotion/good_features_to_track/GoodFeaturesToTrackDemo.java)
@include samples/java/tutorial_code/TrackingMotion/good_features_to_track/GoodFeaturesToTrackDemo.java
@end_toggle
@add_toggle_python
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/TrackingMotion/good_features_to_track/goodFeaturesToTrack_Demo.py)
@include samples/python/tutorial_code/TrackingMotion/good_features_to_track/goodFeaturesToTrack_Demo.py
@end_toggle
Explanation Explanation
----------- -----------
...@@ -24,4 +38,4 @@ Explanation ...@@ -24,4 +38,4 @@ Explanation
Result Result
------ ------
![](images/Feature_Detection_Result_a.jpg) ![](images/good_features_to_track_Shi_Tomasi.jpg)
...@@ -118,9 +118,23 @@ In this tutorial we will study the *corner* features, specifically. ...@@ -118,9 +118,23 @@ In this tutorial we will study the *corner* features, specifically.
Code Code
---- ----
@add_toggle_cpp
This tutorial code's is shown lines below. You can also download it from This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp) [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp)
@include samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp @include samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp
@end_toggle
@add_toggle_java
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/TrackingMotion/harris_detector/CornerHarrisDemo.java)
@include samples/java/tutorial_code/TrackingMotion/harris_detector/CornerHarrisDemo.java
@end_toggle
@add_toggle_python
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/TrackingMotion/harris_detector/cornerHarris_Demo.py)
@include samples/python/tutorial_code/TrackingMotion/harris_detector/cornerHarris_Demo.py
@end_toggle
Explanation Explanation
----------- -----------
......
...@@ -13,15 +13,15 @@ using namespace std; ...@@ -13,15 +13,15 @@ using namespace std;
/// Global variables /// Global variables
Mat src, src_gray; Mat src, src_gray;
Mat myHarris_dst; Mat myHarris_copy; Mat Mc; Mat myHarris_dst, myHarris_copy, Mc;
Mat myShiTomasi_dst; Mat myShiTomasi_copy; Mat myShiTomasi_dst, myShiTomasi_copy;
int myShiTomasi_qualityLevel = 50; int myShiTomasi_qualityLevel = 50;
int myHarris_qualityLevel = 50; int myHarris_qualityLevel = 50;
int max_qualityLevel = 100; int max_qualityLevel = 100;
double myHarris_minVal; double myHarris_maxVal; double myHarris_minVal, myHarris_maxVal;
double myShiTomasi_minVal; double myShiTomasi_maxVal; double myShiTomasi_minVal, myShiTomasi_maxVal;
RNG rng(12345); RNG rng(12345);
...@@ -37,56 +37,54 @@ void myHarris_function( int, void* ); ...@@ -37,56 +37,54 @@ void myHarris_function( int, void* );
*/ */
int main( int argc, char** argv ) int main( int argc, char** argv )
{ {
/// Load source image and convert it to gray /// Load source image and convert it to gray
CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" ); CommandLineParser parser( argc, argv, "{@input | ../data/building.jpg | input image}" );
src = imread( parser.get<String>( "@input" ), IMREAD_COLOR ); src = imread( parser.get<String>( "@input" ) );
if ( src.empty() ) if ( src.empty() )
{ {
cout << "Could not open or find the image!\n" << endl; cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl; cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1; return -1;
} }
cvtColor( src, src_gray, COLOR_BGR2GRAY ); cvtColor( src, src_gray, COLOR_BGR2GRAY );
/// Set some parameters /// Set some parameters
int blockSize = 3; int apertureSize = 3; int blockSize = 3, apertureSize = 3;
/// My Harris matrix -- Using cornerEigenValsAndVecs /// My Harris matrix -- Using cornerEigenValsAndVecs
myHarris_dst = Mat::zeros( src_gray.size(), CV_32FC(6) ); cornerEigenValsAndVecs( src_gray, myHarris_dst, blockSize, apertureSize );
Mc = Mat::zeros( src_gray.size(), CV_32FC1 );
/* calculate Mc */
cornerEigenValsAndVecs( src_gray, myHarris_dst, blockSize, apertureSize, BORDER_DEFAULT ); Mc = Mat( src_gray.size(), CV_32FC1 );
for( int i = 0; i < src_gray.rows; i++ )
/* calculate Mc */ {
for( int j = 0; j < src_gray.rows; j++ ) for( int j = 0; j < src_gray.cols; j++ )
{ for( int i = 0; i < src_gray.cols; i++ ) {
{ float lambda_1 = myHarris_dst.at<Vec6f>(i, j)[0];
float lambda_1 = myHarris_dst.at<Vec6f>(j, i)[0]; float lambda_2 = myHarris_dst.at<Vec6f>(i, j)[1];
float lambda_2 = myHarris_dst.at<Vec6f>(j, i)[1]; Mc.at<float>(i, j) = lambda_1*lambda_2 - 0.04f*pow( ( lambda_1 + lambda_2 ), 2 );
Mc.at<float>(j,i) = lambda_1*lambda_2 - 0.04f*pow( ( lambda_1 + lambda_2 ), 2 ); }
} }
}
minMaxLoc( Mc, &myHarris_minVal, &myHarris_maxVal );
minMaxLoc( Mc, &myHarris_minVal, &myHarris_maxVal, 0, 0, Mat() );
/* Create Window and Trackbar */
/* Create Window and Trackbar */ namedWindow( myHarris_window );
namedWindow( myHarris_window, WINDOW_AUTOSIZE ); createTrackbar( "Quality Level:", myHarris_window, &myHarris_qualityLevel, max_qualityLevel, myHarris_function );
createTrackbar( " Quality Level:", myHarris_window, &myHarris_qualityLevel, max_qualityLevel, myHarris_function ); myHarris_function( 0, 0 );
myHarris_function( 0, 0 );
/// My Shi-Tomasi -- Using cornerMinEigenVal
/// My Shi-Tomasi -- Using cornerMinEigenVal cornerMinEigenVal( src_gray, myShiTomasi_dst, blockSize, apertureSize );
myShiTomasi_dst = Mat::zeros( src_gray.size(), CV_32FC1 );
cornerMinEigenVal( src_gray, myShiTomasi_dst, blockSize, apertureSize, BORDER_DEFAULT ); minMaxLoc( myShiTomasi_dst, &myShiTomasi_minVal, &myShiTomasi_maxVal );
minMaxLoc( myShiTomasi_dst, &myShiTomasi_minVal, &myShiTomasi_maxVal, 0, 0, Mat() ); /* Create Window and Trackbar */
namedWindow( myShiTomasi_window );
/* Create Window and Trackbar */ createTrackbar( "Quality Level:", myShiTomasi_window, &myShiTomasi_qualityLevel, max_qualityLevel, myShiTomasi_function );
namedWindow( myShiTomasi_window, WINDOW_AUTOSIZE ); myShiTomasi_function( 0, 0 );
createTrackbar( " Quality Level:", myShiTomasi_window, &myShiTomasi_qualityLevel, max_qualityLevel, myShiTomasi_function );
myShiTomasi_function( 0, 0 ); waitKey();
return 0;
waitKey(0);
return(0);
} }
/** /**
...@@ -94,18 +92,20 @@ int main( int argc, char** argv ) ...@@ -94,18 +92,20 @@ int main( int argc, char** argv )
*/ */
void myShiTomasi_function( int, void* ) void myShiTomasi_function( int, void* )
{ {
myShiTomasi_copy = src.clone(); myShiTomasi_copy = src.clone();
myShiTomasi_qualityLevel = MAX(myShiTomasi_qualityLevel, 1);
if( myShiTomasi_qualityLevel < 1 ) { myShiTomasi_qualityLevel = 1; }
for( int i = 0; i < src_gray.rows; i++ )
for( int j = 0; j < src_gray.rows; j++ ) {
{ for( int i = 0; i < src_gray.cols; i++ ) for( int j = 0; j < src_gray.cols; j++ )
{ {
if( myShiTomasi_dst.at<float>(j,i) > myShiTomasi_minVal + ( myShiTomasi_maxVal - myShiTomasi_minVal )*myShiTomasi_qualityLevel/max_qualityLevel ) if( myShiTomasi_dst.at<float>(i,j) > myShiTomasi_minVal + ( myShiTomasi_maxVal - myShiTomasi_minVal )*myShiTomasi_qualityLevel/max_qualityLevel )
{ circle( myShiTomasi_copy, Point(i,j), 4, Scalar( rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255) ), -1, 8, 0 ); } {
} circle( myShiTomasi_copy, Point(j,i), 4, Scalar( rng.uniform(0,256), rng.uniform(0,256), rng.uniform(0,256) ), FILLED );
} }
imshow( myShiTomasi_window, myShiTomasi_copy ); }
}
imshow( myShiTomasi_window, myShiTomasi_copy );
} }
/** /**
...@@ -113,16 +113,18 @@ void myShiTomasi_function( int, void* ) ...@@ -113,16 +113,18 @@ void myShiTomasi_function( int, void* )
*/ */
void myHarris_function( int, void* ) void myHarris_function( int, void* )
{ {
myHarris_copy = src.clone(); myHarris_copy = src.clone();
myHarris_qualityLevel = MAX(myHarris_qualityLevel, 1);
if( myHarris_qualityLevel < 1 ) { myHarris_qualityLevel = 1; }
for( int i = 0; i < src_gray.rows; i++ )
for( int j = 0; j < src_gray.rows; j++ ) {
{ for( int i = 0; i < src_gray.cols; i++ ) for( int j = 0; j < src_gray.cols; j++ )
{ {
if( Mc.at<float>(j,i) > myHarris_minVal + ( myHarris_maxVal - myHarris_minVal )*myHarris_qualityLevel/max_qualityLevel ) if( Mc.at<float>(i,j) > myHarris_minVal + ( myHarris_maxVal - myHarris_minVal )*myHarris_qualityLevel/max_qualityLevel )
{ circle( myHarris_copy, Point(i,j), 4, Scalar( rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255) ), -1, 8, 0 ); } {
} circle( myHarris_copy, Point(j,i), 4, Scalar( rng.uniform(0,256), rng.uniform(0,256), rng.uniform(0,256) ), FILLED );
} }
imshow( myHarris_window, myHarris_copy ); }
}
imshow( myHarris_window, myHarris_copy );
} }
...@@ -27,26 +27,26 @@ void cornerHarris_demo( int, void* ); ...@@ -27,26 +27,26 @@ void cornerHarris_demo( int, void* );
*/ */
int main( int argc, char** argv ) int main( int argc, char** argv )
{ {
/// Load source image and convert it to gray /// Load source image and convert it to gray
CommandLineParser parser( argc, argv, "{@input | ../data/building.jpg | input image}" ); CommandLineParser parser( argc, argv, "{@input | ../data/building.jpg | input image}" );
src = imread( parser.get<String>( "@input" ), IMREAD_COLOR ); src = imread( parser.get<String>( "@input" ) );
if ( src.empty() ) if ( src.empty() )
{ {
cout << "Could not open or find the image!\n" << endl; cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl; cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1; return -1;
} }
cvtColor( src, src_gray, COLOR_BGR2GRAY ); cvtColor( src, src_gray, COLOR_BGR2GRAY );
/// Create a window and a trackbar /// Create a window and a trackbar
namedWindow( source_window, WINDOW_AUTOSIZE ); namedWindow( source_window );
createTrackbar( "Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo ); createTrackbar( "Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo );
imshow( source_window, src ); imshow( source_window, src );
cornerHarris_demo( 0, 0 ); cornerHarris_demo( 0, 0 );
waitKey(0); waitKey();
return(0); return 0;
} }
/** /**
...@@ -55,33 +55,33 @@ int main( int argc, char** argv ) ...@@ -55,33 +55,33 @@ int main( int argc, char** argv )
*/ */
void cornerHarris_demo( int, void* ) void cornerHarris_demo( int, void* )
{ {
/// Detector parameters
int blockSize = 2;
int apertureSize = 3;
double k = 0.04;
Mat dst, dst_norm, dst_norm_scaled; /// Detecting corners
dst = Mat::zeros( src.size(), CV_32FC1 ); Mat dst = Mat::zeros( src.size(), CV_32FC1 );
cornerHarris( src_gray, dst, blockSize, apertureSize, k );
/// Detector parameters /// Normalizing
int blockSize = 2; Mat dst_norm, dst_norm_scaled;
int apertureSize = 3; normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );
double k = 0.04; convertScaleAbs( dst_norm, dst_norm_scaled );
/// Detecting corners /// Drawing a circle around corners
cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT ); for( int i = 0; i < dst_norm.rows ; i++ )
{
for( int j = 0; j < dst_norm.cols; j++ )
{
if( (int) dst_norm.at<float>(i,j) > thresh )
{
circle( dst_norm_scaled, Point(j,i), 5, Scalar(0), 2, 8, 0 );
}
}
}
/// Normalizing /// Showing the result
normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() ); namedWindow( corners_window );
convertScaleAbs( dst_norm, dst_norm_scaled ); imshow( corners_window, dst_norm_scaled );
/// Drawing a circle around corners
for( int j = 0; j < dst_norm.rows ; j++ )
{ for( int i = 0; i < dst_norm.cols; i++ )
{
if( (int) dst_norm.at<float>(j,i) > thresh )
{
circle( dst_norm_scaled, Point( i, j ), 5, Scalar(0), 2, 8, 0 );
}
}
}
/// Showing the result
namedWindow( corners_window, WINDOW_AUTOSIZE );
imshow( corners_window, dst_norm_scaled );
} }
...@@ -28,29 +28,29 @@ void goodFeaturesToTrack_Demo( int, void* ); ...@@ -28,29 +28,29 @@ void goodFeaturesToTrack_Demo( int, void* );
*/ */
int main( int argc, char** argv ) int main( int argc, char** argv )
{ {
/// Load source image and convert it to gray /// Load source image and convert it to gray
CommandLineParser parser( argc, argv, "{@input | ../data/pic3.png | input image}" ); CommandLineParser parser( argc, argv, "{@input | ../data/pic3.png | input image}" );
src = imread(parser.get<String>( "@input" ), IMREAD_COLOR); src = imread( parser.get<String>( "@input" ) );
if ( src.empty() ) if( src.empty() )
{ {
cout << "Could not open or find the image!\n" << endl; cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl; cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1; return -1;
} }
cvtColor( src, src_gray, COLOR_BGR2GRAY ); cvtColor( src, src_gray, COLOR_BGR2GRAY );
/// Create Window /// Create Window
namedWindow( source_window, WINDOW_AUTOSIZE ); namedWindow( source_window );
/// Create Trackbar to set the number of corners /// Create Trackbar to set the number of corners
createTrackbar( "Max corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo ); createTrackbar( "Max corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo );
imshow( source_window, src ); imshow( source_window, src );
goodFeaturesToTrack_Demo( 0, 0 ); goodFeaturesToTrack_Demo( 0, 0 );
waitKey(0); waitKey();
return(0); return 0;
} }
/** /**
...@@ -59,52 +59,54 @@ int main( int argc, char** argv ) ...@@ -59,52 +59,54 @@ int main( int argc, char** argv )
*/ */
void goodFeaturesToTrack_Demo( int, void* ) void goodFeaturesToTrack_Demo( int, void* )
{ {
if( maxCorners < 1 ) { maxCorners = 1; } /// Parameters for Shi-Tomasi algorithm
maxCorners = MAX(maxCorners, 1);
/// Parameters for Shi-Tomasi algorithm vector<Point2f> corners;
vector<Point2f> corners; double qualityLevel = 0.01;
double qualityLevel = 0.01; double minDistance = 10;
double minDistance = 10; int blockSize = 3, gradientSize = 3;
int blockSize = 3, gradiantSize = 3; bool useHarrisDetector = false;
bool useHarrisDetector = false; double k = 0.04;
double k = 0.04;
/// Copy the source image
/// Copy the source image Mat copy = src.clone();
Mat copy;
copy = src.clone(); /// Apply corner detection
goodFeaturesToTrack( src_gray,
/// Apply corner detection corners,
goodFeaturesToTrack( src_gray, maxCorners,
corners, qualityLevel,
maxCorners, minDistance,
qualityLevel, Mat(),
minDistance, blockSize,
Mat(), gradientSize,
blockSize, useHarrisDetector,
gradiantSize, k );
useHarrisDetector,
k );
/// Draw corners detected
cout << "** Number of corners detected: " << corners.size() << endl;
/// Draw corners detected int radius = 4;
cout<<"** Number of corners detected: "<<corners.size()<<endl; for( size_t i = 0; i < corners.size(); i++ )
int r = 4; {
for( size_t i = 0; i < corners.size(); i++ ) circle( copy, corners[i], radius, Scalar(rng.uniform(0,255), rng.uniform(0, 256), rng.uniform(0, 256)), FILLED );
{ circle( copy, corners[i], r, Scalar(rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255)), -1, 8, 0 ); } }
/// Show what you got /// Show what you got
namedWindow( source_window, WINDOW_AUTOSIZE ); namedWindow( source_window );
imshow( source_window, copy ); imshow( source_window, copy );
/// Set the needed parameters to find the refined corners /// Set the needed parameters to find the refined corners
Size winSize = Size( 5, 5 ); Size winSize = Size( 5, 5 );
Size zeroZone = Size( -1, -1 ); Size zeroZone = Size( -1, -1 );
TermCriteria criteria = TermCriteria( TermCriteria::EPS + TermCriteria::COUNT, 40, 0.001 ); TermCriteria criteria = TermCriteria( TermCriteria::EPS + TermCriteria::COUNT, 40, 0.001 );
/// Calculate the refined corner locations /// Calculate the refined corner locations
cornerSubPix( src_gray, corners, winSize, zeroZone, criteria ); cornerSubPix( src_gray, corners, winSize, zeroZone, criteria );
/// Write them down /// Write them down
for( size_t i = 0; i < corners.size(); i++ ) for( size_t i = 0; i < corners.size(); i++ )
{ cout<<" -- Refined Corner ["<<i<<"] ("<<corners[i].x<<","<<corners[i].y<<")"<<endl; } {
cout << " -- Refined Corner [" << i << "] (" << corners[i].x << "," << corners[i].y << ")" << endl;
}
} }
...@@ -29,29 +29,29 @@ void goodFeaturesToTrack_Demo( int, void* ); ...@@ -29,29 +29,29 @@ void goodFeaturesToTrack_Demo( int, void* );
*/ */
int main( int argc, char** argv ) int main( int argc, char** argv )
{ {
/// Load source image and convert it to gray /// Load source image and convert it to gray
CommandLineParser parser( argc, argv, "{@input | ../data/pic3.png | input image}" ); CommandLineParser parser( argc, argv, "{@input | ../data/pic3.png | input image}" );
src = imread( parser.get<String>( "@input" ), IMREAD_COLOR ); src = imread( parser.get<String>( "@input" ) );
if( src.empty() ) if( src.empty() )
{ {
cout << "Could not open or find the image!\n" << endl; cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl; cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1; return -1;
} }
cvtColor( src, src_gray, COLOR_BGR2GRAY ); cvtColor( src, src_gray, COLOR_BGR2GRAY );
/// Create Window /// Create Window
namedWindow( source_window, WINDOW_AUTOSIZE ); namedWindow( source_window );
/// Create Trackbar to set the number of corners /// Create Trackbar to set the number of corners
createTrackbar( "Max corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo ); createTrackbar( "Max corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo );
imshow( source_window, src ); imshow( source_window, src );
goodFeaturesToTrack_Demo( 0, 0 ); goodFeaturesToTrack_Demo( 0, 0 );
waitKey(0); waitKey();
return(0); return 0;
} }
/** /**
...@@ -60,40 +60,40 @@ int main( int argc, char** argv ) ...@@ -60,40 +60,40 @@ int main( int argc, char** argv )
*/ */
void goodFeaturesToTrack_Demo( int, void* ) void goodFeaturesToTrack_Demo( int, void* )
{ {
if( maxCorners < 1 ) { maxCorners = 1; } /// Parameters for Shi-Tomasi algorithm
maxCorners = MAX(maxCorners, 1);
/// Parameters for Shi-Tomasi algorithm vector<Point2f> corners;
vector<Point2f> corners; double qualityLevel = 0.01;
double qualityLevel = 0.01; double minDistance = 10;
double minDistance = 10; int blockSize = 3, gradientSize = 3;
int blockSize = 3, gradiantSize = 3; bool useHarrisDetector = false;
bool useHarrisDetector = false; double k = 0.04;
double k = 0.04;
/// Copy the source image
/// Copy the source image Mat copy = src.clone();
Mat copy;
copy = src.clone(); /// Apply corner detection
goodFeaturesToTrack( src_gray,
/// Apply corner detection corners,
goodFeaturesToTrack( src_gray, maxCorners,
corners, qualityLevel,
maxCorners, minDistance,
qualityLevel, Mat(),
minDistance, blockSize,
Mat(), gradientSize,
blockSize, useHarrisDetector,
gradiantSize, k );
useHarrisDetector,
k );
/// Draw corners detected
cout << "** Number of corners detected: " << corners.size() << endl;
/// Draw corners detected int radius = 4;
cout<<"** Number of corners detected: "<<corners.size()<<endl; for( size_t i = 0; i < corners.size(); i++ )
int r = 4; {
for( size_t i = 0; i < corners.size(); i++ ) circle( copy, corners[i], radius, Scalar(rng.uniform(0,255), rng.uniform(0, 256), rng.uniform(0, 256)), FILLED );
{ circle( copy, corners[i], r, Scalar(rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255)), -1, 8, 0 ); } }
/// Show what you got /// Show what you got
namedWindow( source_window, WINDOW_AUTOSIZE ); namedWindow( source_window );
imshow( source_window, copy ); imshow( source_window, copy );
} }
#include <iostream>
#include "opencv2/core.hpp"
#ifdef HAVE_OPENCV_XFEATURES2D
#include "opencv2/highgui.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/xfeatures2d.hpp"
using namespace cv;
using namespace cv::xfeatures2d;
using std::cout;
using std::endl;
const char* keys =
"{ help h | | Print help message. }"
"{ input1 | ../data/box.png | Path to input image 1. }"
"{ input2 | ../data/box_in_scene.png | Path to input image 2. }";
int main( int argc, char* argv[] )
{
CommandLineParser parser( argc, argv, keys );
Mat img1 = imread( parser.get<String>("input1"), IMREAD_GRAYSCALE );
Mat img2 = imread( parser.get<String>("input2"), IMREAD_GRAYSCALE );
if ( img1.empty() || img2.empty() )
{
cout << "Could not open or find the image!\n" << endl;
parser.printMessage();
return -1;
}
//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
int minHessian = 400;
Ptr<SURF> detector = SURF::create( minHessian );
std::vector<KeyPoint> keypoints1, keypoints2;
Mat descriptors1, descriptors2;
detector->detectAndCompute( img1, noArray(), keypoints1, descriptors1 );
detector->detectAndCompute( img2, noArray(), keypoints2, descriptors2 );
//-- Step 2: Matching descriptor vectors with a brute force matcher
// Since SURF is a floating-point descriptor NORM_L2 is used
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::BRUTEFORCE);
std::vector< DMatch > matches;
matcher->match( descriptors1, descriptors2, matches );
//-- Draw matches
Mat img_matches;
drawMatches( img1, keypoints1, img2, keypoints2, matches, img_matches );
//-- Show detected matches
imshow("Matches", img_matches );
waitKey();
return 0;
}
#else
int main()
{
std::cout << "This tutorial code needs the xfeatures2d contrib module to be run." << std::endl;
return 0;
}
#endif
#include <iostream>
#include "opencv2/core.hpp"
#ifdef HAVE_OPENCV_XFEATURES2D
#include "opencv2/highgui.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/xfeatures2d.hpp"
using namespace cv;
using namespace cv::xfeatures2d;
using std::cout;
using std::endl;
int main( int argc, char* argv[] )
{
CommandLineParser parser( argc, argv, "{@input | ../data/box.png | input image}" );
Mat src = imread( parser.get<String>( "@input" ), IMREAD_GRAYSCALE );
if ( src.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
//-- Step 1: Detect the keypoints using SURF Detector
int minHessian = 400;
Ptr<SURF> detector = SURF::create( minHessian );
std::vector<KeyPoint> keypoints;
detector->detect( src, keypoints );
//-- Draw keypoints
Mat img_keypoints;
drawKeypoints( src, keypoints, img_keypoints );
//-- Show detected (drawn) keypoints
imshow("SURF Keypoints", img_keypoints );
waitKey();
return 0;
}
#else
int main()
{
std::cout << "This tutorial code needs the xfeatures2d contrib module to be run." << std::endl;
return 0;
}
#endif
#include <iostream>
#include "opencv2/core.hpp"
#ifdef HAVE_OPENCV_XFEATURES2D
#include "opencv2/highgui.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/xfeatures2d.hpp"
using namespace cv;
using namespace cv::xfeatures2d;
using std::cout;
using std::endl;
const char* keys =
"{ help h | | Print help message. }"
"{ input1 | ../data/box.png | Path to input image 1. }"
"{ input2 | ../data/box_in_scene.png | Path to input image 2. }";
int main( int argc, char* argv[] )
{
CommandLineParser parser( argc, argv, keys );
Mat img1 = imread( parser.get<String>("input1"), IMREAD_GRAYSCALE );
Mat img2 = imread( parser.get<String>("input2"), IMREAD_GRAYSCALE );
if ( img1.empty() || img2.empty() )
{
cout << "Could not open or find the image!\n" << endl;
parser.printMessage();
return -1;
}
//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
int minHessian = 400;
Ptr<SURF> detector = SURF::create( minHessian );
std::vector<KeyPoint> keypoints1, keypoints2;
Mat descriptors1, descriptors2;
detector->detectAndCompute( img1, noArray(), keypoints1, descriptors1 );
detector->detectAndCompute( img2, noArray(), keypoints2, descriptors2 );
//-- Step 2: Matching descriptor vectors with a FLANN based matcher
// Since SURF is a floating-point descriptor NORM_L2 is used
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::FLANNBASED);
std::vector< std::vector<DMatch> > knn_matches;
matcher->knnMatch( descriptors1, descriptors2, knn_matches, 2 );
//-- Filter matches using the Lowe's ratio test
const float ratio_thresh = 0.7f;
std::vector<DMatch> good_matches;
for (size_t i = 0; i < knn_matches.size(); i++)
{
if (knn_matches[i].size() > 1 && knn_matches[i][0].distance / knn_matches[i][1].distance <= ratio_thresh)
{
good_matches.push_back(knn_matches[i][0]);
}
}
//-- Draw matches
Mat img_matches;
drawMatches( img1, keypoints1, img2, keypoints2, good_matches, img_matches, Scalar::all(-1),
Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
//-- Show detected matches
imshow("Good Matches", img_matches );
waitKey();
return 0;
}
#else
int main()
{
std::cout << "This tutorial code needs the xfeatures2d contrib module to be run." << std::endl;
return 0;
}
#endif
#include <iostream>
#include "opencv2/core.hpp"
#ifdef HAVE_OPENCV_XFEATURES2D
#include "opencv2/calib3d.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/xfeatures2d.hpp"
using namespace cv;
using namespace cv::xfeatures2d;
using std::cout;
using std::endl;
const char* keys =
"{ help h | | Print help message. }"
"{ input1 | ../data/box.png | Path to input image 1. }"
"{ input2 | ../data/box_in_scene.png | Path to input image 2. }";
int main( int argc, char* argv[] )
{
CommandLineParser parser( argc, argv, keys );
Mat img_object = imread( parser.get<String>("input1"), IMREAD_GRAYSCALE );
Mat img_scene = imread( parser.get<String>("input2"), IMREAD_GRAYSCALE );
if ( img_object.empty() || img_scene.empty() )
{
cout << "Could not open or find the image!\n" << endl;
parser.printMessage();
return -1;
}
//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
int minHessian = 400;
Ptr<SURF> detector = SURF::create( minHessian );
std::vector<KeyPoint> keypoints_object, keypoints_scene;
Mat descriptors_object, descriptors_scene;
detector->detectAndCompute( img_object, noArray(), keypoints_object, descriptors_object );
detector->detectAndCompute( img_scene, noArray(), keypoints_scene, descriptors_scene );
//-- Step 2: Matching descriptor vectors with a FLANN based matcher
// Since SURF is a floating-point descriptor NORM_L2 is used
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::FLANNBASED);
std::vector< std::vector<DMatch> > knn_matches;
matcher->knnMatch( descriptors_object, descriptors_scene, knn_matches, 2 );
//-- Filter matches using the Lowe's ratio test
const float ratio_thresh = 0.75f;
std::vector<DMatch> good_matches;
for (size_t i = 0; i < knn_matches.size(); i++)
{
if (knn_matches[i].size() > 1 && knn_matches[i][0].distance / knn_matches[i][1].distance <= ratio_thresh)
{
good_matches.push_back(knn_matches[i][0]);
}
}
//-- Draw matches
Mat img_matches;
drawMatches( img_object, keypoints_object, img_scene, keypoints_scene, good_matches, img_matches, Scalar::all(-1),
Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
//-- Localize the object
std::vector<Point2f> obj;
std::vector<Point2f> scene;
for( size_t i = 0; i < good_matches.size(); i++ )
{
//-- Get the keypoints from the good matches
obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
}
Mat H = findHomography( obj, scene, RANSAC );
//-- Get the corners from the image_1 ( the object to be "detected" )
std::vector<Point2f> obj_corners(4);
obj_corners[0] = Point2f(0, 0);
obj_corners[1] = Point2f( (float)img_object.cols, 0 );
obj_corners[2] = Point2f( (float)img_object.cols, (float)img_object.rows );
obj_corners[3] = Point2f( 0, (float)img_object.rows );
std::vector<Point2f> scene_corners(4);
perspectiveTransform( obj_corners, scene_corners, H);
//-- Draw lines between the corners (the mapped object in the scene - image_2 )
line( img_matches, scene_corners[0] + Point2f((float)img_object.cols, 0),
scene_corners[1] + Point2f((float)img_object.cols, 0), Scalar(0, 255, 0), 4 );
line( img_matches, scene_corners[1] + Point2f((float)img_object.cols, 0),
scene_corners[2] + Point2f((float)img_object.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[2] + Point2f((float)img_object.cols, 0),
scene_corners[3] + Point2f((float)img_object.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[3] + Point2f((float)img_object.cols, 0),
scene_corners[0] + Point2f((float)img_object.cols, 0), Scalar( 0, 255, 0), 4 );
//-- Show detected matches
imshow("Good Matches & Object detection", img_matches );
waitKey();
return 0;
}
#else
int main()
{
std::cout << "This tutorial code needs the xfeatures2d contrib module to be run." << std::endl;
return 0;
}
#endif
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Image;
import java.util.Random;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.core.TermCriteria;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
class CornerSubPix {
private Mat src = new Mat();
private Mat srcGray = new Mat();
private JFrame frame;
private JLabel imgLabel;
private static final int MAX_CORNERS = 25;
private int maxCorners = 10;
private Random rng = new Random(12345);
public CornerSubPix(String[] args) {
/// Load source image and convert it to gray
String filename = args.length > 0 ? args[0] : "../data/pic3.png";
src = Imgcodecs.imread(filename);
if (src.empty()) {
System.err.println("Cannot read image: " + filename);
System.exit(0);
}
Imgproc.cvtColor(src, srcGray, Imgproc.COLOR_BGR2GRAY);
// Create and set up the window.
frame = new JFrame("Shi-Tomasi corner detector demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set up the content pane.
Image img = HighGui.toBufferedImage(src);
addComponentsToPane(frame.getContentPane(), img);
// Use the content pane's default BorderLayout. No need for
// setLayout(new BorderLayout());
// Display the window.
frame.pack();
frame.setVisible(true);
update();
}
private void addComponentsToPane(Container pane, Image img) {
if (!(pane.getLayout() instanceof BorderLayout)) {
pane.add(new JLabel("Container doesn't use BorderLayout!"));
return;
}
JPanel sliderPanel = new JPanel();
sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS));
sliderPanel.add(new JLabel("Max corners:"));
JSlider slider = new JSlider(0, MAX_CORNERS, maxCorners);
slider.setMajorTickSpacing(20);
slider.setMinorTickSpacing(10);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider) e.getSource();
maxCorners = source.getValue();
update();
}
});
sliderPanel.add(slider);
pane.add(sliderPanel, BorderLayout.PAGE_START);
imgLabel = new JLabel(new ImageIcon(img));
pane.add(imgLabel, BorderLayout.CENTER);
}
private void update() {
/// Parameters for Shi-Tomasi algorithm
maxCorners = Math.max(maxCorners, 1);
MatOfPoint corners = new MatOfPoint();
double qualityLevel = 0.01;
double minDistance = 10;
int blockSize = 3, gradientSize = 3;
boolean useHarrisDetector = false;
double k = 0.04;
/// Copy the source image
Mat copy = src.clone();
/// Apply corner detection
Imgproc.goodFeaturesToTrack(srcGray, corners, maxCorners, qualityLevel, minDistance, new Mat(),
blockSize, gradientSize, useHarrisDetector, k);
/// Draw corners detected
System.out.println("** Number of corners detected: " + corners.rows());
int[] cornersData = new int[(int) (corners.total() * corners.channels())];
corners.get(0, 0, cornersData);
int radius = 4;
Mat matCorners = new Mat(corners.rows(), 2, CvType.CV_32F);
float[] matCornersData = new float[(int) (matCorners.total() * matCorners.channels())];
matCorners.get(0, 0, matCornersData);
for (int i = 0; i < corners.rows(); i++) {
Imgproc.circle(copy, new Point(cornersData[i * 2], cornersData[i * 2 + 1]), radius,
new Scalar(rng.nextInt(256), rng.nextInt(256), rng.nextInt(256)), Core.FILLED);
matCornersData[i * 2] = cornersData[i * 2];
matCornersData[i * 2 + 1] = cornersData[i * 2 + 1];
}
matCorners.put(0, 0, matCornersData);
imgLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(copy)));
frame.repaint();
/// Set the needed parameters to find the refined corners
Size winSize = new Size(5, 5);
Size zeroZone = new Size(-1, -1);
TermCriteria criteria = new TermCriteria(TermCriteria.EPS + TermCriteria.COUNT, 40, 0.001);
/// Calculate the refined corner locations
Imgproc.cornerSubPix(srcGray, matCorners, winSize, zeroZone, criteria);
/// Write them down
matCorners.get(0, 0, matCornersData);
for (int i = 0; i < corners.rows(); i++) {
System.out.println(
" -- Refined Corner [" + i + "] (" + matCornersData[i * 2] + "," + matCornersData[i * 2 + 1] + ")");
}
}
}
public class CornerSubPixDemo {
public static void main(String[] args) {
// Load the native OpenCV library
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
// Schedule a job for the event dispatch thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new CornerSubPix(args);
}
});
}
}
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Image;
import java.util.Random;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.opencv.core.Core;
import org.opencv.core.Core.MinMaxLocResult;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
class CornerDetector {
private Mat src = new Mat();
private Mat srcGray = new Mat();
private Mat harrisDst = new Mat();
private Mat shiTomasiDst = new Mat();
private Mat harrisCopy = new Mat();
private Mat shiTomasiCopy = new Mat();
private Mat Mc = new Mat();
private JFrame frame;
private JLabel harrisImgLabel;
private JLabel shiTomasiImgLabel;
private static final int MAX_QUALITY_LEVEL = 100;
private int qualityLevel = 50;
private double harrisMinVal;
private double harrisMaxVal;
private double shiTomasiMinVal;
private double shiTomasiMaxVal;
private Random rng = new Random(12345);
public CornerDetector(String[] args) {
/// Load source image and convert it to gray
String filename = args.length > 0 ? args[0] : "../data/building.jpg";
src = Imgcodecs.imread(filename);
if (src.empty()) {
System.err.println("Cannot read image: " + filename);
System.exit(0);
}
Imgproc.cvtColor(src, srcGray, Imgproc.COLOR_BGR2GRAY);
// Create and set up the window.
frame = new JFrame("Creating your own corner detector demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set up the content pane.
Image img = HighGui.toBufferedImage(src);
addComponentsToPane(frame.getContentPane(), img);
// Use the content pane's default BorderLayout. No need for
// setLayout(new BorderLayout());
// Display the window.
frame.pack();
frame.setVisible(true);
/// Set some parameters
int blockSize = 3, apertureSize = 3;
/// My Harris matrix -- Using cornerEigenValsAndVecs
Imgproc.cornerEigenValsAndVecs(srcGray, harrisDst, blockSize, apertureSize);
/* calculate Mc */
Mc = Mat.zeros(srcGray.size(), CvType.CV_32F);
float[] harrisData = new float[(int) (harrisDst.total() * harrisDst.channels())];
harrisDst.get(0, 0, harrisData);
float[] McData = new float[(int) (Mc.total() * Mc.channels())];
Mc.get(0, 0, McData);
for( int i = 0; i < srcGray.rows(); i++ ) {
for( int j = 0; j < srcGray.cols(); j++ ) {
float lambda1 = harrisData[(i*srcGray.cols() + j) * 6];
float lambda2 = harrisData[(i*srcGray.cols() + j) * 6 + 1];
McData[i*srcGray.cols()+j] = (float) (lambda1*lambda2 - 0.04f*Math.pow( ( lambda1 + lambda2 ), 2 ));
}
}
Mc.put(0, 0, McData);
MinMaxLocResult res = Core.minMaxLoc(Mc);
harrisMinVal = res.minVal;
harrisMaxVal = res.maxVal;
/// My Shi-Tomasi -- Using cornerMinEigenVal
Imgproc.cornerMinEigenVal(srcGray, shiTomasiDst, blockSize, apertureSize);
res = Core.minMaxLoc(shiTomasiDst);
shiTomasiMinVal = res.minVal;
shiTomasiMaxVal = res.maxVal;
update();
}
private void addComponentsToPane(Container pane, Image img) {
if (!(pane.getLayout() instanceof BorderLayout)) {
pane.add(new JLabel("Container doesn't use BorderLayout!"));
return;
}
JPanel sliderPanel = new JPanel();
sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS));
sliderPanel.add(new JLabel("Max corners:"));
JSlider slider = new JSlider(0, MAX_QUALITY_LEVEL, qualityLevel);
slider.setMajorTickSpacing(20);
slider.setMinorTickSpacing(10);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider) e.getSource();
qualityLevel = source.getValue();
update();
}
});
sliderPanel.add(slider);
pane.add(sliderPanel, BorderLayout.PAGE_START);
JPanel imgPanel = new JPanel();
harrisImgLabel = new JLabel(new ImageIcon(img));
shiTomasiImgLabel = new JLabel(new ImageIcon(img));
imgPanel.add(harrisImgLabel);
imgPanel.add(shiTomasiImgLabel);
pane.add(imgPanel, BorderLayout.CENTER);
}
private void update() {
int qualityLevelVal = Math.max(qualityLevel, 1);
//Harris
harrisCopy = src.clone();
float[] McData = new float[(int) (Mc.total() * Mc.channels())];
Mc.get(0, 0, McData);
for (int i = 0; i < srcGray.rows(); i++) {
for (int j = 0; j < srcGray.cols(); j++) {
if (McData[i * srcGray.cols() + j] > harrisMinVal
+ (harrisMaxVal - harrisMinVal) * qualityLevelVal / MAX_QUALITY_LEVEL) {
Imgproc.circle(harrisCopy, new Point(j, i), 4,
new Scalar(rng.nextInt(256), rng.nextInt(256), rng.nextInt(256)), Core.FILLED);
}
}
}
//Shi-Tomasi
shiTomasiCopy = src.clone();
float[] shiTomasiData = new float[(int) (shiTomasiDst.total() * shiTomasiDst.channels())];
shiTomasiDst.get(0, 0, shiTomasiData);
for (int i = 0; i < srcGray.rows(); i++) {
for (int j = 0; j < srcGray.cols(); j++) {
if (shiTomasiData[i * srcGray.cols() + j] > shiTomasiMinVal
+ (shiTomasiMaxVal - shiTomasiMinVal) * qualityLevelVal / MAX_QUALITY_LEVEL) {
Imgproc.circle(shiTomasiCopy, new Point(j, i), 4,
new Scalar(rng.nextInt(256), rng.nextInt(256), rng.nextInt(256)), Core.FILLED);
}
}
}
harrisImgLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(harrisCopy)));
shiTomasiImgLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(shiTomasiCopy)));
frame.repaint();
}
}
public class CornerDetectorDemo {
public static void main(String[] args) {
// Load the native OpenCV library
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
// Schedule a job for the event dispatch thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new CornerDetector(args);
}
});
}
}
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Image;
import java.util.Random;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
class GoodFeaturesToTrack {
private Mat src = new Mat();
private Mat srcGray = new Mat();
private JFrame frame;
private JLabel imgLabel;
private static final int MAX_THRESHOLD = 100;
private int maxCorners = 23;
private Random rng = new Random(12345);
public GoodFeaturesToTrack(String[] args) {
/// Load source image and convert it to gray
String filename = args.length > 0 ? args[0] : "../data/pic3.png";
src = Imgcodecs.imread(filename);
if (src.empty()) {
System.err.println("Cannot read image: " + filename);
System.exit(0);
}
Imgproc.cvtColor(src, srcGray, Imgproc.COLOR_BGR2GRAY);
// Create and set up the window.
frame = new JFrame("Shi-Tomasi corner detector demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set up the content pane.
Image img = HighGui.toBufferedImage(src);
addComponentsToPane(frame.getContentPane(), img);
// Use the content pane's default BorderLayout. No need for
// setLayout(new BorderLayout());
// Display the window.
frame.pack();
frame.setVisible(true);
update();
}
private void addComponentsToPane(Container pane, Image img) {
if (!(pane.getLayout() instanceof BorderLayout)) {
pane.add(new JLabel("Container doesn't use BorderLayout!"));
return;
}
JPanel sliderPanel = new JPanel();
sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS));
sliderPanel.add(new JLabel("Max corners:"));
JSlider slider = new JSlider(0, MAX_THRESHOLD, maxCorners);
slider.setMajorTickSpacing(20);
slider.setMinorTickSpacing(10);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider) e.getSource();
maxCorners = source.getValue();
update();
}
});
sliderPanel.add(slider);
pane.add(sliderPanel, BorderLayout.PAGE_START);
imgLabel = new JLabel(new ImageIcon(img));
pane.add(imgLabel, BorderLayout.CENTER);
}
private void update() {
/// Parameters for Shi-Tomasi algorithm
maxCorners = Math.max(maxCorners, 1);
MatOfPoint corners = new MatOfPoint();
double qualityLevel = 0.01;
double minDistance = 10;
int blockSize = 3, gradientSize = 3;
boolean useHarrisDetector = false;
double k = 0.04;
/// Copy the source image
Mat copy = src.clone();
/// Apply corner detection
Imgproc.goodFeaturesToTrack(srcGray, corners, maxCorners, qualityLevel, minDistance, new Mat(),
blockSize, gradientSize, useHarrisDetector, k);
/// Draw corners detected
System.out.println("** Number of corners detected: " + corners.rows());
int[] cornersData = new int[(int) (corners.total() * corners.channels())];
corners.get(0, 0, cornersData);
int radius = 4;
for (int i = 0; i < corners.rows(); i++) {
Imgproc.circle(copy, new Point(cornersData[i * 2], cornersData[i * 2 + 1]), radius,
new Scalar(rng.nextInt(256), rng.nextInt(256), rng.nextInt(256)), Core.FILLED);
}
imgLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(copy)));
frame.repaint();
}
}
public class GoodFeaturesToTrackDemo {
public static void main(String[] args) {
// Load the native OpenCV library
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
// Schedule a job for the event dispatch thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new GoodFeaturesToTrack(args);
}
});
}
}
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Image;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
class CornerHarris {
private Mat srcGray = new Mat();
private Mat dst = new Mat();
private Mat dstNorm = new Mat();
private Mat dstNormScaled = new Mat();
private JFrame frame;
private JLabel imgLabel;
private JLabel cornerLabel;
private static final int MAX_THRESHOLD = 255;
private int threshold = 200;
public CornerHarris(String[] args) {
/// Load source image and convert it to gray
String filename = args.length > 0 ? args[0] : "../data/building.jpg";
Mat src = Imgcodecs.imread(filename);
if (src.empty()) {
System.err.println("Cannot read image: " + filename);
System.exit(0);
}
Imgproc.cvtColor(src, srcGray, Imgproc.COLOR_BGR2GRAY);
// Create and set up the window.
frame = new JFrame("Harris corner detector demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set up the content pane.
Image img = HighGui.toBufferedImage(src);
addComponentsToPane(frame.getContentPane(), img);
// Use the content pane's default BorderLayout. No need for
// setLayout(new BorderLayout());
// Display the window.
frame.pack();
frame.setVisible(true);
update();
}
private void addComponentsToPane(Container pane, Image img) {
if (!(pane.getLayout() instanceof BorderLayout)) {
pane.add(new JLabel("Container doesn't use BorderLayout!"));
return;
}
JPanel sliderPanel = new JPanel();
sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS));
sliderPanel.add(new JLabel("Threshold: "));
JSlider slider = new JSlider(0, MAX_THRESHOLD, threshold);
slider.setMajorTickSpacing(20);
slider.setMinorTickSpacing(10);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider) e.getSource();
threshold = source.getValue();
update();
}
});
sliderPanel.add(slider);
pane.add(sliderPanel, BorderLayout.PAGE_START);
JPanel imgPanel = new JPanel();
imgLabel = new JLabel(new ImageIcon(img));
imgPanel.add(imgLabel);
Mat blackImg = Mat.zeros(srcGray.size(), CvType.CV_8U);
cornerLabel = new JLabel(new ImageIcon(HighGui.toBufferedImage(blackImg)));
imgPanel.add(cornerLabel);
pane.add(imgPanel, BorderLayout.CENTER);
}
private void update() {
dst = Mat.zeros(srcGray.size(), CvType.CV_32F);
/// Detector parameters
int blockSize = 2;
int apertureSize = 3;
double k = 0.04;
/// Detecting corners
Imgproc.cornerHarris(srcGray, dst, blockSize, apertureSize, k);
/// Normalizing
Core.normalize(dst, dstNorm, 0, 255, Core.NORM_MINMAX);
Core.convertScaleAbs(dstNorm, dstNormScaled);
/// Drawing a circle around corners
float[] dstNormData = new float[(int) (dstNorm.total() * dstNorm.channels())];
dstNorm.get(0, 0, dstNormData);
for (int i = 0; i < dstNorm.rows(); i++) {
for (int j = 0; j < dstNorm.cols(); j++) {
if ((int) dstNormData[i * dstNorm.cols() + j] > threshold) {
Imgproc.circle(dstNormScaled, new Point(j, i), 5, new Scalar(0), 2, 8, 0);
}
}
}
cornerLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(dstNormScaled)));
frame.repaint();
}
}
public class CornerHarrisDemo {
public static void main(String[] args) {
// Load the native OpenCV library
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
// Schedule a job for the event dispatch thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new CornerHarris(args);
}
});
}
}
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfDMatch;
import org.opencv.core.MatOfKeyPoint;
import org.opencv.features2d.DescriptorMatcher;
import org.opencv.features2d.Features2d;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.xfeatures2d.SURF;
class SURFMatching {
public void run(String[] args) {
String filename1 = args.length > 1 ? args[0] : "../data/box.png";
String filename2 = args.length > 1 ? args[1] : "../data/box_in_scene.png";
Mat img1 = Imgcodecs.imread(filename1, Imgcodecs.IMREAD_GRAYSCALE);
Mat img2 = Imgcodecs.imread(filename2, Imgcodecs.IMREAD_GRAYSCALE);
if (img1.empty() || img2.empty()) {
System.err.println("Cannot read images!");
System.exit(0);
}
//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
double hessianThreshold = 400;
int nOctaves = 4, nOctaveLayers = 3;
boolean extended = false, upright = false;
SURF detector = SURF.create(hessianThreshold, nOctaves, nOctaveLayers, extended, upright);
MatOfKeyPoint keypoints1 = new MatOfKeyPoint(), keypoints2 = new MatOfKeyPoint();
Mat descriptors1 = new Mat(), descriptors2 = new Mat();
detector.detectAndCompute(img1, new Mat(), keypoints1, descriptors1);
detector.detectAndCompute(img2, new Mat(), keypoints2, descriptors2);
//-- Step 2: Matching descriptor vectors with a brute force matcher
// Since SURF is a floating-point descriptor NORM_L2 is used
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE);
MatOfDMatch matches = new MatOfDMatch();
matcher.match(descriptors1, descriptors2, matches);
//-- Draw matches
Mat imgMatches = new Mat();
Features2d.drawMatches(img1, keypoints1, img2, keypoints2, matches, imgMatches);
HighGui.imshow("Matches", imgMatches);
HighGui.waitKey(0);
System.exit(0);
}
}
public class SURFMatchingDemo {
public static void main(String[] args) {
// Load the native OpenCV library
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
new SURFMatching().run(args);
}
}
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfKeyPoint;
import org.opencv.features2d.Features2d;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.xfeatures2d.SURF;
class SURFDetection {
public void run(String[] args) {
String filename = args.length > 0 ? args[0] : "../data/box.png";
Mat src = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);
if (src.empty()) {
System.err.println("Cannot read image: " + filename);
System.exit(0);
}
//-- Step 1: Detect the keypoints using SURF Detector
double hessianThreshold = 400;
int nOctaves = 4, nOctaveLayers = 3;
boolean extended = false, upright = false;
SURF detector = SURF.create(hessianThreshold, nOctaves, nOctaveLayers, extended, upright);
MatOfKeyPoint keypoints = new MatOfKeyPoint();
detector.detect(src, keypoints);
//-- Draw keypoints
Features2d.drawKeypoints(src, keypoints, src);
//-- Show detected (drawn) keypoints
HighGui.imshow("SURF Keypoints", src);
HighGui.waitKey(0);
System.exit(0);
}
}
public class SURFDetectionDemo {
public static void main(String[] args) {
// Load the native OpenCV library
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
new SURFDetection().run(args);
}
}
import java.util.ArrayList;
import java.util.List;
import org.opencv.core.Core;
import org.opencv.core.DMatch;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfDMatch;
import org.opencv.core.MatOfKeyPoint;
import org.opencv.core.Scalar;
import org.opencv.features2d.DescriptorMatcher;
import org.opencv.features2d.Features2d;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.xfeatures2d.SURF;
class SURFFLANNMatching {
public void run(String[] args) {
String filename1 = args.length > 1 ? args[0] : "../data/box.png";
String filename2 = args.length > 1 ? args[1] : "../data/box_in_scene.png";
Mat img1 = Imgcodecs.imread(filename1, Imgcodecs.IMREAD_GRAYSCALE);
Mat img2 = Imgcodecs.imread(filename2, Imgcodecs.IMREAD_GRAYSCALE);
if (img1.empty() || img2.empty()) {
System.err.println("Cannot read images!");
System.exit(0);
}
//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
double hessianThreshold = 400;
int nOctaves = 4, nOctaveLayers = 3;
boolean extended = false, upright = false;
SURF detector = SURF.create(hessianThreshold, nOctaves, nOctaveLayers, extended, upright);
MatOfKeyPoint keypoints1 = new MatOfKeyPoint(), keypoints2 = new MatOfKeyPoint();
Mat descriptors1 = new Mat(), descriptors2 = new Mat();
detector.detectAndCompute(img1, new Mat(), keypoints1, descriptors1);
detector.detectAndCompute(img2, new Mat(), keypoints2, descriptors2);
//-- Step 2: Matching descriptor vectors with a FLANN based matcher
// Since SURF is a floating-point descriptor NORM_L2 is used
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED);
List<MatOfDMatch> knnMatches = new ArrayList<>();
matcher.knnMatch(descriptors1, descriptors2, knnMatches, 2);
//-- Filter matches using the Lowe's ratio test
float ratio_thresh = 0.7f;
List<DMatch> listOfGoodMatches = new ArrayList<>();
for (int i = 0; i < knnMatches.size(); i++) {
if (knnMatches.get(i).rows() > 1) {
DMatch[] matches = knnMatches.get(i).toArray();
if (matches[0].distance / matches[1].distance <= ratio_thresh) {
listOfGoodMatches.add(matches[0]);
}
}
}
MatOfDMatch goodMatches = new MatOfDMatch();
goodMatches.fromList(listOfGoodMatches);
//-- Draw matches
Mat imgMatches = new Mat();
Features2d.drawMatches(img1, keypoints1, img2, keypoints2, goodMatches, imgMatches, Scalar.all(-1),
Scalar.all(-1), new MatOfByte(), Features2d.NOT_DRAW_SINGLE_POINTS);
//-- Show detected matches
HighGui.imshow("Good Matches", imgMatches);
HighGui.waitKey(0);
System.exit(0);
}
}
public class SURFFLANNMatchingDemo {
public static void main(String[] args) {
// Load the native OpenCV library
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
new SURFFLANNMatching().run(args);
}
}
import java.util.ArrayList;
import java.util.List;
import org.opencv.calib3d.Calib3d;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.DMatch;
import org.opencv.core.KeyPoint;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfDMatch;
import org.opencv.core.MatOfKeyPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.features2d.DescriptorMatcher;
import org.opencv.features2d.Features2d;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.xfeatures2d.SURF;
class SURFFLANNMatchingHomography {
public void run(String[] args) {
String filenameObject = args.length > 1 ? args[0] : "../data/box.png";
String filenameScene = args.length > 1 ? args[1] : "../data/box_in_scene.png";
Mat imgObject = Imgcodecs.imread(filenameObject, Imgcodecs.IMREAD_GRAYSCALE);
Mat imgScene = Imgcodecs.imread(filenameScene, Imgcodecs.IMREAD_GRAYSCALE);
if (imgObject.empty() || imgScene.empty()) {
System.err.println("Cannot read images!");
System.exit(0);
}
//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
double hessianThreshold = 400;
int nOctaves = 4, nOctaveLayers = 3;
boolean extended = false, upright = false;
SURF detector = SURF.create(hessianThreshold, nOctaves, nOctaveLayers, extended, upright);
MatOfKeyPoint keypointsObject = new MatOfKeyPoint(), keypointsScene = new MatOfKeyPoint();
Mat descriptorsObject = new Mat(), descriptorsScene = new Mat();
detector.detectAndCompute(imgObject, new Mat(), keypointsObject, descriptorsObject);
detector.detectAndCompute(imgScene, new Mat(), keypointsScene, descriptorsScene);
//-- Step 2: Matching descriptor vectors with a FLANN based matcher
// Since SURF is a floating-point descriptor NORM_L2 is used
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED);
List<MatOfDMatch> knnMatches = new ArrayList<>();
matcher.knnMatch(descriptorsObject, descriptorsScene, knnMatches, 2);
//-- Filter matches using the Lowe's ratio test
float ratio_thresh = 0.75f;
List<DMatch> listOfGoodMatches = new ArrayList<>();
for (int i = 0; i < knnMatches.size(); i++) {
if (knnMatches.get(i).rows() > 1) {
DMatch[] matches = knnMatches.get(i).toArray();
if (matches[0].distance / matches[1].distance <= ratio_thresh) {
listOfGoodMatches.add(matches[0]);
}
}
}
MatOfDMatch goodMatches = new MatOfDMatch();
goodMatches.fromList(listOfGoodMatches);
//-- Draw matches
Mat imgMatches = new Mat();
Features2d.drawMatches(imgObject, keypointsObject, imgScene, keypointsScene, goodMatches, imgMatches, Scalar.all(-1),
Scalar.all(-1), new MatOfByte(), Features2d.NOT_DRAW_SINGLE_POINTS);
//-- Localize the object
List<Point> obj = new ArrayList<>();
List<Point> scene = new ArrayList<>();
List<KeyPoint> listOfKeypointsObject = keypointsObject.toList();
List<KeyPoint> listOfKeypointsScene = keypointsScene.toList();
for (int i = 0; i < listOfGoodMatches.size(); i++) {
//-- Get the keypoints from the good matches
obj.add(listOfKeypointsObject.get(listOfGoodMatches.get(i).queryIdx).pt);
scene.add(listOfKeypointsScene.get(listOfGoodMatches.get(i).trainIdx).pt);
}
MatOfPoint2f objMat = new MatOfPoint2f(), sceneMat = new MatOfPoint2f();
objMat.fromList(obj);
sceneMat.fromList(scene);
double ransacReprojThreshold = 3.0;
Mat H = Calib3d.findHomography( objMat, sceneMat, Calib3d.RANSAC, ransacReprojThreshold );
//-- Get the corners from the image_1 ( the object to be "detected" )
Mat objCorners = new Mat(4, 1, CvType.CV_32FC2), sceneCorners = new Mat();
float[] objCornersData = new float[(int) (objCorners.total() * objCorners.channels())];
objCorners.get(0, 0, objCornersData);
objCornersData[0] = 0;
objCornersData[1] = 0;
objCornersData[2] = imgObject.cols();
objCornersData[3] = 0;
objCornersData[4] = imgObject.cols();
objCornersData[5] = imgObject.rows();
objCornersData[6] = 0;
objCornersData[7] = imgObject.rows();
objCorners.put(0, 0, objCornersData);
Core.perspectiveTransform(objCorners, sceneCorners, H);
float[] sceneCornersData = new float[(int) (sceneCorners.total() * sceneCorners.channels())];
sceneCorners.get(0, 0, sceneCornersData);
//-- Draw lines between the corners (the mapped object in the scene - image_2 )
Imgproc.line(imgMatches, new Point(sceneCornersData[0] + imgObject.cols(), sceneCornersData[1]),
new Point(sceneCornersData[2] + imgObject.cols(), sceneCornersData[3]), new Scalar(0, 255, 0), 4);
Imgproc.line(imgMatches, new Point(sceneCornersData[2] + imgObject.cols(), sceneCornersData[3]),
new Point(sceneCornersData[4] + imgObject.cols(), sceneCornersData[5]), new Scalar(0, 255, 0), 4);
Imgproc.line(imgMatches, new Point(sceneCornersData[4] + imgObject.cols(), sceneCornersData[5]),
new Point(sceneCornersData[6] + imgObject.cols(), sceneCornersData[7]), new Scalar(0, 255, 0), 4);
Imgproc.line(imgMatches, new Point(sceneCornersData[6] + imgObject.cols(), sceneCornersData[7]),
new Point(sceneCornersData[0] + imgObject.cols(), sceneCornersData[1]), new Scalar(0, 255, 0), 4);
//-- Show detected matches
HighGui.imshow("Good Matches & Object detection", imgMatches);
HighGui.waitKey(0);
System.exit(0);
}
}
public class SURFFLANNMatchingHomographyDemo {
public static void main(String[] args) {
// Load the native OpenCV library
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
new SURFFLANNMatchingHomography().run(args);
}
}
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
source_window = 'Image'
maxTrackbar = 25
rng.seed(12345)
def goodFeaturesToTrack_Demo(val):
maxCorners = max(val, 1)
# Parameters for Shi-Tomasi algorithm
qualityLevel = 0.01
minDistance = 10
blockSize = 3
gradientSize = 3
useHarrisDetector = False
k = 0.04
# Copy the source image
copy = np.copy(src)
# Apply corner detection
corners = cv.goodFeaturesToTrack(src_gray, maxCorners, qualityLevel, minDistance, None, \
blockSize=blockSize, gradientSize=gradientSize, useHarrisDetector=useHarrisDetector, k=k)
# Draw corners detected
print('** Number of corners detected:', corners.shape[0])
radius = 4
for i in range(corners.shape[0]):
cv.circle(copy, (corners[i,0,0], corners[i,0,1]), radius, (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)), cv.FILLED)
# Show what you got
cv.namedWindow(source_window)
cv.imshow(source_window, copy)
# Set the needed parameters to find the refined corners
winSize = (5, 5)
zeroZone = (-1, -1)
criteria = (cv.TERM_CRITERIA_EPS + cv.TermCriteria_COUNT, 40, 0.001)
# Calculate the refined corner locations
corners = cv.cornerSubPix(src_gray, corners, winSize, zeroZone, criteria)
# Write them down
for i in range(corners.shape[0]):
print(" -- Refined Corner [", i, "] (", corners[i,0,0], ",", corners[i,0,1], ")")
# Load source image and convert it to gray
parser = argparse.ArgumentParser(description='Code for Shi-Tomasi corner detector tutorial.')
parser.add_argument('--input', help='Path to input image.', default='../data/pic3.png')
args = parser.parse_args()
src = cv.imread(args.input)
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# Create a window and a trackbar
cv.namedWindow(source_window)
maxCorners = 10 # initial threshold
cv.createTrackbar('Threshold: ', source_window, maxCorners, maxTrackbar, goodFeaturesToTrack_Demo)
cv.imshow(source_window, src)
goodFeaturesToTrack_Demo(maxCorners)
cv.waitKey()
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
myHarris_window = 'My Harris corner detector'
myShiTomasi_window = 'My Shi Tomasi corner detector'
myHarris_qualityLevel = 50
myShiTomasi_qualityLevel = 50
max_qualityLevel = 100
rng.seed(12345)
def myHarris_function(val):
myHarris_copy = np.copy(src)
myHarris_qualityLevel = max(val, 1)
for i in range(src_gray.shape[0]):
for j in range(src_gray.shape[1]):
if Mc[i,j] > myHarris_minVal + ( myHarris_maxVal - myHarris_minVal )*myHarris_qualityLevel/max_qualityLevel:
cv.circle(myHarris_copy, (j,i), 4, (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)), cv.FILLED)
cv.imshow(myHarris_window, myHarris_copy)
def myShiTomasi_function(val):
myShiTomasi_copy = np.copy(src)
myShiTomasi_qualityLevel = max(val, 1)
for i in range(src_gray.shape[0]):
for j in range(src_gray.shape[1]):
if myShiTomasi_dst[i,j] > myShiTomasi_minVal + ( myShiTomasi_maxVal - myShiTomasi_minVal )*myShiTomasi_qualityLevel/max_qualityLevel:
cv.circle(myShiTomasi_copy, (j,i), 4, (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)), cv.FILLED)
cv.imshow(myShiTomasi_window, myShiTomasi_copy)
# Load source image and convert it to gray
parser = argparse.ArgumentParser(description='Code for Creating your own corner detector tutorial.')
parser.add_argument('--input', help='Path to input image.', default='../data/building.jpg')
args = parser.parse_args()
src = cv.imread(args.input)
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# Set some parameters
blockSize = 3
apertureSize = 3
# My Harris matrix -- Using cornerEigenValsAndVecs
myHarris_dst = cv.cornerEigenValsAndVecs(src_gray, blockSize, apertureSize)
# calculate Mc
Mc = np.empty(src_gray.shape, dtype=np.float32)
for i in range(src_gray.shape[0]):
for j in range(src_gray.shape[1]):
lambda_1 = myHarris_dst[i,j,0]
lambda_2 = myHarris_dst[i,j,1]
Mc[i,j] = lambda_1*lambda_2 - 0.04*pow( ( lambda_1 + lambda_2 ), 2 )
myHarris_minVal, myHarris_maxVal, _, _ = cv.minMaxLoc(Mc)
# Create Window and Trackbar
cv.namedWindow(myHarris_window)
cv.createTrackbar('Quality Level:', myHarris_window, myHarris_qualityLevel, max_qualityLevel, myHarris_function)
myHarris_function(myHarris_qualityLevel)
# My Shi-Tomasi -- Using cornerMinEigenVal
myShiTomasi_dst = cv.cornerMinEigenVal(src_gray, blockSize, apertureSize)
myShiTomasi_minVal, myShiTomasi_maxVal, _, _ = cv.minMaxLoc(myShiTomasi_dst)
# Create Window and Trackbar
cv.namedWindow(myShiTomasi_window)
cv.createTrackbar('Quality Level:', myShiTomasi_window, myShiTomasi_qualityLevel, max_qualityLevel, myShiTomasi_function)
myShiTomasi_function(myShiTomasi_qualityLevel)
cv.waitKey()
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
source_window = 'Image'
maxTrackbar = 100
rng.seed(12345)
def goodFeaturesToTrack_Demo(val):
maxCorners = max(val, 1)
# Parameters for Shi-Tomasi algorithm
qualityLevel = 0.01
minDistance = 10
blockSize = 3
gradientSize = 3
useHarrisDetector = False
k = 0.04
# Copy the source image
copy = np.copy(src)
# Apply corner detection
corners = cv.goodFeaturesToTrack(src_gray, maxCorners, qualityLevel, minDistance, None, \
blockSize=blockSize, gradientSize=gradientSize, useHarrisDetector=useHarrisDetector, k=k)
# Draw corners detected
print('** Number of corners detected:', corners.shape[0])
radius = 4
for i in range(corners.shape[0]):
cv.circle(copy, (corners[i,0,0], corners[i,0,1]), radius, (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)), cv.FILLED)
# Show what you got
cv.namedWindow(source_window)
cv.imshow(source_window, copy)
# Load source image and convert it to gray
parser = argparse.ArgumentParser(description='Code for Shi-Tomasi corner detector tutorial.')
parser.add_argument('--input', help='Path to input image.', default='../data/pic3.png')
args = parser.parse_args()
src = cv.imread(args.input)
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# Create a window and a trackbar
cv.namedWindow(source_window)
maxCorners = 23 # initial threshold
cv.createTrackbar('Threshold: ', source_window, maxCorners, maxTrackbar, goodFeaturesToTrack_Demo)
cv.imshow(source_window, src)
goodFeaturesToTrack_Demo(maxCorners)
cv.waitKey()
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
source_window = 'Source image'
corners_window = 'Corners detected'
max_thresh = 255
def cornerHarris_demo(val):
thresh = val
# Detector parameters
blockSize = 2
apertureSize = 3
k = 0.04
# Detecting corners
dst = cv.cornerHarris(src_gray, blockSize, apertureSize, k)
# Normalizing
dst_norm = np.empty(dst.shape, dtype=np.float32)
cv.normalize(dst, dst_norm, alpha=0, beta=255, norm_type=cv.NORM_MINMAX)
dst_norm_scaled = cv.convertScaleAbs(dst_norm)
# Drawing a circle around corners
for i in range(dst_norm.shape[0]):
for j in range(dst_norm.shape[1]):
if int(dst_norm[i,j]) > thresh:
cv.circle(dst_norm_scaled, (j,i), 5, (0), 2)
# Showing the result
cv.namedWindow(corners_window)
cv.imshow(corners_window, dst_norm_scaled)
# Load source image and convert it to gray
parser = argparse.ArgumentParser(description='Code for Harris corner detector tutorial.')
parser.add_argument('--input', help='Path to input image.', default='../data/building.jpg')
args = parser.parse_args()
src = cv.imread(args.input)
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# Create a window and a trackbar
cv.namedWindow(source_window)
thresh = 200 # initial threshold
cv.createTrackbar('Threshold: ', source_window, thresh, max_thresh, cornerHarris_demo)
cv.imshow(source_window, src)
cornerHarris_demo(thresh)
cv.waitKey()
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
parser = argparse.ArgumentParser(description='Code for Feature Detection tutorial.')
parser.add_argument('--input1', help='Path to input image 1.', default='../data/box.png')
parser.add_argument('--input2', help='Path to input image 2.', default='../data/box_in_scene.png')
args = parser.parse_args()
img1 = cv.imread(args.input1, cv.IMREAD_GRAYSCALE)
img2 = cv.imread(args.input2, cv.IMREAD_GRAYSCALE)
if img1 is None or img2 is None:
print('Could not open or find the images!')
exit(0)
#-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
minHessian = 400
detector = cv.xfeatures2d_SURF.create(hessianThreshold=minHessian)
keypoints1, descriptors1 = detector.detectAndCompute(img1, None)
keypoints2, descriptors2 = detector.detectAndCompute(img2, None)
#-- Step 2: Matching descriptor vectors with a brute force matcher
# Since SURF is a floating-point descriptor NORM_L2 is used
matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_BRUTEFORCE)
matches = matcher.match(descriptors1, descriptors2)
#-- Draw matches
img_matches = np.empty((max(img1.shape[0], img2.shape[0]), img1.shape[1]+img2.shape[1], 3), dtype=np.uint8)
cv.drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches)
#-- Show detected matches
cv.imshow('Matches', img_matches)
cv.waitKey()
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
parser = argparse.ArgumentParser(description='Code for Feature Detection tutorial.')
parser.add_argument('--input', help='Path to input image.', default='../data/box.png')
args = parser.parse_args()
src = cv.imread(args.input, cv.IMREAD_GRAYSCALE)
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
#-- Step 1: Detect the keypoints using SURF Detector
minHessian = 400
detector = cv.xfeatures2d_SURF.create(hessianThreshold=minHessian)
keypoints = detector.detect(src)
#-- Draw keypoints
img_keypoints = np.empty((src.shape[0], src.shape[1], 3), dtype=np.uint8)
cv.drawKeypoints(src, keypoints, img_keypoints)
#-- Show detected (drawn) keypoints
cv.imshow('SURF Keypoints', img_keypoints)
cv.waitKey()
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
parser = argparse.ArgumentParser(description='Code for Feature Matching with FLANN tutorial.')
parser.add_argument('--input1', help='Path to input image 1.', default='../data/box.png')
parser.add_argument('--input2', help='Path to input image 2.', default='../data/box_in_scene.png')
args = parser.parse_args()
img1 = cv.imread(args.input1, cv.IMREAD_GRAYSCALE)
img2 = cv.imread(args.input2, cv.IMREAD_GRAYSCALE)
if img1 is None or img2 is None:
print('Could not open or find the images!')
exit(0)
#-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
minHessian = 400
detector = cv.xfeatures2d_SURF.create(hessianThreshold=minHessian)
keypoints1, descriptors1 = detector.detectAndCompute(img1, None)
keypoints2, descriptors2 = detector.detectAndCompute(img2, None)
#-- Step 2: Matching descriptor vectors with a FLANN based matcher
# Since SURF is a floating-point descriptor NORM_L2 is used
matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_FLANNBASED)
knn_matches = matcher.knnMatch(descriptors1, descriptors2, 2)
#-- Filter matches using the Lowe's ratio test
ratio_thresh = 0.7
good_matches = []
for matches in knn_matches:
if len(matches) > 1:
if matches[0].distance / matches[1].distance <= ratio_thresh:
good_matches.append(matches[0])
#-- Draw matches
img_matches = np.empty((max(img1.shape[0], img2.shape[0]), img1.shape[1]+img2.shape[1], 3), dtype=np.uint8)
cv.drawMatches(img1, keypoints1, img2, keypoints2, good_matches, img_matches, flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
#-- Show detected matches
cv.imshow('Good Matches', img_matches)
cv.waitKey()
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
parser = argparse.ArgumentParser(description='Code for Feature Matching with FLANN tutorial.')
parser.add_argument('--input1', help='Path to input image 1.', default='../data/box.png')
parser.add_argument('--input2', help='Path to input image 2.', default='../data/box_in_scene.png')
args = parser.parse_args()
img_object = cv.imread(args.input1, cv.IMREAD_GRAYSCALE)
img_scene = cv.imread(args.input2, cv.IMREAD_GRAYSCALE)
if img_object is None or img_scene is None:
print('Could not open or find the images!')
exit(0)
#-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
minHessian = 400
detector = cv.xfeatures2d_SURF.create(hessianThreshold=minHessian)
keypoints_obj, descriptors_obj = detector.detectAndCompute(img_object, None)
keypoints_scene, descriptors_scene = detector.detectAndCompute(img_scene, None)
#-- Step 2: Matching descriptor vectors with a FLANN based matcher
# Since SURF is a floating-point descriptor NORM_L2 is used
matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_FLANNBASED)
knn_matches = matcher.knnMatch(descriptors_obj, descriptors_scene, 2)
#-- Filter matches using the Lowe's ratio test
ratio_thresh = 0.75
good_matches = []
for matches in knn_matches:
if len(matches) > 1:
if matches[0].distance / matches[1].distance <= ratio_thresh:
good_matches.append(matches[0])
#-- Draw matches
img_matches = np.empty((max(img_object.shape[0], img_scene.shape[0]), img_object.shape[1]+img_scene.shape[1], 3), dtype=np.uint8)
cv.drawMatches(img_object, keypoints_obj, img_scene, keypoints_scene, good_matches, img_matches, flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
#-- Localize the object
obj = np.empty((len(good_matches),2), dtype=np.float32)
scene = np.empty((len(good_matches),2), dtype=np.float32)
for i in range(len(good_matches)):
#-- Get the keypoints from the good matches
obj[i,0] = keypoints_obj[good_matches[i].queryIdx].pt[0]
obj[i,1] = keypoints_obj[good_matches[i].queryIdx].pt[1]
scene[i,0] = keypoints_scene[good_matches[i].trainIdx].pt[0]
scene[i,1] = keypoints_scene[good_matches[i].trainIdx].pt[1]
H, _ = cv.findHomography(obj, scene, cv.RANSAC)
#-- Get the corners from the image_1 ( the object to be "detected" )
obj_corners = np.empty((4,1,2), dtype=np.float32)
obj_corners[0,0,0] = 0
obj_corners[0,0,1] = 0
obj_corners[1,0,0] = img_object.shape[1]
obj_corners[1,0,1] = 0
obj_corners[2,0,0] = img_object.shape[1]
obj_corners[2,0,1] = img_object.shape[0]
obj_corners[3,0,0] = 0
obj_corners[3,0,1] = img_object.shape[0]
scene_corners = cv.perspectiveTransform(obj_corners, H)
#-- Draw lines between the corners (the mapped object in the scene - image_2 )
cv.line(img_matches, (int(scene_corners[0,0,0] + img_object.shape[1]), int(scene_corners[0,0,1])),\
(int(scene_corners[1,0,0] + img_object.shape[1]), int(scene_corners[1,0,1])), (0,255,0), 4)
cv.line(img_matches, (int(scene_corners[1,0,0] + img_object.shape[1]), int(scene_corners[1,0,1])),\
(int(scene_corners[2,0,0] + img_object.shape[1]), int(scene_corners[2,0,1])), (0,255,0), 4)
cv.line(img_matches, (int(scene_corners[2,0,0] + img_object.shape[1]), int(scene_corners[2,0,1])),\
(int(scene_corners[3,0,0] + img_object.shape[1]), int(scene_corners[3,0,1])), (0,255,0), 4)
cv.line(img_matches, (int(scene_corners[3,0,0] + img_object.shape[1]), int(scene_corners[3,0,1])),\
(int(scene_corners[0,0,0] + img_object.shape[1]), int(scene_corners[0,0,1])), (0,255,0), 4)
#-- Show detected matches
cv.imshow('Good Matches & Object detection', img_matches)
cv.waitKey()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment