 2b106db02f
			
		
	
	2b106db02f
	
	
	
		
			
			Also fixed some typos and code alignment Also adapted tutorial CPP samples Fixed some identation problems
		
			
				
	
	
		
			234 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| * video_homography.cpp
 | |
| *
 | |
| *  Created on: Oct 18, 2010
 | |
| *      Author: erublee
 | |
| */
 | |
| 
 | |
| #include "opencv2/calib3d/calib3d.hpp"
 | |
| #include "opencv2/highgui/highgui.hpp"
 | |
| #include "opencv2/imgproc/imgproc.hpp"
 | |
| #include "opencv2/features2d/features2d.hpp"
 | |
| #include <iostream>
 | |
| #include <list>
 | |
| #include <vector>
 | |
| 
 | |
| using namespace std;
 | |
| using namespace cv;
 | |
| 
 | |
| 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;
 | |
|     }
 | |
| 
 | |
|     BriefDescriptorExtractor brief(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(NORM_HAMMING);
 | |
| 
 | |
|     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;
 | |
|     const int DESIRED_FTRS = 500;
 | |
|     GridAdaptedFeatureDetector detector(new FastFeatureDetector(10, true), DESIRED_FTRS, 4, 4);
 | |
| 
 | |
|     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, mask);
 | |
|             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;
 | |
| }
 |