• 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)
    
    • 1
    • 2

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    上述代码运行结果如下:
    在这里插入图片描述

    二、特征点匹配

    特征点匹配类:

    Cv::DMatch:DMatch ( int _queryldx, int _trainldx, int _imgldx, float _distance)
    
    • 1

    queryIdx:第一个描述子集合中的索引
    trainldx:第二个描述子集合中的索引
    imgldx :训练描述子来自的图像索引
    distance :两个描述符之间的距离
    常用特征点匹配方法以及函数:
    一对一:

    void cv.DescriptorMatcher::match ( InputArray queryDescriptors,
    InputArray trainDescriptors,
    std::vector< DMatch > & matches, InputArray mask noArray()
    const)
    
    • 1
    • 2
    • 3
    • 4

    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)
    
    • 1
    • 2

    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)
    
    • 1
    • 2

    queryDescriptors:第一个描述子集合。
    trainDescriptors:第二个描述子集合。
    matches:描述子匹配结果。
    maxDistance:两个描述子之间满足匹配条件的距离阈值。
    mask:描述子匹配时的掩码矩阵,用于指定匹配哪些描述子。
    compactResult:输出匹配结果数目是否与查询描述子数目相同的选择标志。
    暴力匹配:

    cv::BFMatcher:;BFMatcher (normType = int NORM_L2, bool crossCheck = false)
    
    • 1

    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)
    
    • 1

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    在这里插入图片描述

    三、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)
    
    • 1

    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;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94

    在这里插入图片描述

  • 相关阅读:
    linux学习总结
    Kafka学习笔记之进阶篇
    语音控制系统的安全挑战与防御策略(上)
    2022年12月英语六级预测范文:情景作文-流行文化
    写给正在互联网经历孤独和迷茫的你
    为什么拼多多总能给市场带来惊喜?
    QMenu的基本使用:实现右键弹出菜单栏
    如何在Docker中安装MySQL数据库
    PostgreSQL的学习心得和知识总结(八十五)|深入理解PostgreSQL数据库开源扩展pg_backtrace的使用场景和实现原理
    片上网络(2)拓扑结构
  • 原文地址:https://blog.csdn.net/qq_52302919/article/details/130902659