改进orb提取算法,首先通过图像尺寸大小来确定所需要构建的金字塔的层数;将特征点均摊到每层图像上,将剩余的特征点全部归于图像金字塔的顶层;根据图像灰度信息计算出一种自适应提取阈值,若此阈值提取的特征点数目不满足要求,则降低阈值至 T/2,直到提取的特征点数目达到要求;对每层图像进行网格划分,从图像金字塔的第一层开始遍历网格进行特征提取并对每个网格计数,然后采用四叉树算法均匀化;最后采用GMS匹配算法。给出源码和头文件
时间: 2024-02-12 15:08:54 浏览: 130
很抱歉,我之前的回答有误。以下是改进ORB算法的源代码和头文件供参考:
源代码:
```
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
vector<KeyPoint> pyramidKeypoints;
vector<vector<KeyPoint>> gridKeypoints;
vector<Mat> pyramidDescriptors;
vector<Mat> pyramidImages;
void buildPyramidImages(const Mat &image, vector<Mat> &pyramidImages, int pyramidLevel) {
pyramidImages.clear();
pyramidImages.push_back(image.clone());
for (int i = 1; i < pyramidLevel; ++i) {
Mat tmp;
pyrDown(pyramidImages.back(), tmp);
pyramidImages.push_back(tmp);
}
}
void buildPyramidKeypoints(vector<KeyPoint> &pyramidKeypoints, const vector<Mat> &pyramidImages) {
const int pyramidLevel = pyramidImages.size();
pyramidKeypoints.clear();
for (int level = 0; level < pyramidLevel; ++level) {
const float scale = pow(2.0, level);
vector<KeyPoint> keypoints;
for (auto & keypoint : pyramidKeypoints) {
KeyPoint scaledKeypoint(keypoint.pt * scale, keypoint.size * scale, keypoint.angle, keypoint.response, keypoint.octave + level);
keypoints.push_back(scaledKeypoint);
}
for (int y = 0; y < pyramidImages[level].rows; ++y) {
for (int x = 0; x < pyramidImages[level].cols; ++x) {
keypoints.push_back(KeyPoint(Point2f(x, y), 1, -1));
}
}
pyramidKeypoints.insert(pyramidKeypoints.end(), keypoints.begin(), keypoints.end());
}
}
void extractOrbDescriptor(const Mat &image, vector<KeyPoint> &keypoints, Mat &descriptor, int nfeatures, float scaleFactor, int nlevels) {
buildPyramidImages(image, pyramidImages, nlevels);
int maxFeaturesPerLevel = max(1, static_cast<int>(nfeatures / pyramidImages.size()));
int threshold = 80;
int lastKeypointCount = -1;
while (true) {
buildPyramidKeypoints(pyramidKeypoints, pyramidImages);
if (static_cast<int>(pyramidKeypoints.size()) > nfeatures) {
vector<KeyPoint> tmpKeypoints;
tmpKeypoints.reserve(nfeatures);
std::partial_sort(pyramidKeypoints.begin(), pyramidKeypoints.begin() + nfeatures, pyramidKeypoints.end(),
[](const KeyPoint &pt1, const KeyPoint &pt2) {
return pt1.response > pt2.response;
});
std::copy(pyramidKeypoints.begin(), pyramidKeypoints.begin() + nfeatures, back_inserter(tmpKeypoints));
pyramidKeypoints = tmpKeypoints;
}
if (static_cast<int>(pyramidKeypoints.size()) == lastKeypointCount) {
break;
}
lastKeypointCount = static_cast<int>(pyramidKeypoints.size());
if (lastKeypointCount > maxFeaturesPerLevel) {
threshold /= 2;
} else {
threshold *= 2;
}
if (threshold > 255) {
threshold = 255;
} else if (threshold < 1) {
threshold = 1;
}
pyramidDescriptors.clear();
for (auto & image : pyramidImages) {
vector<KeyPoint> keypoints;
Mat descriptor;
Ptr<ORB> orbDetector = ORB::create(lastKeypointCount);
orbDetector->setFastThreshold(threshold);
orbDetector->detectAndCompute(image, noArray(), keypoints, descriptor);
pyramidDescriptors.push_back(descriptor);
}
}
int totalKeypoints = 0;
for (auto & keypoints : pyramidKeypoints) {
totalKeypoints += static_cast<int>(keypoints.size());
}
vector<vector<int>> gridCount(pyramidImages.size());
const int gridCols = 4;
const int gridRows = 4;
const int gridWidth = image.cols / gridCols;
const int gridHeight = image.rows / gridRows;
for (int level = 0; level < pyramidImages.size(); ++level) {
gridCount[level].resize(gridCols * gridRows);
gridKeypoints[level].resize(gridCols * gridRows);
for (int r = 0; r < gridRows; ++r) {
for (int c = 0; c < gridCols; ++c) {
int index = r * gridCols + c;
gridKeypoints[level][index].reserve(totalKeypoints / (gridCols * gridRows));
}
}
for (auto & keypoint : pyramidKeypoints) {
if (keypoint.octave == level) {
int x = static_cast<int>(keypoint.pt.x / gridWidth);
int y = static_cast<int>(keypoint.pt.y / gridHeight);
int index = y * gridCols + x;
gridCount[level][index] += 1;
gridKeypoints[level][index].push_back(keypoint);
}
}
int minCount = INT_MAX;
for (auto & count : gridCount[level]) {
if (count < minCount) {
minCount = count;
}
}
for (int row = 0; row < gridRows; ++row) {
for (int col = 0; col < gridCols; ++col) {
int index = row * gridCols + col;
if (gridCount[level][index] > 2 * minCount) {
vector<KeyPoint> &keypoints = gridKeypoints[level][index];
sort(keypoints.begin(), keypoints.end(),
[](const KeyPoint &pt1, const KeyPoint &pt2) {
return pt1.response > pt2.response;
});
keypoints.resize(static_cast<int>(keypoints.size() * 0.8));
}
}
}
}
Mat allDescriptors;
for (int i = 0; i < pyramidImages.size(); ++i) {
Ptr<DescriptorMatcher> descriptorMatcher = DescriptorMatcher::create("BruteForce-Hamming");
descriptorMatcher->add(vector<Mat>{pyramidDescriptors[i]});
if (i > 0) {
descriptorMatcher->add(vector<Mat>{pyramidDescriptors[i - 1]});
}
descriptorMatcher->train();
for (int row = 0; row < gridRows; ++row) {
for (int col = 0; col < gridCols; ++col) {
int index = row * gridCols + col;
vector<KeyPoint> &keypoints = gridKeypoints[i][index];
if (keypoints.empty()) {
continue;
}
Mat desc = Mat(keypoints.size(), allDescriptors.cols, allDescriptors.type());
int offset = 0;
for (int j = 0; j < keypoints.size(); ++j) {
if (i == 0) {
pyramidKeypoints.push_back(keypoints[j]);
}
allDescriptors.row(pyramidKeypoints.size() - 1).copyTo(desc.row(j));
offset += allDescriptors.cols;
}
vector<vector<DMatch>> matches;
if (i > 0) {
descriptorMatcher->knnMatch(pyramidDescriptors[i], pyramidDescriptors[i - 1], matches, 2);
for (auto & match : matches) {
if (match[0].distance < 0.75 * match[1].distance) {
int queryIndex = match[0].queryIdx;
int trainIndex = match[0].trainIdx;
if (trainIndex >= offset - allDescriptors.cols && trainIndex < offset) {
int j = trainIndex - (offset - allDescriptors.cols);
pyramidKeypoints[j].octave = i - 1;
}
}
}
}
descriptor.push_back(desc);
}
}
}
}
int main() {
Mat image = imread("test.jpg");
if (image.empty()) {
cerr << "Failed to load image." << endl;
return -1;
}
int nfeatures = 5000;
float scaleFactor = 1.2f;
int nlevels = static_cast<int>(log2(static_cast<float>(std::min(image.cols, image.rows)))) - 3;
gridKeypoints.resize(nlevels);
Mat descriptor;
vector<KeyPoint> keypoints;
extractOrbDescriptor(image, keypoints, descriptor, nfeatures, scaleFactor, nlevels);
cout << "Extracted " << keypoints.size() << " keypoints." << endl;
return 0;
}
```
头文件:
```
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void buildPyramidImages(const Mat &image, vector<Mat> &pyramidImages, int pyramidLevel);
void buildPyramidKeypoints(vector<KeyPoint> &pyramidKeypoints, const vector<Mat> &pyramidImages);
void extractOrbDescriptor(const Mat &image, vector<KeyPoint> &keypoints, Mat &descriptor, int nfeatures, float scaleFactor, int nlevels);
```
阅读全文