123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- /*
- * video_homography.cpp
- *
- * Created on: Oct 18, 2010
- * Author: erublee
- */
- #include <iostream>
- #include "opencv2/opencv_modules.hpp"
- #ifdef HAVE_OPENCV_CALIB3D
- #include "opencv2/calib3d.hpp"
- #include "opencv2/videoio.hpp"
- #include "opencv2/highgui.hpp"
- #include "opencv2/imgproc.hpp"
- #include "opencv2/features2d.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 features2d 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 calib3d module" << std::endl;
- return 0;
- }
- #endif
|