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.
@ -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 @@
|
|||||||
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:
|
|||||||
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"
|
|
||||||
#include "opencv2/xfeatures2d.hpp"
|
|
||||||
|
|
||||||
using namespace cv;
|
@add_toggle_java
|
||||||
using namespace cv::xfeatures2d;
|
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)
|
||||||
|
@include samples/java/tutorial_code/features2D/feature_description/SURFMatchingDemo.java
|
||||||
|
@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:
|
|||||||
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;
|
@add_toggle_java
|
||||||
using namespace cv::xfeatures2d;
|
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
|
||||||
|
|
||||||
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_detection/SURF_detection_Demo.py)
|
||||||
int main( int argc, char** argv )
|
@include samples/python/tutorial_code/features2D/feature_detection/SURF_detection_Demo.py
|
||||||
{
|
@end_toggle
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* @function readme */
|
|
||||||
void readme()
|
|
||||||
{ std::cout << " Usage: ./SURF_detector <img1> <img2>" << std::endl; }
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
Explanation
|
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:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
-# And here is the result for the second image:
|
-# And here is the result for the `box_in_scene.png` image:
|
||||||
|
|
||||||

|

|
||||||
|
@ -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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
@add_toggle_java
|
||||||
#include <iostream>
|
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 "opencv2/core.hpp"
|
@end_toggle
|
||||||
#include "opencv2/features2d.hpp"
|
|
||||||
#include "opencv2/imgcodecs.hpp"
|
|
||||||
#include "opencv2/highgui.hpp"
|
|
||||||
#include "opencv2/xfeatures2d.hpp"
|
|
||||||
|
|
||||||
using namespace std;
|
@add_toggle_python
|
||||||
using namespace cv;
|
This tutorial code's is shown lines below. You can also download it from
|
||||||
using namespace cv::xfeatures2d;
|
[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.py)
|
||||||
|
@include samples/python/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.py
|
||||||
void readme();
|
@end_toggle
|
||||||
|
|
||||||
/*
|
|
||||||
* @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
|
|||||||
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:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
-# Additionally, we get as console output the keypoints filtered:
|
|
||||||
|
|
||||||

|
|
||||||
|
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 79 KiB |
@ -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;
|
@add_toggle_java
|
||||||
using namespace cv::xfeatures2d;
|
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
|
||||||
|
|
||||||
void readme();
|
@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/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 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
|
|
||||||
imshow( "Good Matches & Object detection", img_matches );
|
|
||||||
|
|
||||||
waitKey(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* @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.
|
||||||
|
|
||||||

|

|
||||||
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 88 KiB |
@ -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.
|
|||||||
|
|
||||||
- @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.
|
|||||||
|
|
||||||
- @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.
|
|||||||
|
|
||||||
- @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
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
Detecting corners location in subpixeles {#tutorial_corner_subpixeles}
|
|
||||||
========================================
|
|
||||||
|
|
||||||
Goal
|
|
||||||
----
|
|
||||||
|
|
||||||
In this tutorial you will learn how to:
|
|
||||||
|
|
||||||
- Use the OpenCV function @ref cv::cornerSubPix to find more exact corner positions (more exact
|
|
||||||
than integer pixels).
|
|
||||||
|
|
||||||
Theory
|
|
||||||
------
|
|
||||||
|
|
||||||
Code
|
|
||||||
----
|
|
||||||
|
|
||||||
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)
|
|
||||||
@include samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp
|
|
||||||
|
|
||||||
Explanation
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Result
|
|
||||||
------
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Here is the result:
|
|
||||||
|
|
||||||

|
|
@ -0,0 +1,46 @@
|
|||||||
|
Detecting corners location in subpixels {#tutorial_corner_subpixels}
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
Goal
|
||||||
|
----
|
||||||
|
|
||||||
|
In this tutorial you will learn how to:
|
||||||
|
|
||||||
|
- Use the OpenCV function @ref cv::cornerSubPix to find more exact corner positions (more exact
|
||||||
|
than integer pixels).
|
||||||
|
|
||||||
|
Theory
|
||||||
|
------
|
||||||
|
|
||||||
|
Code
|
||||||
|
----
|
||||||
|
|
||||||
|
@add_toggle_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/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
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Result
|
||||||
|
------
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Here is the result:
|
||||||
|
|
||||||
|

|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@ -1,5 +1,5 @@
|
|||||||
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:
|
|||||||
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
|
|||||||
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
|
|||||||
|
|
||||||
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
|
|||||||
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
|
|||||||
Result
|
Result
|
||||||
------
|
------
|
||||||
|
|
||||||

|

|
||||||
|
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 27 KiB |
@ -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;
|
|||||||
|
|
||||||
/// 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);
|
||||||
|
|
||||||
@ -38,8 +38,8 @@ 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;
|
||||||
@ -49,44 +49,42 @@ int main( int argc, char** argv )
|
|||||||
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 );
|
|
||||||
|
|
||||||
cornerEigenValsAndVecs( src_gray, myHarris_dst, blockSize, apertureSize, BORDER_DEFAULT );
|
|
||||||
|
|
||||||
/* calculate Mc */
|
/* calculate Mc */
|
||||||
for( int j = 0; j < src_gray.rows; j++ )
|
Mc = Mat( src_gray.size(), CV_32FC1 );
|
||||||
{ for( int i = 0; i < src_gray.cols; i++ )
|
for( int i = 0; i < src_gray.rows; i++ )
|
||||||
{
|
{
|
||||||
float lambda_1 = myHarris_dst.at<Vec6f>(j, i)[0];
|
for( int j = 0; j < src_gray.cols; j++ )
|
||||||
float lambda_2 = myHarris_dst.at<Vec6f>(j, i)[1];
|
{
|
||||||
Mc.at<float>(j,i) = lambda_1*lambda_2 - 0.04f*pow( ( lambda_1 + lambda_2 ), 2 );
|
float lambda_1 = myHarris_dst.at<Vec6f>(i, j)[0];
|
||||||
|
float lambda_2 = myHarris_dst.at<Vec6f>(i, j)[1];
|
||||||
|
Mc.at<float>(i, j) = lambda_1*lambda_2 - 0.04f*pow( ( lambda_1 + lambda_2 ), 2 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
minMaxLoc( Mc, &myHarris_minVal, &myHarris_maxVal, 0, 0, Mat() );
|
minMaxLoc( Mc, &myHarris_minVal, &myHarris_maxVal );
|
||||||
|
|
||||||
/* Create Window and Trackbar */
|
/* Create Window and Trackbar */
|
||||||
namedWindow( myHarris_window, WINDOW_AUTOSIZE );
|
namedWindow( myHarris_window );
|
||||||
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
|
||||||
myShiTomasi_dst = Mat::zeros( src_gray.size(), CV_32FC1 );
|
cornerMinEigenVal( src_gray, myShiTomasi_dst, blockSize, apertureSize );
|
||||||
cornerMinEigenVal( src_gray, myShiTomasi_dst, blockSize, apertureSize, BORDER_DEFAULT );
|
|
||||||
|
|
||||||
minMaxLoc( myShiTomasi_dst, &myShiTomasi_minVal, &myShiTomasi_maxVal, 0, 0, Mat() );
|
minMaxLoc( myShiTomasi_dst, &myShiTomasi_minVal, &myShiTomasi_maxVal );
|
||||||
|
|
||||||
/* Create Window and Trackbar */
|
/* Create Window and Trackbar */
|
||||||
namedWindow( myShiTomasi_window, WINDOW_AUTOSIZE );
|
namedWindow( myShiTomasi_window );
|
||||||
createTrackbar( "Quality Level:", myShiTomasi_window, &myShiTomasi_qualityLevel, max_qualityLevel, myShiTomasi_function );
|
createTrackbar( "Quality Level:", myShiTomasi_window, &myShiTomasi_qualityLevel, max_qualityLevel, myShiTomasi_function );
|
||||||
myShiTomasi_function( 0, 0 );
|
myShiTomasi_function( 0, 0 );
|
||||||
|
|
||||||
waitKey(0);
|
waitKey();
|
||||||
return(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,14 +93,16 @@ 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++ )
|
|
||||||
{
|
{
|
||||||
if( myShiTomasi_dst.at<float>(j,i) > myShiTomasi_minVal + ( myShiTomasi_maxVal - myShiTomasi_minVal )*myShiTomasi_qualityLevel/max_qualityLevel )
|
for( int j = 0; j < src_gray.cols; j++ )
|
||||||
{ circle( myShiTomasi_copy, Point(i,j), 4, Scalar( rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255) ), -1, 8, 0 ); }
|
{
|
||||||
|
if( myShiTomasi_dst.at<float>(i,j) > myShiTomasi_minVal + ( myShiTomasi_maxVal - myShiTomasi_minVal )*myShiTomasi_qualityLevel/max_qualityLevel )
|
||||||
|
{
|
||||||
|
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 );
|
||||||
@ -114,14 +114,16 @@ 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++ )
|
|
||||||
{
|
{
|
||||||
if( Mc.at<float>(j,i) > myHarris_minVal + ( myHarris_maxVal - myHarris_minVal )*myHarris_qualityLevel/max_qualityLevel )
|
for( int j = 0; j < src_gray.cols; j++ )
|
||||||
{ circle( myHarris_copy, Point(i,j), 4, Scalar( rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255) ), -1, 8, 0 ); }
|
{
|
||||||
|
if( Mc.at<float>(i,j) > myHarris_minVal + ( myHarris_maxVal - myHarris_minVal )*myHarris_qualityLevel/max_qualityLevel )
|
||||||
|
{
|
||||||
|
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 );
|
||||||
|
@ -29,7 +29,7 @@ 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;
|
||||||
@ -39,14 +39,14 @@ int main( int argc, char** argv )
|
|||||||
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 )
|
|||||||
*/
|
*/
|
||||||
void cornerHarris_demo( int, void* )
|
void cornerHarris_demo( int, void* )
|
||||||
{
|
{
|
||||||
|
|
||||||
Mat dst, dst_norm, dst_norm_scaled;
|
|
||||||
dst = Mat::zeros( src.size(), CV_32FC1 );
|
|
||||||
|
|
||||||
/// Detector parameters
|
/// Detector parameters
|
||||||
int blockSize = 2;
|
int blockSize = 2;
|
||||||
int apertureSize = 3;
|
int apertureSize = 3;
|
||||||
double k = 0.04;
|
double k = 0.04;
|
||||||
|
|
||||||
/// Detecting corners
|
/// Detecting corners
|
||||||
cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT );
|
Mat dst = Mat::zeros( src.size(), CV_32FC1 );
|
||||||
|
cornerHarris( src_gray, dst, blockSize, apertureSize, k );
|
||||||
|
|
||||||
/// Normalizing
|
/// Normalizing
|
||||||
|
Mat dst_norm, dst_norm_scaled;
|
||||||
normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );
|
normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );
|
||||||
convertScaleAbs( dst_norm, dst_norm_scaled );
|
convertScaleAbs( dst_norm, dst_norm_scaled );
|
||||||
|
|
||||||
/// Drawing a circle around corners
|
/// Drawing a circle around corners
|
||||||
for( int j = 0; j < dst_norm.rows ; j++ )
|
for( int i = 0; i < dst_norm.rows ; i++ )
|
||||||
{ for( int i = 0; i < dst_norm.cols; i++ )
|
|
||||||
{
|
{
|
||||||
if( (int) dst_norm.at<float>(j,i) > thresh )
|
for( int j = 0; j < dst_norm.cols; j++ )
|
||||||
{
|
{
|
||||||
circle( dst_norm_scaled, Point( i, j ), 5, Scalar(0), 2, 8, 0 );
|
if( (int) dst_norm.at<float>(i,j) > thresh )
|
||||||
|
{
|
||||||
|
circle( dst_norm_scaled, Point(j,i), 5, Scalar(0), 2, 8, 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Showing the result
|
/// Showing the result
|
||||||
namedWindow( corners_window, WINDOW_AUTOSIZE );
|
namedWindow( corners_window );
|
||||||
imshow( corners_window, dst_norm_scaled );
|
imshow( corners_window, dst_norm_scaled );
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ 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;
|
||||||
@ -40,7 +40,7 @@ int main( int argc, char** argv )
|
|||||||
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 );
|
||||||
@ -49,8 +49,8 @@ int main( int argc, char** argv )
|
|||||||
|
|
||||||
goodFeaturesToTrack_Demo( 0, 0 );
|
goodFeaturesToTrack_Demo( 0, 0 );
|
||||||
|
|
||||||
waitKey(0);
|
waitKey();
|
||||||
return(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,19 +59,17 @@ 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
|
/// Parameters for Shi-Tomasi algorithm
|
||||||
|
maxCorners = MAX(maxCorners, 1);
|
||||||
vector<Point2f> corners;
|
vector<Point2f> corners;
|
||||||
double qualityLevel = 0.01;
|
double qualityLevel = 0.01;
|
||||||
double minDistance = 10;
|
double minDistance = 10;
|
||||||
int blockSize = 3, gradiantSize = 3;
|
int blockSize = 3, gradientSize = 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;
|
Mat copy = src.clone();
|
||||||
copy = src.clone();
|
|
||||||
|
|
||||||
/// Apply corner detection
|
/// Apply corner detection
|
||||||
goodFeaturesToTrack( src_gray,
|
goodFeaturesToTrack( src_gray,
|
||||||
@ -81,19 +79,21 @@ void goodFeaturesToTrack_Demo( int, void* )
|
|||||||
minDistance,
|
minDistance,
|
||||||
Mat(),
|
Mat(),
|
||||||
blockSize,
|
blockSize,
|
||||||
gradiantSize,
|
gradientSize,
|
||||||
useHarrisDetector,
|
useHarrisDetector,
|
||||||
k );
|
k );
|
||||||
|
|
||||||
|
|
||||||
/// Draw corners detected
|
/// Draw corners detected
|
||||||
cout << "** Number of corners detected: " << corners.size() << endl;
|
cout << "** Number of corners detected: " << corners.size() << endl;
|
||||||
int r = 4;
|
int radius = 4;
|
||||||
for( size_t i = 0; i < corners.size(); i++ )
|
for( size_t i = 0; i < corners.size(); i++ )
|
||||||
{ circle( copy, corners[i], r, Scalar(rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255)), -1, 8, 0 ); }
|
{
|
||||||
|
circle( copy, corners[i], radius, Scalar(rng.uniform(0,255), rng.uniform(0, 256), rng.uniform(0, 256)), FILLED );
|
||||||
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
@ -106,5 +106,7 @@ void goodFeaturesToTrack_Demo( int, void* )
|
|||||||
|
|
||||||
/// 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ 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;
|
||||||
@ -41,7 +41,7 @@ int main( int argc, char** argv )
|
|||||||
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 );
|
||||||
@ -50,8 +50,8 @@ int main( int argc, char** argv )
|
|||||||
|
|
||||||
goodFeaturesToTrack_Demo( 0, 0 );
|
goodFeaturesToTrack_Demo( 0, 0 );
|
||||||
|
|
||||||
waitKey(0);
|
waitKey();
|
||||||
return(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,19 +60,17 @@ 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
|
/// Parameters for Shi-Tomasi algorithm
|
||||||
|
maxCorners = MAX(maxCorners, 1);
|
||||||
vector<Point2f> corners;
|
vector<Point2f> corners;
|
||||||
double qualityLevel = 0.01;
|
double qualityLevel = 0.01;
|
||||||
double minDistance = 10;
|
double minDistance = 10;
|
||||||
int blockSize = 3, gradiantSize = 3;
|
int blockSize = 3, gradientSize = 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;
|
Mat copy = src.clone();
|
||||||
copy = src.clone();
|
|
||||||
|
|
||||||
/// Apply corner detection
|
/// Apply corner detection
|
||||||
goodFeaturesToTrack( src_gray,
|
goodFeaturesToTrack( src_gray,
|
||||||
@ -82,18 +80,20 @@ void goodFeaturesToTrack_Demo( int, void* )
|
|||||||
minDistance,
|
minDistance,
|
||||||
Mat(),
|
Mat(),
|
||||||
blockSize,
|
blockSize,
|
||||||
gradiantSize,
|
gradientSize,
|
||||||
useHarrisDetector,
|
useHarrisDetector,
|
||||||
k );
|
k );
|
||||||
|
|
||||||
|
|
||||||
/// Draw corners detected
|
/// Draw corners detected
|
||||||
cout << "** Number of corners detected: " << corners.size() << endl;
|
cout << "** Number of corners detected: " << corners.size() << endl;
|
||||||
int r = 4;
|
int radius = 4;
|
||||||
for( size_t i = 0; i < corners.size(); i++ )
|
for( size_t i = 0; i < corners.size(); i++ )
|
||||||
{ circle( copy, corners[i], r, Scalar(rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255)), -1, 8, 0 ); }
|
{
|
||||||
|
circle( copy, corners[i], radius, Scalar(rng.uniform(0,255), rng.uniform(0, 256), rng.uniform(0, 256)), FILLED );
|
||||||
|
}
|
||||||
|
|
||||||
/// Show what you got
|
/// Show what you got
|
||||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
namedWindow( source_window );
|
||||||
imshow( source_window, copy );
|
imshow( source_window, copy );
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
#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
|
@ -0,0 +1,46 @@
|
|||||||
|
#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
|
@ -0,0 +1,72 @@
|
|||||||
|
#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
|
@ -0,0 +1,107 @@
|
|||||||
|
#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
|
@ -0,0 +1,158 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,190 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,142 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
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()
|
@ -0,0 +1,80 @@
|
|||||||
|
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()
|
@ -0,0 +1,58 @@
|
|||||||
|
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()
|
@ -0,0 +1,55 @@
|
|||||||
|
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()
|
@ -0,0 +1,35 @@
|
|||||||
|
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()
|
@ -0,0 +1,27 @@
|
|||||||
|
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()
|
@ -0,0 +1,43 @@
|
|||||||
|
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()
|
@ -0,0 +1,78 @@
|
|||||||
|
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()
|