opencv_c++学习(二十六)

一、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 IpTp),则将中心点设置为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;

}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_52302919/article/details/130902659