改进orb提取算法,首先通过图像尺寸大小来确定所需要构建的金字塔的层数;接着针对每层金字塔图像的大小来划分网格;根据图像灰度信息计算出一 种自适应提取阈值,若此阈值提取的特征点数目不满足要求,则降低阈值至 T/2,直到提取的特征点数目达到要求,对每层图像金字塔中的网格按照一定顺序提取特征点;然后采用四叉树算法均匀化;最后采用GMS匹配算法。给出源码和头文件
时间: 2024-02-12 11:08:34 浏览: 88
以下是一个参考实现,仅供参考:
```c++
#include <opencv2/opencv.hpp>
#include <vector>
#include <cmath>
using namespace cv;
using namespace std;
// 自适应阈值计算函数
double thresholdAdapt(Mat img, double k)
{
Mat dst, stdDev;
meanStdDev(img, dst, stdDev);
double T = dst.at<double>(0, 0) + k * stdDev.at<double>(0, 0);
return T;
}
// 计算网格数量
int calcGridNum(int width, int height, int grid_size)
{
int grid_cols = ceil((double)width / (double)grid_size);
int grid_rows = ceil((double)height / (double)grid_size);
return grid_cols * grid_rows;
}
// 网格提取ORB特征点
void extractORBInGrid(Mat img, int grid_size, int max_features, vector<KeyPoint>& kpts, Mat& desc)
{
int width = img.cols;
int height = img.rows;
int grid_cols = ceil((double)width / (double)grid_size);
int grid_rows = ceil((double)height / (double)grid_size);
int num_grids = grid_cols * grid_rows;
int num_features_per_grid = ceil((double)max_features / (double)num_grids);
for (int i = 0; i < grid_rows; i++)
{
for (int j = 0; j < grid_cols; j++)
{
int x = j * grid_size;
int y = i * grid_size;
int w = min(grid_size, width - x);
int h = min(grid_size, height - y);
if (w <= 0 || h <= 0) continue;
Rect roi(x, y, w, h);
Mat roi_img = img(roi);
// 计算自适应阈值
double T = thresholdAdapt(roi_img, 0.5);
// 提取ORB特征点
vector<KeyPoint> grid_kpts;
Mat grid_desc;
Ptr<ORB> orb = ORB::create(num_features_per_grid);
orb->detectAndCompute(roi_img, noArray(), grid_kpts, grid_desc);
// 检查特征点数量是否满足要求
if (grid_kpts.size() > num_features_per_grid)
{
// 降低阈值
do
{
T /= 2;
grid_kpts.clear();
grid_desc.release();
orb = ORB::create(num_features_per_grid);
orb->detectAndCompute(roi_img, noArray(), grid_kpts, grid_desc);
} while (grid_kpts.size() > num_features_per_grid && T > 1);
}
// 将特征点位置转换到全局坐标系
for (int k = 0; k < grid_kpts.size(); k++)
{
grid_kpts[k].pt.x += x;
grid_kpts[k].pt.y += y;
}
// 合并ORB特征点和描述子
kpts.insert(kpts.end(), grid_kpts.begin(), grid_kpts.end());
desc.push_back(grid_desc);
}
}
}
// 四叉树均匀化
void quadTreeSubDivide(vector<KeyPoint>& kpts, int min_features_per_cell)
{
vector<KeyPoint> new_kpts;
for (int i = 0; i < kpts.size(); i++)
{
KeyPoint kp = kpts[i];
int x = (int)kp.pt.x;
int y = (int)kp.pt.y;
int size = (int)kp.size;
if (size > 1 && size >= 2 * min_features_per_cell)
{
int new_size = size / 2;
KeyPoint kp0(x - new_size / 2, y - new_size / 2, new_size);
KeyPoint kp1(x + new_size / 2, y - new_size / 2, new_size);
KeyPoint kp2(x - new_size / 2, y + new_size / 2, new_size);
KeyPoint kp3(x + new_size / 2, y + new_size / 2, new_size);
new_kpts.push_back(kp0);
new_kpts.push_back(kp1);
new_kpts.push_back(kp2);
new_kpts.push_back(kp3);
}
else
{
new_kpts.push_back(kp);
}
}
kpts = new_kpts;
}
// GMS匹配算法
void GMSMatch(Mat desc1, Mat desc2, vector<DMatch>& matches, float reprojThresh = 1.0f)
{
vector<Point2f> pts1, pts2;
vector<KeyPoint> kpts1, kpts2;
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");
matcher->match(desc1, desc2, matches);
// 将匹配点转换为点坐标
for (int i = 0; i < matches.size(); i++)
{
pts1.push_back(kpts1[matches[i].queryIdx].pt);
pts2.push_back(kpts2[matches[i].trainIdx].pt);
}
// 计算单应性矩阵
Mat H = findHomography(pts1, pts2, RANSAC, reprojThresh);
// 进行逆映射,筛选出正确匹配
vector<DMatch> inliers;
for (int i = 0; i < matches.size(); i++)
{
Point2f pt1 = kpts1[matches[i].queryIdx].pt;
Point2f pt2 = kpts2[matches[i].trainIdx].pt;
Mat pt1_mat = (Mat_<double>(3, 1) << pt1.x, pt1.y, 1);
Mat pt2_mat = (Mat_<double>(3, 1) << pt2.x, pt2.y, 1);
Mat pt2_est = H * pt1_mat;
pt2_est /= pt2_est.at<double>(2, 0);
double dist = norm(pt2_mat - pt2_est);
if (dist < reprojThresh)
{
inliers.push_back(matches[i]);
}
}
matches = inliers;
}
// 主函数
int main()
{
// 读取图像
Mat img1 = imread("img1.jpg", IMREAD_GRAYSCALE);
Mat img2 = imread("img2.jpg", IMREAD_GRAYSCALE);
// 构建金字塔
vector<Mat> pyramid1, pyramid2;
pyramid1.push_back(img1);
pyramid2.push_back(img2);
int max_level = 3;
for (int i = 1; i <= max_level; i++)
{
Mat img1_down, img2_down;
pyrDown(pyramid1[i - 1], img1_down);
pyrDown(pyramid2[i - 1], img2_down);
pyramid1.push_back(img1_down);
pyramid2.push_back(img2_down);
}
// 提取ORB特征点和描述子
vector<KeyPoint> kpts1, kpts2;
Mat desc1, desc2;
int grid_size = 50;
int max_features = 500;
int min_features_per_cell = 5;
for (int i = max_level; i >= 0; i--)
{
extractORBInGrid(pyramid1[i], grid_size, max_features, kpts1, desc1);
extractORBInGrid(pyramid2[i], grid_size, max_features, kpts2, desc2);
}
// 进行四叉树均匀化
quadTreeSubDivide(kpts1, min_features_per_cell);
quadTreeSubDivide(kpts2, min_features_per_cell);
// 进行GMS匹配
vector<DMatch> matches;
GMSMatch(desc1, desc2, matches);
// 绘制匹配结果
Mat img_matches;
drawMatches(img1, kpts1, img2, kpts2, matches, img_matches);
imshow("Matches", img_matches);
waitKey(0);
return 0;
}
```
需要注意的是,以上代码仅供参考,可能存在错误或不足之处。如果您想要使用这个算法,需要根据实际需求进行修改和优化。
阅读全文