一、ORB特征点
ORB特征点计算步骤:
Step1:选择某个像素点作为中心点P,其像素值为I。
Step2:设置判定FAST角点(其方法比较两个像素之间的差值)的像素阈值,例如
T
p
=
20
%
∗
I
p
T_p = 20\%*I_p
Tp=20%∗Ip
Step3:比较中心点的像素值与半径为3的圆周上所有像素的像素值进行比较,如果存在连续N个像素的像素值大于(
I
p
+
T
p
I_p+ T_p
Ip+Tp)或者小于(
I
p
−
T
p
I_p - T_p
Ip−Tp),则将中心点设置为FAST角点。
Step4:遍历图像中每个像素点,重复上述步骤,计算图像中的FAST角点。
如下图所示:
特征点计算步骤如下:
static Ptr<ORB> cv::ORB::create ( int nfeatures = 500, float scaleFactor = 1.2f, int nlevels = s, int edgeThreshold = 3i, int firstLevel = 0, int WTA_K= 2,score Type =
ORB::ScoreType ORB:: HARRIS_SCORE, int patchSize = 31, int fastThreshold = 20)
nfeatures:检测ORB特征点的数目。
scalcFactor:金字塔尺寸缩小的比例。
nlevels:金字塔层数。
edgeThreshold:边缘阈值(决定了提取特征点的精度)。
firstLevel:将原图像放入金字塔中的等级。
WTA_K:生成每位描述子时需要用的像素点数目。
scoreType:检测关键点时关键点评价方法。
patchSizc:生成描述子时关键点周围邻域的尺寸。
firstLevel:将原图像放入金字塔中的等级。
本节应用案例如下:
int main() {
//读取图片
Mat src = imread("2.jpg", IMREAD_COLOR);
if (src.empty())
{
printf("不能打开空图片");
return -1;
}
//创建ORB特征点类变量(其他的方法参见官网)
Ptr<ORB> orb = ORB::create(500, //特征点数目
1.2f, //金字塔层级之间的缩放比例
8, //金字塔图像层系数
31,//边缘阈值
0,//原图在金字塔中的层数
2,//生成描述子时需要用的像素点数目
ORB::HARRIS_SCORE,//使用Harris方法评价特征点
31,//生成描述子时关键点周围邻域的尺寸
20//计算FAST角点时像素差值的阈值
);
//计算ORB关键点
vector<KeyPoint> Keypoints;
//确定关键点
orb->detect(src, Keypoints);
//计算ORB描述子
Mat descriptions;
orb->compute(src, Keypoints, descriptions);
//绘制特征点
Mat imgAngle;
src.copyTo(imgAngle);
//绘制不含角度和大小的结果
drawKeypoints(src, Keypoints, src, Scalar(255, 255, 255));
//绘制含角度和大小的结果
drawKeypoints(src, Keypoints, imgAngle, Scalar(255, 255, 255), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
//显示结果
imshow("q", src);
imshow("w", imgAngle);
waitKey(0);
return 0;
}
上述代码运行结果如下:
二、特征点匹配
特征点匹配类:
Cv::DMatch:DMatch ( int _queryldx, int _trainldx, int _imgldx, float _distance)
queryIdx:第一个描述子集合中的索引
trainldx:第二个描述子集合中的索引
imgldx :训练描述子来自的图像索引
distance :两个描述符之间的距离
常用特征点匹配方法以及函数:
一对一:
void cv.DescriptorMatcher::match ( InputArray queryDescriptors,
InputArray trainDescriptors,
std::vector< DMatch > & matches, InputArray mask noArray()
const)
queryDescriptors:第一个描述子集合。
trainDescriptors:第二个描述子集合。
matches:两个集合描述子匹配结果。
mask:描述子匹配时的掩码矩阵,用于指定匹配哪些描述子。
一对多:
void cv::DescriptorMlatcher::knnMatch ( InputArray queryDescriptors, InputArray trainDescriptors,
std::vector< std:-vector< DMatch > > & matches, int k, InputArray mask = noArray(), bool compactResult = false const)
queryDescriptors:第一个描述子集合。
trainDescriptors:第二个描述子集合。
matches:描述子匹配结果。
k:每个查询描述子在训练描述子集合中寻找的最优匹配结果的数目
mask:描述子匹配时的掩码矩阵,用于指定匹配哪些描述子。
compactResult:输出匹配结果数目是否与查询描述子数目相同的选择标志。
void cv::DescriptorMatchere-radiusMatch ( InputArray queryDescriptors, InputArray trainDescriptors,
std:vector< std::vector< DMatch > >& matches, float maxDistance, InputArray mask = noArray(), bool compactResult = false, const)
queryDescriptors:第一个描述子集合。
trainDescriptors:第二个描述子集合。
matches:描述子匹配结果。
maxDistance:两个描述子之间满足匹配条件的距离阈值。
mask:描述子匹配时的掩码矩阵,用于指定匹配哪些描述子。
compactResult:输出匹配结果数目是否与查询描述子数目相同的选择标志。
暴力匹配:
cv::BFMatcher:;BFMatcher (normType = int NORM_L2, bool crossCheck = false)
normType:两个描述子之间距离的类型标志,可以选择的参数为NORM_Ll、NORM_L2、NORM_HAMMING和NORM_HAMMING2。
crossCheck:是否进行交叉检测的标志。
显示特征点匹配结果:
void cv:drawMatches ( InputArray img1, const std::vector< KeyPoint > & keypoints1, InputArray img2, const std::vector< KeyPoint > & keypoints2, const std::vector< DMatch > &matches1to2, InputOutputArray outImg, const Scalar & matchColor = scalar: :all(-1), const Scalar & singlePointColor = scalart :al1(-1), canst std::vector< char > & matchesMask = std : :vectorc char >(, DrawMatchesFlags flags = DrawNatchesFlags : :DEFAULT)
imgl:第一张图像。
matchColor:连接线和关键点的颜色。
keypointsl:第一张图像中的关键点。
singlcPointColor:没有匹配点的关键点的颜色。
img2:第二张图像。
matchesMask:匹配掩码
keypoints2:第二张图像中的关键点。
flags:绘制功能选择标志
matches1to2:第一张图像中关键点与第二张图像中关键点的匹配关系。
outImg:显示匹配结果的输出图像。
本节应用案例如下:
void orb_features(Mat &gray, vector<KeyPoint> &keypoints, Mat &descriptions)
{
Ptr<ORB> orb = ORB::create(1000, 1.2f);
orb->detect(gray, keypoints);
orb->compute(gray, keypoints, descriptions);
}
int main() {
//读取图片
Mat src = imread("2.jpg");
Mat src1= imread("2.jpg");
if (src.empty() && src1.empty())
{
printf("不能打开空图片");
return -1;
}
//计算ORB关键点
vector<KeyPoint> Keypoints1, Keypoints2;
Mat descriptions1, descriptions2;
//计算特征点
orb_features(src, Keypoints1, descriptions1);
orb_features(src1, Keypoints2, descriptions2);
//特征点匹配
//定义存放匹配结果的变量
vector<DMatch> matches;
//定义特征点匹配的类,使用汉明距离
BFMatcher matcher(NORM_HAMMING);
//开始匹配
matcher.match(descriptions1, descriptions2, matches);
//通过汉明距离选择匹配结果
double min_dist = 1000, max_dist = 0;
for (int i = 0; i < matches.size(); i++)
{
double dist = matches[i].distance;
if (dist < min_dist) min_dist = dist;
if (dist > min_dist) max_dist = dist;
}
//删除距离较大的点
vector<DMatch> good_matches;
for (int i = 0; i < matches.size(); i++)
{
if (matches[i].distance <= max(2 * min_dist, 20.0))
{
good_matches.push_back(matches[i]);
}
}
//绘制匹配结果
Mat outimg, outimg1;
drawMatches(src, Keypoints1, src1, Keypoints2, matches, outimg);
drawMatches(src, Keypoints1, src1, Keypoints2, good_matches, outimg1);
imshow("未筛选的结果", outimg);
imshow("筛选的结果", outimg1);
waitKey(0);
return 0;
}
三、RANSAC优化特征点匹配
RANSAC,随机采样一致性
1、随机取样,计算规律(特征点匹配中计算单应矩阵)
2、测试规律是否满足大多数数据
3、循环前两步
4、选取最佳规律,并输出满足数据的点
RANSAC优化特征点匹配结果的函数:
Mat cvcfindHomography ( InputArray srcPoints, InputArray dstPoints, int method = 0, ransacReprojThreshold =, double 3, OutputArray mask = naArray(), const int maxllters = 2000, const double confidence = 0.995)
srcPoints:原始图像中特征点的坐标。
dstPoints:目标图像中特征点的坐标
method:计算单应矩阵方法的标志。
ransacReprojThreshold:重投影的最大误差。
mask:掩码矩阵,使用RANSAC算法时表示满足单应矩阵的特征点。maxIters: RANSAC算法迭代的最大次数。
confidence:置信区间,取值范围0-1。
本节应用案例如下:
void match_min(vector<DMatch> matches, vector<DMatch> & good_matches)
{
//通过汉明距离选择匹配结果
double min_dist = 1000, max_dist = 0;
for (int i = 0; i < matches.size(); i++)
{
double dist = matches[i].distance;
if (dist < min_dist) min_dist = dist;
if (dist > min_dist) max_dist = dist;
}
for (int i = 0; i < matches.size(); i++)
{
if (matches[i].distance <= max(2 * min_dist, 20.0))
{
good_matches.push_back(matches[i]);
}
}
}
void ransac(vector<DMatch> matches, vector<KeyPoint> queryKeyPoint, vector<KeyPoint> trainKeyPoint, vector<DMatch> &matches_ransac)
{
//保存匹配点的坐标
vector<Point2f> srcPoints(matches.size()), dstPoints(matches.size());
//保存从关键点中提取的匹配点对的坐标
for (int i = 0; i < matches.size(); i++)
{
srcPoints[i] = queryKeyPoint[matches[i].queryIdx].pt;
dstPoints[i] = trainKeyPoint[matches[i].trainIdx].pt;
}
//匹配点对进行RANSAC过滤
vector<int> inliersMask(srcPoints.size());
findHomography(srcPoints, dstPoints, RANSAC, 5, inliersMask);
//保留RANSAC过滤后的匹配点对
for (int i = 0; i < inliersMask.size(); i++)
{
if (inliersMask[i])
{
matches_ransac.push_back(matches[i]);
}
}
}
int main() {
//读取图片
Mat src = imread("2.jpg");
Mat src1 = imread("2.jpg");
if (src.empty() && src1.empty())
{
printf("不能打开空图片");
return -1;
}
//计算ORB关键点
vector<KeyPoint> Keypoints1, Keypoints2;
Mat descriptions1, descriptions2;
//计算特征点
orb_features(src, Keypoints1, descriptions1);
orb_features(src1, Keypoints2, descriptions2);
//定义存放匹配结果的变量
vector<DMatch> matches, good_min, good_ransac;
//定义特征点匹配的类,使用汉明距离
BFMatcher matcher(NORM_HAMMING);
//开始匹配
matcher.match(descriptions1, descriptions2, matches);
//最小汉明距离
match_min(matches, good_min);
//用ransac匹配
ransac(good_min, Keypoints1, Keypoints2, good_ransac);
//绘制匹配结果
Mat outimg, outimg1, outimg2;
drawMatches(src, Keypoints1, src1, Keypoints2, matches, outimg);
drawMatches(src, Keypoints1, src1, Keypoints2, good_min, outimg1);
drawMatches(src, Keypoints1, src1, Keypoints2, good_ransac, outimg2);
imshow("未筛选的结果", outimg);
imshow("筛选的结果", outimg1);
imshow("ransac筛选的结果", outimg2);
waitKey(0);
return 0;
}