vendor: OpenCV 5.0.0 snapshot at 755e50675d97db9b7d449d8bd6b09888646f6c6e
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "opencv2/opencv_modules.hpp"
|
||||
|
||||
#ifdef HAVE_OPENCV_XFEATURES2D
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/features.hpp>
|
||||
#include <opencv2/xfeatures2d.hpp>
|
||||
#include <opencv2/imgcodecs.hpp>
|
||||
#include <vector>
|
||||
|
||||
// If you find this code useful, please add a reference to the following paper in your work:
|
||||
// Gil Levi and Tal Hassner, "LATCH: Learned Arrangements of Three Patch Codes", arXiv preprint arXiv:1501.03719, 15 Jan. 2015
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
const float inlier_threshold = 2.5f; // Distance threshold to identify inliers
|
||||
const float nn_match_ratio = 0.8f; // Nearest neighbor matching ratio
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CommandLineParser parser(argc, argv,
|
||||
"{@img1 | graf1.png | input image 1}"
|
||||
"{@img2 | graf3.png | input image 2}"
|
||||
"{@homography | H1to3p.xml | homography matrix}");
|
||||
Mat img1 = imread( samples::findFile( parser.get<String>("@img1") ), IMREAD_GRAYSCALE);
|
||||
Mat img2 = imread( samples::findFile( parser.get<String>("@img2") ), IMREAD_GRAYSCALE);
|
||||
|
||||
Mat homography;
|
||||
FileStorage fs( samples::findFile( parser.get<String>("@homography") ), FileStorage::READ);
|
||||
fs.getFirstTopLevelNode() >> homography;
|
||||
|
||||
vector<KeyPoint> kpts1, kpts2;
|
||||
Mat desc1, desc2;
|
||||
|
||||
Ptr<cv::ORB> orb_detector = cv::ORB::create(10000);
|
||||
|
||||
Ptr<xfeatures2d::LATCH> latch = xfeatures2d::LATCH::create();
|
||||
|
||||
|
||||
orb_detector->detect(img1, kpts1);
|
||||
latch->compute(img1, kpts1, desc1);
|
||||
|
||||
orb_detector->detect(img2, kpts2);
|
||||
latch->compute(img2, kpts2, desc2);
|
||||
|
||||
BFMatcher matcher(NORM_HAMMING);
|
||||
vector< vector<DMatch> > nn_matches;
|
||||
matcher.knnMatch(desc1, desc2, nn_matches, 2);
|
||||
|
||||
vector<KeyPoint> matched1, matched2, inliers1, inliers2;
|
||||
vector<DMatch> good_matches;
|
||||
for (size_t i = 0; i < nn_matches.size(); i++) {
|
||||
DMatch first = nn_matches[i][0];
|
||||
float dist1 = nn_matches[i][0].distance;
|
||||
float dist2 = nn_matches[i][1].distance;
|
||||
|
||||
if (dist1 < nn_match_ratio * dist2) {
|
||||
matched1.push_back(kpts1[first.queryIdx]);
|
||||
matched2.push_back(kpts2[first.trainIdx]);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < matched1.size(); i++) {
|
||||
Mat col = Mat::ones(3, 1, CV_64F);
|
||||
col.at<double>(0) = matched1[i].pt.x;
|
||||
col.at<double>(1) = matched1[i].pt.y;
|
||||
|
||||
col = homography * col;
|
||||
col /= col.at<double>(2);
|
||||
double dist = sqrt(pow(col.at<double>(0) - matched2[i].pt.x, 2) +
|
||||
pow(col.at<double>(1) - matched2[i].pt.y, 2));
|
||||
|
||||
if (dist < inlier_threshold) {
|
||||
int new_i = static_cast<int>(inliers1.size());
|
||||
inliers1.push_back(matched1[i]);
|
||||
inliers2.push_back(matched2[i]);
|
||||
good_matches.push_back(DMatch(new_i, new_i, 0));
|
||||
}
|
||||
}
|
||||
|
||||
Mat res;
|
||||
drawMatches(img1, inliers1, img2, inliers2, good_matches, res);
|
||||
imwrite("latch_result.png", res);
|
||||
|
||||
|
||||
double inlier_ratio = inliers1.size() * 1.0 / matched1.size();
|
||||
cout << "LATCH Matching Results" << endl;
|
||||
cout << "*******************************" << endl;
|
||||
cout << "# Keypoints 1: \t" << kpts1.size() << endl;
|
||||
cout << "# Keypoints 2: \t" << kpts2.size() << endl;
|
||||
cout << "# Matches: \t" << matched1.size() << endl;
|
||||
cout << "# Inliers: \t" << inliers1.size() << endl;
|
||||
cout << "# Inliers Ratio: \t" << inlier_ratio << endl;
|
||||
cout << endl;
|
||||
|
||||
imshow("result", res);
|
||||
waitKey();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cerr << "OpenCV was built without xfeatures2d module" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,293 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"""
|
||||
|
||||
/*********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright (c) 2016
|
||||
*
|
||||
* Balint Cristian <cristian dot balint at gmail dot com>
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*********************************************************************/
|
||||
|
||||
/* export-boostdesc.py */
|
||||
/* Export C headers from binary data */
|
||||
// [http://infoscience.epfl.ch/record/186246/files/boostDesc_1.0.tar.gz]
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import struct
|
||||
|
||||
|
||||
|
||||
def float_to_hex(f):
|
||||
return struct.unpack( '<I', struct.pack('<f', f) )[0]
|
||||
|
||||
def main():
|
||||
|
||||
# usage
|
||||
if ( len(sys.argv) < 3 ):
|
||||
print( "Usage: %s <binary-type (BGM, LBGM, BINBOOST)> <boostdesc-binary-filename>" % sys.argv[0] )
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if ( ( sys.argv[1] != "BGM" ) and
|
||||
( sys.argv[1] != "LBGM" ) and
|
||||
( sys.argv[1] != "BINBOOST" ) ):
|
||||
print( "Invalid type [%s]" % sys.argv[1] )
|
||||
sys.exit(0)
|
||||
|
||||
# enum literals
|
||||
Assign = [ "ASSIGN_HARD",
|
||||
"ASSIGN_BILINEAR",
|
||||
"ASSIGN_SOFT",
|
||||
"ASSIGN_HARD_MAGN",
|
||||
"ASSIGN_SOFT_MAGN" ]
|
||||
|
||||
# open binary data file
|
||||
f = open( sys.argv[2], 'rb' )
|
||||
|
||||
# header
|
||||
print "/*"
|
||||
print " *"
|
||||
print " * Header exported from binary."
|
||||
print " * [%s %s %s]" % ( sys.argv[0], sys.argv[1], sys.argv[2] )
|
||||
print " *"
|
||||
print " */"
|
||||
|
||||
# ini
|
||||
nDim = 1;
|
||||
nWLs = 0;
|
||||
|
||||
# dimensionality (where is the case)
|
||||
if ( ( sys.argv[1] == "LBGM" ) or
|
||||
( sys.argv[1] == "BINBOOST" ) ):
|
||||
nDim = struct.unpack( '<i', f.read(4) )[0]
|
||||
|
||||
print
|
||||
print "// dimensionality of learner"
|
||||
print "static const int nDim = %i;" % nDim
|
||||
|
||||
# week learners (where is the case)
|
||||
if ( sys.argv[1] != "BINBOOST" ):
|
||||
nWLs = struct.unpack( '<i', f.read(4) )[0]
|
||||
|
||||
# common header
|
||||
orientQuant = struct.unpack( '<i', f.read(4) )[0]
|
||||
patchSize = struct.unpack( '<i', f.read(4) )[0]
|
||||
iGradAssignType = struct.unpack( '<i', f.read(4) )[0]
|
||||
|
||||
print
|
||||
print "// orientations"
|
||||
print "static const int orientQuant = %i;" % orientQuant
|
||||
|
||||
print
|
||||
print "// patch size"
|
||||
print "static const int patchSize = %i;" % patchSize
|
||||
|
||||
print
|
||||
print "// gradient assignment type"
|
||||
print "static const int iGradAssignType = %s;" % Assign[iGradAssignType]
|
||||
|
||||
arr_thresh = ""
|
||||
arr_orient = ""
|
||||
|
||||
arr__y_min = ""
|
||||
arr__y_max = ""
|
||||
arr__x_min = ""
|
||||
arr__x_max = ""
|
||||
|
||||
arr__alpha = ""
|
||||
arr___beta = ""
|
||||
|
||||
|
||||
dims = nDim
|
||||
if ( sys.argv[1] == "LBGM" ):
|
||||
dims = 1
|
||||
|
||||
# iterate each dimension
|
||||
for d in range( 0, dims ):
|
||||
|
||||
if ( sys.argv[1] == "BINBOOST" ):
|
||||
nWLs = struct.unpack( '<i', f.read(4) )[0]
|
||||
|
||||
if ( d == 0 ):
|
||||
print
|
||||
print "// number of weak learners"
|
||||
print "static const int nWLs = %i;" % nWLs
|
||||
|
||||
# iterate each members
|
||||
for i in range( 0, nWLs ):
|
||||
|
||||
# unpack structure array
|
||||
thresh = struct.unpack( '<f', f.read(4) )[0]
|
||||
orient = struct.unpack( '<i', f.read(4) )[0]
|
||||
|
||||
y_min = struct.unpack( '<i', f.read(4) )[0]
|
||||
y_max = struct.unpack( '<i', f.read(4) )[0]
|
||||
x_min = struct.unpack( '<i', f.read(4) )[0]
|
||||
x_max = struct.unpack( '<i', f.read(4) )[0]
|
||||
|
||||
alpha = struct.unpack( '<f', f.read(4) )[0]
|
||||
|
||||
beta = 0
|
||||
if ( sys.argv[1] == "BINBOOST" ):
|
||||
beta = struct.unpack( '<f', f.read(4) )[0]
|
||||
|
||||
# first entry
|
||||
if ( d*dims + i == 0 ):
|
||||
|
||||
arr_thresh += "\n"
|
||||
arr_thresh += "// threshold array (%s x %s)\n" % (dims,nWLs)
|
||||
arr_thresh += "static const unsigned int thresh[] =\n{\n"
|
||||
|
||||
arr_orient += "\n"
|
||||
arr_orient += "// orientation array (%s x %s)\n" % (dims,nWLs)
|
||||
arr_orient += "static const int orient[] =\n{\n"
|
||||
|
||||
arr__y_min += "\n"
|
||||
arr__y_min += "// Y min array (%s x %s)\n" % (dims,nWLs)
|
||||
arr__y_min += "static const int y_min[] =\n{\n"
|
||||
|
||||
arr__y_max += "\n"
|
||||
arr__y_max += "// Y max array (%s x %s)\n" % (dims,nWLs)
|
||||
arr__y_max += "static const int y_max[] =\n{\n"
|
||||
|
||||
arr__x_min += "\n"
|
||||
arr__x_min += "// X min array (%s x %s)\n" % (dims,nWLs)
|
||||
arr__x_min += "static const int x_min[] =\n{\n"
|
||||
|
||||
arr__x_max += "\n"
|
||||
arr__x_max += "// X max array (%s x %s)\n" % (dims,nWLs)
|
||||
arr__x_max += "static const int x_max[] =\n{\n"
|
||||
|
||||
arr__alpha += "\n"
|
||||
arr__alpha += "// alpha array (%s x %s)\n" % (dims,nWLs)
|
||||
arr__alpha += "static const unsigned int alpha[] =\n{\n"
|
||||
|
||||
if ( sys.argv[1] == "BINBOOST" ):
|
||||
arr___beta += "\n"
|
||||
arr___beta += "// beta array (%s x %s)\n" % (dims,nWLs)
|
||||
arr___beta += "static const unsigned int beta[] =\n{\n"
|
||||
|
||||
# last entry
|
||||
if ( i == nWLs - 1 ) and ( d == dims - 1):
|
||||
|
||||
arr_thresh += " 0x%08x\n};" % float_to_hex(thresh)
|
||||
arr_orient += " 0x%02x\n};" % orient
|
||||
|
||||
arr__y_min += " 0x%02x\n};" % y_min
|
||||
arr__y_max += " 0x%02x\n};" % y_max
|
||||
arr__x_min += " 0x%02x\n};" % x_min
|
||||
arr__x_max += " 0x%02x\n};" % x_max
|
||||
|
||||
arr__alpha += " 0x%08x\n};" % float_to_hex(alpha)
|
||||
|
||||
if ( sys.argv[1] == "BINBOOST" ):
|
||||
arr___beta += " 0x%08x\n};" % float_to_hex(beta)
|
||||
|
||||
break
|
||||
|
||||
# align entries
|
||||
if ( (d*dims + i + 1) % 8 ):
|
||||
|
||||
arr_thresh += " 0x%08x," % float_to_hex(thresh)
|
||||
arr_orient += " 0x%02x," % orient
|
||||
|
||||
arr__y_min += " 0x%02x," % y_min
|
||||
arr__y_max += " 0x%02x," % y_max
|
||||
arr__x_min += " 0x%02x," % x_min
|
||||
arr__x_max += " 0x%02x," % x_max
|
||||
|
||||
arr__alpha += " 0x%08x," % float_to_hex(alpha)
|
||||
|
||||
if ( sys.argv[1] == "BINBOOST" ):
|
||||
arr___beta += " 0x%08x," % float_to_hex(beta)
|
||||
|
||||
else:
|
||||
|
||||
arr_thresh += " 0x%08x,\n" % float_to_hex(thresh)
|
||||
arr_orient += " 0x%02x,\n" % orient
|
||||
|
||||
arr__y_min += " 0x%02x,\n" % y_min
|
||||
arr__y_max += " 0x%02x,\n" % y_max
|
||||
arr__x_min += " 0x%02x,\n" % x_min
|
||||
arr__x_max += " 0x%02x,\n" % x_max
|
||||
|
||||
arr__alpha += " 0x%08x,\n" % float_to_hex(alpha)
|
||||
|
||||
if ( sys.argv[1] == "BINBOOST" ):
|
||||
arr___beta += " 0x%08x,\n" % float_to_hex(beta)
|
||||
|
||||
# extra array (when LBGM)
|
||||
if ( sys.argv[1] == "LBGM" ):
|
||||
|
||||
arr___beta += "\n"
|
||||
arr___beta += "// beta array (%s x %s)\n" % (nWLs,nDim)
|
||||
arr___beta += "static const unsigned int beta[] =\n{\n"
|
||||
|
||||
for i in range( 0, nWLs ):
|
||||
for d in range( 0, nDim ):
|
||||
beta = struct.unpack( '<f', f.read(4) )[0]
|
||||
|
||||
# last entry
|
||||
if ( i == nWLs-1 ) and ( d == nDim-1 ):
|
||||
arr___beta += " 0x%08x\n};" % float_to_hex(beta)
|
||||
break
|
||||
|
||||
# align entries
|
||||
if ( (i*nDim + d + 1) % 8 ):
|
||||
arr___beta += " 0x%08x," % float_to_hex(beta)
|
||||
else:
|
||||
arr___beta += " 0x%08x,\n" % float_to_hex(beta)
|
||||
|
||||
# release
|
||||
f.close()
|
||||
|
||||
# dump on screen
|
||||
print arr_thresh
|
||||
print arr_orient
|
||||
|
||||
print arr__y_min
|
||||
print arr__y_max
|
||||
print arr__x_min
|
||||
print arr__x_max
|
||||
|
||||
print arr__alpha
|
||||
|
||||
if ( ( sys.argv[1] == "LBGM" ) or
|
||||
( sys.argv[1] == "BINBOOST" ) ):
|
||||
print arr___beta
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,138 @@
|
||||
#include <iostream>
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/videoio.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/features.hpp>
|
||||
#include <opencv2/flann.hpp>
|
||||
#include <opencv2/xfeatures2d.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::xfeatures2d;
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// This program demonstrates the GMS matching strategy.
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* keys =
|
||||
"{ h help | | print help message }"
|
||||
"{ l left | | specify left (reference) image }"
|
||||
"{ r right | | specify right (query) image }"
|
||||
"{ camera | 0 | specify the camera device number }"
|
||||
"{ nfeatures | 10000 | specify the maximum number of ORB features }"
|
||||
"{ fastThreshold | 20 | specify the FAST threshold }"
|
||||
"{ drawSimple | true | do not draw not matched keypoints }"
|
||||
"{ withRotation | false | take rotation into account }"
|
||||
"{ withScale | false | take scale into account }";
|
||||
|
||||
CommandLineParser cmd(argc, argv, keys);
|
||||
if (cmd.has("help"))
|
||||
{
|
||||
std::cout << "Usage: gms_matcher [options]" << std::endl;
|
||||
std::cout << "Available options:" << std::endl;
|
||||
cmd.printMessage();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Ptr<Feature2D> orb = ORB::create(cmd.get<int>("nfeatures"));
|
||||
orb.dynamicCast<cv::ORB>()->setFastThreshold(cmd.get<int>("fastThreshold"));
|
||||
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");
|
||||
|
||||
if (!cmd.get<String>("left").empty() && !cmd.get<String>("right").empty())
|
||||
{
|
||||
Mat imgL = imread(cmd.get<String>("left"));
|
||||
Mat imgR = imread(cmd.get<String>("right"));
|
||||
|
||||
std::vector<KeyPoint> kpRef, kpCur;
|
||||
Mat descRef, descCur;
|
||||
orb->detectAndCompute(imgL, noArray(), kpRef, descRef);
|
||||
orb->detectAndCompute(imgR, noArray(), kpCur, descCur);
|
||||
|
||||
std::vector<DMatch> matchesAll, matchesGMS;
|
||||
matcher->match(descCur, descRef, matchesAll);
|
||||
|
||||
matchGMS(imgR.size(), imgL.size(), kpCur, kpRef, matchesAll, matchesGMS, cmd.get<bool>("withRotation"), cmd.get<bool>("withScale"));
|
||||
std::cout << "matchesGMS: " << matchesGMS.size() << std::endl;
|
||||
|
||||
Mat frameMatches;
|
||||
if (cmd.get<bool>("drawSimple"))
|
||||
drawMatches(imgR, kpCur, imgL, kpRef, matchesGMS, frameMatches, Scalar::all(-1), Scalar::all(-1),
|
||||
std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
|
||||
else
|
||||
drawMatches(imgR, kpCur, imgL, kpRef, matchesGMS, frameMatches);
|
||||
imshow("Matches GMS", frameMatches);
|
||||
waitKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<KeyPoint> kpRef;
|
||||
Mat descRef;
|
||||
|
||||
VideoCapture capture(cmd.get<int>("camera"));
|
||||
//Camera warm-up
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
Mat frame;
|
||||
capture >> frame;
|
||||
}
|
||||
|
||||
Mat frameRef;
|
||||
for (;;)
|
||||
{
|
||||
Mat frame;
|
||||
capture >> frame;
|
||||
|
||||
if (frameRef.empty())
|
||||
{
|
||||
frame.copyTo(frameRef);
|
||||
orb->detectAndCompute(frameRef, noArray(), kpRef, descRef);
|
||||
}
|
||||
|
||||
TickMeter tm;
|
||||
tm.start();
|
||||
std::vector<KeyPoint> kp;
|
||||
Mat desc;
|
||||
orb->detectAndCompute(frame, noArray(), kp, desc);
|
||||
tm.stop();
|
||||
double t_orb = tm.getTimeMilli();
|
||||
|
||||
tm.reset();
|
||||
tm.start();
|
||||
std::vector<DMatch> matchesAll, matchesGMS;
|
||||
matcher->match(desc, descRef, matchesAll);
|
||||
tm.stop();
|
||||
double t_match = tm.getTimeMilli();
|
||||
|
||||
matchGMS(frame.size(), frameRef.size(), kp, kpRef, matchesAll, matchesGMS, cmd.get<bool>("withRotation"), cmd.get<bool>("withScale"));
|
||||
tm.stop();
|
||||
Mat frameMatches;
|
||||
if (cmd.get<bool>("drawSimple"))
|
||||
drawMatches(frame, kp, frameRef, kpRef, matchesGMS, frameMatches, Scalar::all(-1), Scalar::all(-1),
|
||||
std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
|
||||
else
|
||||
drawMatches(frame, kp, frameRef, kpRef, matchesGMS, frameMatches);
|
||||
|
||||
String label = format("ORB: %.2f ms", t_orb);
|
||||
putText(frameMatches, label, Point(20, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0,0,255));
|
||||
label = format("Matching: %.2f ms", t_match);
|
||||
putText(frameMatches, label, Point(20, 40), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0,0,255));
|
||||
label = format("GMS matching: %.2f ms", tm.getTimeMilli());
|
||||
putText(frameMatches, label, Point(20, 60), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0,0,255));
|
||||
putText(frameMatches, "Press r to reinitialize the reference image.", Point(frameMatches.cols-380, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0,0,255));
|
||||
putText(frameMatches, "Press esc to quit.", Point(frameMatches.cols-180, 40), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0,0,255));
|
||||
|
||||
imshow("Matches GMS", frameMatches);
|
||||
int c = waitKey(30);
|
||||
if (c == 27)
|
||||
break;
|
||||
else if (c == 'r')
|
||||
{
|
||||
frame.copyTo(frameRef);
|
||||
orb->detectAndCompute(frameRef, noArray(), kpRef, descRef);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
By downloading, copying, installing or using the software you agree to this license.
|
||||
If you do not agree to this license, do not download, install,
|
||||
copy or use the software.
|
||||
|
||||
|
||||
License Agreement
|
||||
For Open Source Computer Vision Library
|
||||
(3-clause BSD License)
|
||||
|
||||
Copyright (C) 2000-2016, Intel Corporation, all rights reserved.
|
||||
Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
|
||||
Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved.
|
||||
Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
|
||||
Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved.
|
||||
Copyright (C) 2015-2016, Itseez Inc., all rights reserved.
|
||||
Third party copyrights are property of their respective owners.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the copyright holders nor the names of the contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
This software is provided by the copyright holders and contributors "as is" and
|
||||
any express or implied warranties, including, but not limited to, the implied
|
||||
warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
In no event shall copyright holders or contributors be liable for any direct,
|
||||
indirect, incidental, special, exemplary, or consequential damages
|
||||
(including, but not limited to, procurement of substitute goods or services;
|
||||
loss of use, data, or profits; or business interruption) however caused
|
||||
and on any theory of liability, whether in contract, strict liability,
|
||||
or tort (including negligence or otherwise) arising in any way out of
|
||||
the use of this software, even if advised of the possibility of such damage.
|
||||
*/
|
||||
|
||||
/*
|
||||
Contributed by Gregor Kovalcik <gregor dot kovalcik at gmail dot com>
|
||||
based on code provided by Martin Krulis, Jakub Lokoc and Tomas Skopal.
|
||||
|
||||
References:
|
||||
Martin Krulis, Jakub Lokoc, Tomas Skopal.
|
||||
Efficient Extraction of Clustering-Based Feature Signatures Using GPU Architectures.
|
||||
Multimedia tools and applications, 75(13), pp.: 8071–8103, Springer, ISSN: 1380-7501, 2016
|
||||
|
||||
Christian Beecks, Merih Seran Uysal, Thomas Seidl.
|
||||
Signature quadratic form distance.
|
||||
In Proceedings of the ACM International Conference on Image and Video Retrieval, pages 438-445.
|
||||
ACM, 2010.
|
||||
*/
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/xfeatures2d.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
using namespace xfeatures2d;
|
||||
|
||||
|
||||
void printHelpMessage(void);
|
||||
void printHelpMessage(void)
|
||||
{
|
||||
cout << "Example of the PCTSignatures algorithm computing and visualizing\n"
|
||||
"image signature for one image, or comparing multiple images with the first\n"
|
||||
"image using the signature quadratic form distance.\n\n"
|
||||
"Usage: pct_signatures ImageToProcessAndDisplay\n"
|
||||
"or: pct_signatures ReferenceImage [ImagesToCompareWithTheReferenceImage]\n\n"
|
||||
"The program has 2 modes:\n"
|
||||
"- single argument: program computes and visualizes the image signature\n"
|
||||
"- multiple arguments: program compares the first image to the others\n"
|
||||
" using pct signatures and signature quadratic form distance (SQFD)";
|
||||
}
|
||||
|
||||
/** @brief
|
||||
|
||||
Example of the PCTSignatures algorithm.
|
||||
|
||||
The program has 2 modes:
|
||||
- single argument mode, where the program computes and visualizes the image signature
|
||||
- multiple argument mode, where the program compares the first image to the others
|
||||
using signatures and signature quadratic form distance (SQFD)
|
||||
|
||||
*/
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2) // Check arguments
|
||||
{
|
||||
printHelpMessage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
Mat source;
|
||||
source = imread(argv[1]); // Read the file
|
||||
|
||||
if (!source.data) // Check for invalid input
|
||||
{
|
||||
cerr << "Could not open or find the image: " << argv[1];
|
||||
return -1;
|
||||
}
|
||||
|
||||
Mat signature, result; // define variables
|
||||
int initSampleCount = 2000;
|
||||
int initSeedCount = 400;
|
||||
int grayscaleBitsPerPixel = 4;
|
||||
vector<Point2f> initPoints;
|
||||
|
||||
namedWindow("Source", WINDOW_AUTOSIZE); // Create windows for display.
|
||||
namedWindow("Result", WINDOW_AUTOSIZE);
|
||||
|
||||
// create the algorithm
|
||||
PCTSignatures::generateInitPoints(initPoints, initSampleCount, PCTSignatures::UNIFORM);
|
||||
Ptr<PCTSignatures> pctSignatures = PCTSignatures::create(initPoints, initSeedCount);
|
||||
pctSignatures->setGrayscaleBits(grayscaleBitsPerPixel);
|
||||
|
||||
// compute and visualize the first image
|
||||
double start = (double)getTickCount();
|
||||
pctSignatures->computeSignature(source, signature);
|
||||
double end = (double)getTickCount();
|
||||
cout << "Signature of the reference image computed in " << (end - start) / (getTickFrequency() * 1.0f) << " seconds." << endl;
|
||||
PCTSignatures::drawSignature(source, signature, result);
|
||||
|
||||
imshow("Source", source); // show the result
|
||||
imshow("Result", result);
|
||||
|
||||
if (argc == 2) // single image -> finish right after the visualization
|
||||
{
|
||||
waitKey(0); // Wait for user input
|
||||
return 0;
|
||||
}
|
||||
// multiple images -> compare to the first one
|
||||
else
|
||||
{
|
||||
vector<Mat> images;
|
||||
vector<Mat> signatures;
|
||||
vector<float> distances;
|
||||
|
||||
for (int i = 2; i < argc; i++)
|
||||
{
|
||||
Mat image = imread(argv[i]);
|
||||
if (!source.data) // Check for invalid input
|
||||
{
|
||||
cerr << "Could not open or find the image: " << argv[i] << std::endl;
|
||||
return 1;
|
||||
}
|
||||
images.push_back(image);
|
||||
}
|
||||
|
||||
pctSignatures->computeSignatures(images, signatures);
|
||||
Ptr<PCTSignaturesSQFD> pctSQFD = PCTSignaturesSQFD::create();
|
||||
pctSQFD->computeQuadraticFormDistances(signature, signatures, distances);
|
||||
|
||||
for (int i = 0; i < (int)(distances.size()); i++)
|
||||
{
|
||||
cout << "Image: " << argv[i + 2] << ", similarity: " << distances[i] << endl;
|
||||
}
|
||||
waitKey(0); // Wait for user input
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
By downloading, copying, installing or using the software you agree to this license.
|
||||
If you do not agree to this license, do not download, install,
|
||||
copy or use the software.
|
||||
|
||||
|
||||
License Agreement
|
||||
For Open Source Computer Vision Library
|
||||
(3-clause BSD License)
|
||||
|
||||
Copyright (C) 2000-2016, Intel Corporation, all rights reserved.
|
||||
Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
|
||||
Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved.
|
||||
Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
|
||||
Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved.
|
||||
Copyright (C) 2015-2016, Itseez Inc., all rights reserved.
|
||||
Third party copyrights are property of their respective owners.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the copyright holders nor the names of the contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
This software is provided by the copyright holders and contributors "as is" and
|
||||
any express or implied warranties, including, but not limited to, the implied
|
||||
warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
In no event shall copyright holders or contributors be liable for any direct,
|
||||
indirect, incidental, special, exemplary, or consequential damages
|
||||
(including, but not limited to, procurement of substitute goods or services;
|
||||
loss of use, data, or profits; or business interruption) however caused
|
||||
and on any theory of liability, whether in contract, strict liability,
|
||||
or tort (including negligence or otherwise) arising in any way out of
|
||||
the use of this software, even if advised of the possibility of such damage.
|
||||
*/
|
||||
|
||||
/*
|
||||
Contributed by Gregor Kovalcik <gregor dot kovalcik at gmail dot com>
|
||||
based on code provided by Martin Krulis, Jakub Lokoc and Tomas Skopal.
|
||||
|
||||
References:
|
||||
Martin Krulis, Jakub Lokoc, Tomas Skopal.
|
||||
Efficient Extraction of Clustering-Based Feature Signatures Using GPU Architectures.
|
||||
Multimedia tools and applications, 75(13), pp.: 8071–8103, Springer, ISSN: 1380-7501, 2016
|
||||
|
||||
Christian Beecks, Merih Seran Uysal, Thomas Seidl.
|
||||
Signature quadratic form distance.
|
||||
In Proceedings of the ACM International Conference on Image and Video Retrieval, pages 438-445.
|
||||
ACM, 2010.
|
||||
*/
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/xfeatures2d.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
using namespace xfeatures2d;
|
||||
|
||||
|
||||
void printHelpMessage(void);
|
||||
void printHelpMessage(void)
|
||||
{
|
||||
cout << "Example of the PCTSignatures algorithm.\n\n"
|
||||
"This program computes and visualizes position-color-texture signatures\n"
|
||||
"using images from webcam if available.\n\n"
|
||||
"Usage:\n"
|
||||
"pct_webcam [sample_count] [seed_count]\n"
|
||||
"Note: sample_count must be greater or equal to seed_count.";
|
||||
}
|
||||
|
||||
|
||||
/** @brief
|
||||
|
||||
Example of the PCTSignatures algorithm.
|
||||
|
||||
This program computes and visualizes position-color-texture signatures
|
||||
of images taken from webcam if available.
|
||||
*/
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// define variables
|
||||
Mat frame, signature, result;
|
||||
int initSampleCount = 2000;
|
||||
int initSeedCount = 400;
|
||||
int grayscaleBitsPerPixel = 4;
|
||||
|
||||
// parse for help argument
|
||||
{
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
if ((string)argv[i] == "-h" || (string)argv[i] == "--help")
|
||||
{
|
||||
printHelpMessage();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse optional arguments
|
||||
if (argc > 1) // sample count
|
||||
{
|
||||
initSampleCount = atoi(argv[1]);
|
||||
if (initSampleCount <= 0)
|
||||
{
|
||||
cerr << "Sample count have to be a positive integer: " << argv[1] << endl;
|
||||
return 1;
|
||||
}
|
||||
initSeedCount = (int)floor(static_cast<float>(initSampleCount / 4));
|
||||
initSeedCount = std::max(1, initSeedCount); // fallback if sample count == 1
|
||||
}
|
||||
if (argc > 2) // seed count
|
||||
{
|
||||
initSeedCount = atoi(argv[2]);
|
||||
if (initSeedCount <= 0)
|
||||
{
|
||||
cerr << "Seed count have to be a positive integer: " << argv[2] << endl;
|
||||
return 1;
|
||||
}
|
||||
if (initSeedCount > initSampleCount)
|
||||
{
|
||||
cerr << "Seed count have to be lower or equal to sample count!" << endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// create algorithm
|
||||
Ptr<PCTSignatures> pctSignatures = PCTSignatures::create(initSampleCount, initSeedCount, PCTSignatures::UNIFORM);
|
||||
pctSignatures->setGrayscaleBits(grayscaleBitsPerPixel);
|
||||
|
||||
// open video capture device
|
||||
VideoCapture videoCapture;
|
||||
if (!videoCapture.open(0))
|
||||
{
|
||||
cerr << "Unable to open the first video capture device with ID = 0!" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create windows for display.
|
||||
namedWindow("Source", WINDOW_AUTOSIZE);
|
||||
namedWindow("Result", WINDOW_AUTOSIZE);
|
||||
|
||||
// run drawing loop
|
||||
for (;;)
|
||||
{
|
||||
videoCapture >> frame;
|
||||
if (frame.empty()) break; // end of video stream
|
||||
|
||||
pctSignatures->computeSignature(frame, signature);
|
||||
PCTSignatures::drawSignature(Mat::zeros(frame.size(), frame.type()), signature, result);
|
||||
|
||||
imshow("Source", frame); // Show our images inside the windows.
|
||||
imshow("Result", result);
|
||||
|
||||
if (waitKey(1) == 27) break; // stop videocapturing by pressing ESC
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* shape_context.cpp -- Shape context demo for shape matching
|
||||
*/
|
||||
#include <iostream>
|
||||
#include "opencv2/opencv_modules.hpp"
|
||||
|
||||
#ifdef HAVE_OPENCV_SHAPE
|
||||
|
||||
#include "opencv2/shape.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/features.hpp"
|
||||
#include "opencv2/xfeatures2d.hpp"
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
using namespace cv::xfeatures2d;
|
||||
|
||||
static void help()
|
||||
{
|
||||
printf("\nThis program demonstrates how to use common interface for shape transformers\n"
|
||||
"Call\n"
|
||||
"shape_transformation [image1] [image2]\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
help();
|
||||
if (argc < 3)
|
||||
{
|
||||
printf("Not enough parameters\n");
|
||||
return -1;
|
||||
}
|
||||
Mat img1 = imread(argv[1], IMREAD_GRAYSCALE);
|
||||
Mat img2 = imread(argv[2], IMREAD_GRAYSCALE);
|
||||
if(img1.empty() || img2.empty())
|
||||
{
|
||||
printf("Can't read one of the images\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// detecting keypoints & computing descriptors
|
||||
Ptr<SURF> surf = SURF::create(5000);
|
||||
vector<KeyPoint> keypoints1, keypoints2;
|
||||
Mat descriptors1, descriptors2;
|
||||
surf->detectAndCompute(img1, Mat(), keypoints1, descriptors1);
|
||||
surf->detectAndCompute(img2, Mat(), keypoints2, descriptors2);
|
||||
|
||||
// matching descriptors
|
||||
BFMatcher matcher(surf->defaultNorm());
|
||||
vector<DMatch> matches;
|
||||
matcher.match(descriptors1, descriptors2, matches);
|
||||
|
||||
// drawing the results
|
||||
namedWindow("matches", 1);
|
||||
Mat img_matches;
|
||||
drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches);
|
||||
imshow("matches", img_matches);
|
||||
|
||||
// extract points
|
||||
vector<Point2f> pts1, pts2;
|
||||
for (size_t ii=0; ii<keypoints1.size(); ii++)
|
||||
pts1.push_back( keypoints1[ii].pt );
|
||||
for (size_t ii=0; ii<keypoints2.size(); ii++)
|
||||
pts2.push_back( keypoints2[ii].pt );
|
||||
|
||||
// Apply TPS
|
||||
Ptr<ThinPlateSplineShapeTransformer> mytps = createThinPlateSplineShapeTransformer(25000); //TPS with a relaxed constraint
|
||||
mytps->estimateTransformation(pts1, pts2, matches);
|
||||
mytps->warpImage(img2, img2);
|
||||
|
||||
imshow("Tranformed", img2);
|
||||
waitKey(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cerr << "OpenCV was built without shape module" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // HAVE_OPENCV_SHAPE
|
||||
@@ -0,0 +1,225 @@
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include "opencv2/core/ocl.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/features.hpp"
|
||||
#include "opencv2/geometry.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/xfeatures2d.hpp"
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::xfeatures2d;
|
||||
|
||||
const int LOOP_NUM = 10;
|
||||
const int GOOD_PTS_MAX = 50;
|
||||
const float GOOD_PORTION = 0.15f;
|
||||
|
||||
int64 work_begin = 0;
|
||||
int64 work_end = 0;
|
||||
|
||||
static void workBegin()
|
||||
{
|
||||
work_begin = getTickCount();
|
||||
}
|
||||
|
||||
static void workEnd()
|
||||
{
|
||||
work_end = getTickCount() - work_begin;
|
||||
}
|
||||
|
||||
static double getTime()
|
||||
{
|
||||
return work_end /((double)getTickFrequency() )* 1000.;
|
||||
}
|
||||
|
||||
struct SURFDetector
|
||||
{
|
||||
Ptr<Feature2D> surf;
|
||||
SURFDetector(double hessian = 800.0)
|
||||
{
|
||||
surf = SURF::create(hessian);
|
||||
}
|
||||
template<class T>
|
||||
void operator()(const T& in, const T& mask, std::vector<cv::KeyPoint>& pts, T& descriptors, bool useProvided = false)
|
||||
{
|
||||
surf->detectAndCompute(in, mask, pts, descriptors, useProvided);
|
||||
}
|
||||
};
|
||||
|
||||
template<class KPMatcher>
|
||||
struct SURFMatcher
|
||||
{
|
||||
KPMatcher matcher;
|
||||
template<class T>
|
||||
void match(const T& in1, const T& in2, std::vector<cv::DMatch>& matches)
|
||||
{
|
||||
matcher.match(in1, in2, matches);
|
||||
}
|
||||
};
|
||||
|
||||
static Mat drawGoodMatches(
|
||||
const Mat& img1,
|
||||
const Mat& img2,
|
||||
const std::vector<KeyPoint>& keypoints1,
|
||||
const std::vector<KeyPoint>& keypoints2,
|
||||
std::vector<DMatch>& matches,
|
||||
std::vector<Point2f>& scene_corners_
|
||||
)
|
||||
{
|
||||
//-- Sort matches and preserve top 10% matches
|
||||
std::sort(matches.begin(), matches.end());
|
||||
std::vector< DMatch > good_matches;
|
||||
double minDist = matches.front().distance;
|
||||
double maxDist = matches.back().distance;
|
||||
|
||||
const int ptsPairs = std::min(GOOD_PTS_MAX, (int)(matches.size() * GOOD_PORTION));
|
||||
for( int i = 0; i < ptsPairs; i++ )
|
||||
{
|
||||
good_matches.push_back( matches[i] );
|
||||
}
|
||||
std::cout << "\nMax distance: " << maxDist << std::endl;
|
||||
std::cout << "Min distance: " << minDist << std::endl;
|
||||
|
||||
std::cout << "Calculating homography using " << ptsPairs << " point pairs." << std::endl;
|
||||
|
||||
// drawing the results
|
||||
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 );
|
||||
|
||||
//-- 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( keypoints1[ good_matches[i].queryIdx ].pt );
|
||||
scene.push_back( keypoints2[ good_matches[i].trainIdx ].pt );
|
||||
}
|
||||
//-- Get the corners from the image_1 ( the object to be "detected" )
|
||||
std::vector<Point2f> obj_corners(4);
|
||||
obj_corners[0] = Point(0,0);
|
||||
obj_corners[1] = Point( img1.cols, 0 );
|
||||
obj_corners[2] = Point( img1.cols, img1.rows );
|
||||
obj_corners[3] = Point( 0, img1.rows );
|
||||
std::vector<Point2f> scene_corners(4);
|
||||
|
||||
Mat H = findHomography( obj, scene, RANSAC );
|
||||
perspectiveTransform( obj_corners, scene_corners, H);
|
||||
|
||||
scene_corners_ = scene_corners;
|
||||
|
||||
//-- Draw lines between the corners (the mapped object in the scene - image_2 )
|
||||
line( img_matches,
|
||||
scene_corners[0] + Point2f( (float)img1.cols, 0), scene_corners[1] + Point2f( (float)img1.cols, 0),
|
||||
Scalar( 0, 255, 0), 2, LINE_AA );
|
||||
line( img_matches,
|
||||
scene_corners[1] + Point2f( (float)img1.cols, 0), scene_corners[2] + Point2f( (float)img1.cols, 0),
|
||||
Scalar( 0, 255, 0), 2, LINE_AA );
|
||||
line( img_matches,
|
||||
scene_corners[2] + Point2f( (float)img1.cols, 0), scene_corners[3] + Point2f( (float)img1.cols, 0),
|
||||
Scalar( 0, 255, 0), 2, LINE_AA );
|
||||
line( img_matches,
|
||||
scene_corners[3] + Point2f( (float)img1.cols, 0), scene_corners[0] + Point2f( (float)img1.cols, 0),
|
||||
Scalar( 0, 255, 0), 2, LINE_AA );
|
||||
return img_matches;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// This program demonstrates the usage of SURF_OCL.
|
||||
// use cpu findHomography interface to calculate the transformation matrix
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* keys =
|
||||
"{ h help | | print help message }"
|
||||
"{ l left | box.png | specify left image }"
|
||||
"{ r right | box_in_scene.png | specify right image }"
|
||||
"{ o output | SURF_output.jpg | specify output save path }"
|
||||
"{ m cpu_mode | | run without OpenCL }";
|
||||
|
||||
CommandLineParser cmd(argc, argv, keys);
|
||||
if (cmd.has("help"))
|
||||
{
|
||||
std::cout << "Usage: surf_matcher [options]" << std::endl;
|
||||
std::cout << "Available options:" << std::endl;
|
||||
cmd.printMessage();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
if (cmd.has("cpu_mode"))
|
||||
{
|
||||
ocl::setUseOpenCL(false);
|
||||
std::cout << "OpenCL was disabled" << std::endl;
|
||||
}
|
||||
|
||||
UMat img1, img2;
|
||||
|
||||
std::string outpath = cmd.get<std::string>("o");
|
||||
|
||||
std::string leftName = cmd.get<std::string>("l");
|
||||
imread(leftName, IMREAD_GRAYSCALE).copyTo(img1);
|
||||
if(img1.empty())
|
||||
{
|
||||
std::cout << "Couldn't load " << leftName << std::endl;
|
||||
cmd.printMessage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string rightName = cmd.get<std::string>("r");
|
||||
imread(rightName, IMREAD_GRAYSCALE).copyTo(img2);
|
||||
if(img2.empty())
|
||||
{
|
||||
std::cout << "Couldn't load " << rightName << std::endl;
|
||||
cmd.printMessage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
double surf_time = 0.;
|
||||
|
||||
//declare input/output
|
||||
std::vector<KeyPoint> keypoints1, keypoints2;
|
||||
std::vector<DMatch> matches;
|
||||
|
||||
UMat _descriptors1, _descriptors2;
|
||||
Mat descriptors1 = _descriptors1.getMat(ACCESS_RW),
|
||||
descriptors2 = _descriptors2.getMat(ACCESS_RW);
|
||||
|
||||
//instantiate detectors/matchers
|
||||
SURFDetector surf;
|
||||
|
||||
SURFMatcher<BFMatcher> matcher;
|
||||
|
||||
//-- start of timing section
|
||||
|
||||
for (int i = 0; i <= LOOP_NUM; i++)
|
||||
{
|
||||
if(i == 1) workBegin();
|
||||
surf(img1.getMat(ACCESS_READ), Mat(), keypoints1, descriptors1);
|
||||
surf(img2.getMat(ACCESS_READ), Mat(), keypoints2, descriptors2);
|
||||
matcher.match(descriptors1, descriptors2, matches);
|
||||
}
|
||||
workEnd();
|
||||
std::cout << "FOUND " << keypoints1.size() << " keypoints on first image" << std::endl;
|
||||
std::cout << "FOUND " << keypoints2.size() << " keypoints on second image" << std::endl;
|
||||
|
||||
surf_time = getTime();
|
||||
std::cout << "SURF run time: " << surf_time / LOOP_NUM << " ms" << std::endl<<"\n";
|
||||
|
||||
|
||||
std::vector<Point2f> corner;
|
||||
Mat img_matches = drawGoodMatches(img1.getMat(ACCESS_READ), img2.getMat(ACCESS_READ), keypoints1, keypoints2, matches, corner);
|
||||
|
||||
//-- Show detected matches
|
||||
|
||||
namedWindow("surf matches", 0);
|
||||
imshow("surf matches", img_matches);
|
||||
imwrite(outpath, img_matches);
|
||||
|
||||
waitKey(0);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* video_homography.cpp
|
||||
*
|
||||
* Created on: Oct 18, 2010
|
||||
* Author: erublee
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "opencv2/opencv_modules.hpp"
|
||||
|
||||
#ifdef HAVE_OPENCV_3D
|
||||
|
||||
#include "opencv2/geometry.hpp"
|
||||
#include "opencv2/videoio.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/features.hpp"
|
||||
#include "opencv2/xfeatures2d.hpp"
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
using namespace cv::xfeatures2d;
|
||||
|
||||
static void help(char **av)
|
||||
{
|
||||
cout << "\nThis program demonstrated the use of features with the Fast corner detector and brief descriptors\n"
|
||||
<< "to track planar objects by computing their homography from the key (training) image to the query (test) image\n\n" << endl;
|
||||
cout << "usage: " << av[0] << " <video device number>\n" << endl;
|
||||
cout << "The following keys do stuff:" << endl;
|
||||
cout << " t : grabs a reference frame to match against" << endl;
|
||||
cout << " l : makes the reference frame new every frame" << endl;
|
||||
cout << " q or escape: quit" << endl;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void drawMatchesRelative(const vector<KeyPoint>& train, const vector<KeyPoint>& query,
|
||||
std::vector<cv::DMatch>& matches, Mat& img, const vector<unsigned char>& mask = vector<
|
||||
unsigned char> ())
|
||||
{
|
||||
for (int i = 0; i < (int)matches.size(); i++)
|
||||
{
|
||||
if (mask.empty() || mask[i])
|
||||
{
|
||||
Point2f pt_new = query[matches[i].queryIdx].pt;
|
||||
Point2f pt_old = train[matches[i].trainIdx].pt;
|
||||
|
||||
cv::line(img, pt_new, pt_old, Scalar(125, 255, 125), 1);
|
||||
cv::circle(img, pt_new, 2, Scalar(255, 0, 125), 1);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Takes a descriptor and turns it into an xy point
|
||||
void keypoints2points(const vector<KeyPoint>& in, vector<Point2f>& out)
|
||||
{
|
||||
out.clear();
|
||||
out.reserve(in.size());
|
||||
for (size_t i = 0; i < in.size(); ++i)
|
||||
{
|
||||
out.push_back(in[i].pt);
|
||||
}
|
||||
}
|
||||
|
||||
//Takes an xy point and appends that to a keypoint structure
|
||||
void points2keypoints(const vector<Point2f>& in, vector<KeyPoint>& out)
|
||||
{
|
||||
out.clear();
|
||||
out.reserve(in.size());
|
||||
for (size_t i = 0; i < in.size(); ++i)
|
||||
{
|
||||
out.push_back(KeyPoint(in[i], 1));
|
||||
}
|
||||
}
|
||||
|
||||
//Uses computed homography H to warp original input points to new planar position
|
||||
void warpKeypoints(const Mat& H, const vector<KeyPoint>& in, vector<KeyPoint>& out)
|
||||
{
|
||||
vector<Point2f> pts;
|
||||
keypoints2points(in, pts);
|
||||
vector<Point2f> pts_w(pts.size());
|
||||
Mat m_pts_w(pts_w);
|
||||
perspectiveTransform(Mat(pts), m_pts_w, H);
|
||||
points2keypoints(pts_w, out);
|
||||
}
|
||||
|
||||
//Converts matching indices to xy points
|
||||
void matches2points(const vector<KeyPoint>& train, const vector<KeyPoint>& query,
|
||||
const std::vector<cv::DMatch>& matches, std::vector<cv::Point2f>& pts_train,
|
||||
std::vector<Point2f>& pts_query)
|
||||
{
|
||||
|
||||
pts_train.clear();
|
||||
pts_query.clear();
|
||||
pts_train.reserve(matches.size());
|
||||
pts_query.reserve(matches.size());
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
for (; i < matches.size(); i++)
|
||||
{
|
||||
|
||||
const DMatch & dmatch = matches[i];
|
||||
|
||||
pts_query.push_back(query[dmatch.queryIdx].pt);
|
||||
pts_train.push_back(train[dmatch.trainIdx].pt);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void resetH(Mat&H)
|
||||
{
|
||||
H = Mat::eye(3, 3, CV_32FC1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int ac, char ** av)
|
||||
{
|
||||
|
||||
if (ac != 2)
|
||||
{
|
||||
help(av);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Ptr<BriefDescriptorExtractor> brief = BriefDescriptorExtractor::create(32);
|
||||
|
||||
VideoCapture capture;
|
||||
capture.open(atoi(av[1]));
|
||||
if (!capture.isOpened())
|
||||
{
|
||||
help(av);
|
||||
cout << "capture device " << atoi(av[1]) << " failed to open!" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
cout << "following keys do stuff:" << endl;
|
||||
cout << "t : grabs a reference frame to match against" << endl;
|
||||
cout << "l : makes the reference frame new every frame" << endl;
|
||||
cout << "q or escape: quit" << endl;
|
||||
|
||||
Mat frame;
|
||||
|
||||
vector<DMatch> matches;
|
||||
|
||||
BFMatcher desc_matcher(brief->defaultNorm());
|
||||
|
||||
vector<Point2f> train_pts, query_pts;
|
||||
vector<KeyPoint> train_kpts, query_kpts;
|
||||
vector<unsigned char> match_mask;
|
||||
|
||||
Mat gray;
|
||||
|
||||
bool ref_live = true;
|
||||
|
||||
Mat train_desc, query_desc;
|
||||
Ptr<FastFeatureDetector> detector = FastFeatureDetector::create(10, true);
|
||||
|
||||
Mat H_prev = Mat::eye(3, 3, CV_32FC1);
|
||||
for (;;)
|
||||
{
|
||||
capture >> frame;
|
||||
if (frame.empty())
|
||||
break;
|
||||
|
||||
cvtColor(frame, gray, COLOR_RGB2GRAY);
|
||||
|
||||
detector->detect(gray, query_kpts); //Find interest points
|
||||
brief->compute(gray, query_kpts, query_desc); //Compute brief descriptors at each keypoint location
|
||||
|
||||
if (!train_kpts.empty())
|
||||
{
|
||||
|
||||
vector<KeyPoint> test_kpts;
|
||||
warpKeypoints(H_prev.inv(), query_kpts, test_kpts);
|
||||
|
||||
//Mat mask = windowedMatchingMask(test_kpts, train_kpts, 25, 25);
|
||||
desc_matcher.match(query_desc, train_desc, matches, Mat());
|
||||
drawKeypoints(frame, test_kpts, frame, Scalar(255, 0, 0), DrawMatchesFlags::DRAW_OVER_OUTIMG);
|
||||
|
||||
matches2points(train_kpts, query_kpts, matches, train_pts, query_pts);
|
||||
|
||||
if (matches.size() > 5)
|
||||
{
|
||||
Mat H = findHomography(train_pts, query_pts, RANSAC, 4, match_mask);
|
||||
if (countNonZero(Mat(match_mask)) > 15)
|
||||
{
|
||||
H_prev = H;
|
||||
}
|
||||
else
|
||||
resetH(H_prev);
|
||||
drawMatchesRelative(train_kpts, query_kpts, matches, frame, match_mask);
|
||||
}
|
||||
else
|
||||
resetH(H_prev);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
H_prev = Mat::eye(3, 3, CV_32FC1);
|
||||
Mat out;
|
||||
drawKeypoints(gray, query_kpts, out);
|
||||
frame = out;
|
||||
}
|
||||
|
||||
imshow("frame", frame);
|
||||
|
||||
if (ref_live)
|
||||
{
|
||||
train_kpts = query_kpts;
|
||||
query_desc.copyTo(train_desc);
|
||||
}
|
||||
char key = (char)waitKey(2);
|
||||
switch (key)
|
||||
{
|
||||
case 'l':
|
||||
ref_live = true;
|
||||
resetH(H_prev);
|
||||
break;
|
||||
case 't':
|
||||
ref_live = false;
|
||||
train_kpts = query_kpts;
|
||||
query_desc.copyTo(train_desc);
|
||||
resetH(H_prev);
|
||||
break;
|
||||
case 27:
|
||||
case 'q':
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cerr << "OpenCV was built without 3d module" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user