139 lines
5.4 KiB
C++
139 lines
5.4 KiB
C++
|
#include <iostream>
|
||
|
#include <opencv2/core.hpp>
|
||
|
#include <opencv2/videoio.hpp>
|
||
|
#include <opencv2/highgui.hpp>
|
||
|
#include <opencv2/imgproc.hpp>
|
||
|
#include <opencv2/features2d.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;
|
||
|
}
|