《深入理解OpenCV——实用计算机视觉项目解析》第四章学习。
在富特征上使用光流匹配的优势在于处理过程通常较快且能容纳更多的匹配点。
将结构KeyPoint转化成Point2f的代码如下:
void KeyPointsToPoints(const vector<KeyPoint>& kps, vector<Point2f>& ps)
{
ps.clear();
for (unsigned int i = 0; i<kps.size(); i++)
ps.push_back(kps[i].pt);
}
特征提取的方式可以根据实际情况改变,这里使用FAST特征点检测。
光流匹配的代码如下:
void OFMatch()
{
String fileName1 = "1.jpg";
String fileName2 = "2.jpg";
Mat img1;
Mat img2;
img1 = imread(fileName1,1);
img2 = imread(fileName2,1);
if (!img1.data || !img2.data)
{
cout << "error reading" << endl;
}
vector<KeyPoint>left_keypoints, right_keypoints;
//寻找左右两张图中的特征点
FastFeatureDetector ffd;
ffd.detect(img1, left_keypoints);
ffd.detect(img2, right_keypoints);
vector<Point2f> left_points;
KeyPointsToPoints(left_keypoints, left_points);
vector<Point2f> right_points(left_keypoints.size());
KeyPointsToPoints(right_keypoints, right_points);
//保证图片为灰度图
Mat imgGray1, imgGray2;
cvtColor(img1, imgGray1, CV_RGB2GRAY);
cvtColor(img2, imgGray2, CV_RGB2GRAY);
//计算光流域
vector<uchar>vstatus;
vector<float>verror;
calcOpticalFlowPyrLK(imgGray1, imgGray2, left_points, right_points, vstatus, verror);
Mat imofkl = img1.clone();
for (int i = 0; i < vstatus.size(); i++)
{
if (vstatus[i] && verror[i] < 12)
{
line(imofkl, left_points[i], right_points[i], CV_RGB(255, 255, 255), 1, 8, 0);
circle(imofkl, right_points[i], 3, CV_RGB(255, 255, 255), 1, 8, 0);
}
}
namedWindow("光流", WINDOW_NORMAL);
imshow("光流", imofkl);
//去除大误差点
vector<Point2f> right_points_to_find;
vector<int> right_points_to_find_back_index;
for (unsigned int i = 0; i < vstatus.size(); i++)
{
if (vstatus[i] && verror[i] < 12.0)
{
//为使用特征保留原始光流序列的点索引
right_points_to_find_back_index.push_back(i);
//保持特征点本身
right_points_to_find.push_back(right_points[i]);
}
else
{
vstatus[i] = 0;
}
}
//查看每个正确点属于的特征
Mat right_points_to_find_flat = Mat(right_points_to_find).reshape(1, right_points_to_find.size());
vector<Point2f> right_features;
KeyPointsToPoints(right_keypoints, right_features);
Mat right_features_flat = Mat(right_features).reshape(1, right_features.size());
//匹配
BFMatcher matcher(CV_L2);
vector<vector<DMatch>> nearest_neighbors;
matcher.radiusMatch(right_points_to_find_flat, right_features_flat, nearest_neighbors, 2.0f);
//去除距离过近可能导致错误的点
set<int>found_in_right_points;
vector<DMatch>matches;
for (int i = 0; i < nearest_neighbors.size(); i++)
{
DMatch _m;
if (nearest_neighbors[i].size() == 1)
{
_m = nearest_neighbors[i][0];
}
else if (nearest_neighbors[i].size()>1)
{
double ratio = nearest_neighbors[i][0].distance / nearest_neighbors[i][1].distance;
if (ratio < 0.7)
{
_m = nearest_neighbors[i][0];
}
else
continue;
}
else
continue;
if (found_in_right_points.find(_m.trainIdx) == found_in_right_points.end())
{
_m.queryIdx = right_points_to_find_back_index[_m.queryIdx];
matches.push_back(_m);
found_in_right_points.insert(_m.trainIdx);
}
}
cout << "pruned" << matches.size() << "/" << nearest_neighbors.size() << "matches" << endl;
Mat result;
drawMatches(img1, left_keypoints, img2, right_keypoints, matches, result);
namedWindow("结果", WINDOW_NORMAL);
imshow("结果", result);
waitKey(0);
}
匹配结果如下:
1.光流
2.对富特征进行光流匹配结果