OpenCV c++ 角点检测

1、显示关键点

关键点:图像中含有特殊信息的像素点,主要含有像素点位置、角度等信息。

一次性用空心圆绘制所有关键点:

drawKeypoints(img, keypoints, img, Scalar(0, 0, 0));

(输入图像,关键点向量 KeuyPoint类型,输出图像,关键点颜色)

class KeyPoint{

float angle; //关键点的角度

int class_id; //关键点的分类号

int octave; //特征点来源

Point2f pt; //*关键点的坐标*

float response;//最强关键点的响应,可用于进一步分类和二次采样

float size; //关键点邻域的直径

}


#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>


using namespace cv;
using namespace std;




int main(int argc, char** argv) {
	//QuickDemo qd;
	//qd.myFilter_demo(src);
	//system("color F0");
	Mat img = imread("D:/images/dog.png",IMREAD_COLOR);
	if (img.empty()) {
		cout << "请输入正确的图像文件" << endl;
		return -1;
	}
	Mat gray;
	cvtColor(img, gray, COLOR_BGR2GRAY);
	//生成关键点
	vector<KeyPoint> keypoints;
	RNG rng(10086);
	for (int i = 0; i < 100; i++) {
		float pty = rng.uniform(0, img.rows - 1);
		float ptx = rng.uniform(0, img.cols - 1);
		KeyPoint keypoint;		//对KeyPoint类进行赋值
		keypoint.pt.x = ptx;
		keypoint.pt.y = pty;
		keypoints.push_back(keypoint);		//保存到关键点向量中
	}
	//绘制关键点
	drawKeypoints(img, keypoints, img, Scalar(0, 0, 0));
	drawKeypoints(gray, keypoints, gray, Scalar(255, 255, 255));
	imshow("img", img);
	imshow("gray", gray);
	waitKey(0);
	//destroyAllWindows();
	return 0;
}

2、Harris角点检测

角点/特征点:从图像中提取能够表示图像特性或者局部特性的像素点,如灰度梯度最大值对应的像素点、两条直线或者曲线的交点、一阶梯度的导数最大值和梯度方向变化率最大的像素点、一阶导数值最大但是二阶导数值为0的点等。特征点是关键点和描述子的组合。

定义

角点/特征点:从图像中提取能够表示图像特性或者局部特性的像素点,如灰度梯度最大值对应的像素点、两条直线或者曲线的交点、一阶梯度的导数最大值和梯度方向变化率最大的像素点、一阶导数值最大但是二阶导数值为0的点等

特征点是关键点和描述子的组合。

Harris角点:像素值的局部最大峰值

首先,我们选择一个合适大小的像素框,如途中金黄色区域。我们试图通过对框中像素值的变化去探究是否为角点。

第一个 flat,我们在上下左右以及对角线移动像素框时,会发现框中的值几乎没有变化,全部为黑色值0;

第二个 edge,我们在上下移动时,发现像素框中值没有变化,但是左右移动时以及对角线移动时会发生变化;

第三个 corner,我们不论上下移动还是左右移动还是对角线移动,都会发生变化,所以其为角点。

nerHarris(gray, harris, blockSize, apertureSize, 0.04);

该函数用于计算角点Harris评价系数R,通过对系数大小的比较,确定该点是否为Harris角点。

R较大时,说明两个特征向量相似,则该点为角点;R<0时,说明两个特征向量相差较大,则该点位于直线上;当|R|较小时,说明两个特征值较小,则该点位于平面。

(输入单通道灰度图,输出的R矩阵,邻域大小,提取信息的Sobel算子半径,权重系数k,像素外推法标志)

由于该函数的结果R,取值范围较广且有正有负,通常需要进行normalize()归一化到指定区域后,再通过阈值判断该像素点是否是Harris角点。阈值根据实际情况而定。


#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>


using namespace cv;
using namespace std;




int main(int argc, char** argv) {
	//QuickDemo qd;
	//qd.myFilter_demo(src);
	//system("color F0");
	Mat img = imread("D:/images/dog.png",IMREAD_COLOR);
	if (img.empty()) {
		cout << "请输入正确的图像文件" << endl;
		return -1;
	}
	Mat gray;
	cvtColor(img, gray, COLOR_BGR2GRAY);
	//计算Harris评价系数
	Mat harris;
	int blockSize = 2;		//邻域半径
	int apertureSize = 3;
	cornerHarris(gray, harris, blockSize, apertureSize, 0.04);
	//归一化以便进行数值比较和结果显示
	Mat harrisn;
	normalize(harris, harrisn,0,255,NORM_MINMAX);
	//将图像数据类型变成CV_8U
	convertScaleAbs(harrisn, harrisn);

	//寻找Harris角点
	vector<KeyPoint> keypoints;
	for (int row = 0; row < harrisn.rows; row++) {
		for (int col = 0; col < harrisn.cols; col++) {
			int R = harrisn.at<uchar>(row, col);
			if (R > 125) {
				//将角点存入KeyPoint中
				KeyPoint keypoint;
				keypoint.pt.y = row;
				keypoint.pt.x = col;
				keypoints.push_back(keypoint);
			}
		}

	}



	drawKeypoints(img, keypoints, img,Scalar(255,255,255));
	imshow("Harris角点", img);
	imshow("系数矩阵", harrisn);
	waitKey(0);
	//destroyAllWindows();
	return 0;
}

	




引用:【计算机视觉】哈里斯角点检测 Harris Corner Detection-CSDN博客

 

3、Shi-Tomas角点检测

Harris角点评价系数是两个特征向量的组合,因此Harris角点评价系数不能完全的概况两个特征向量之间的大小关系。

因此Shi和Tomas对Harris角点的判定指标进行调整,将特征向量的最小值作为角点的评价系数。当R大于某一阈值时,则将该点认定为角点。

goodFeaturesToTrack(gray, corners, maxCorners, quality_level, minDistance, Mat(), 3, false);

与Harris角点检测函数相比,该函数的阈值与最佳角点相对应,避免了绝对阈值在不同图像中效果不理想的情况。且该函数可直接输出角点坐标,无需根据输出结果再次判断是否为角点。

(输入图像,检测到的角点,寻找角点数目的最大值,角点阈值与最佳角点的关系,两角点间的最小欧氏距离,检测角点的掩码矩阵,计算梯度协方差矩阵的尺寸,是否使用Harris角点检测的标志)


#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>


using namespace cv;
using namespace std;




int main(int argc, char** argv) {
	//QuickDemo qd;
	//qd.myFilter_demo(src);
	//system("color F0");
	Mat img = imread("D:/images/dog.png",IMREAD_COLOR);
	if (img.empty()) {
		cout << "请输入正确的图像文件" << endl;
		return -1;
	}
	Mat img2;
	img.copyTo(img2);
	Mat gray;
	cvtColor(img, gray, COLOR_BGR2GRAY);

	//提取角点
	int maxCorners = 100;		//检测角点数目
	double quality_level = 0.01;		//质量等级,或者是指阈值与最佳角点的比例关系
	double minDistance = 0.04;		//两个角点之间的最小欧氏距离
	vector<Point2f> corners;
	goodFeaturesToTrack(gray, corners, maxCorners, quality_level, minDistance, Mat(), 3, false);

	//绘制角点
	vector<KeyPoint> keypoints;
	RNG rng(10086);
	for (int i = 0; i < corners.size(); i++) {
		//第一种方式绘制角点
		int b = rng.uniform(0, 256);
		int g = rng.uniform(0, 256);
		int r = rng.uniform(0, 256);
		circle(img, corners[i], 5, Scalar(b, g, r), 2, 8, 0);
		//将角点存放在KeyPoint类中
		KeyPoint keypoint;
		keypoint.pt = corners[i];
		keypoints.push_back(keypoint);

	}
	
	drawKeypoints(img2, keypoints, img2,Scalar(255,255,255));
	imshow("用circle()绘制角点的结果", img);
	imshow("用绘制关键点函数绘制角点的结果", img2);
	waitKey(0);
	//destroyAllWindows();
	return 0;
}

	




使用circle()绘制角点:可以自由调整大小、可单独给每一个圆形指定颜色

使用drawKeypoints()绘制角点:实现方式简单,不用反复调用,但圆形大小固定,不易于辨识

4、亚像素级别角点检测


#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>


using namespace cv;
using namespace std;




int main(int argc, char** argv) {
	//QuickDemo qd;
	//qd.myFilter_demo(src);
	system("color F0");
	Mat img = imread("D:/images/dog.png",IMREAD_COLOR);
	if (img.empty()) {
		cout << "请输入正确的图像文件" << endl;
		return -1;
	}
	Mat img2;
	img.copyTo(img2);
	Mat gray;
	cvtColor(img, gray, COLOR_BGR2GRAY);

	//提取角点
	int maxCorners = 100;		//检测角点数目
	double quality_level = 0.01;		//质量等级,或者是指阈值与最佳角点的比例关系
	double minDistance = 0.04;		//两个角点之间的最小欧氏距离
	vector<Point2f> corners;
	goodFeaturesToTrack(gray, corners, maxCorners, quality_level, minDistance, Mat(), 3, false);

	//计算亚像素级别角点坐标
	vector<Point2f> cornerSub = corners;		//角点备份,防止被函数修改
	Size winsize = Size(5, 5);
	Size zerosize = Size(-1, -1);
	TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 40, 0.001);
	cornerSubPix(gray, cornerSub, winsize, zerosize, criteria);
	//输出初始坐标和精细坐标
	for (size_t i = 0; i < corners.size(); i++) {
		string str = to_string(i);
		str = "第" + str + "个角点初始坐标:";
		cout << str << corners[i] << "    精细后坐标:" << cornerSub[i] << endl;
	}
	//绘制角点
	vector<KeyPoint> keypoints;
	RNG rng(10086);
	for (int i = 0; i < corners.size(); i++) {
		//第一种方式绘制角点
		int b = rng.uniform(0, 256);
		int g = rng.uniform(0, 256);
		int r = rng.uniform(0, 256);
		circle(img, corners[i], 5, Scalar(b, g, r), 2, 8, 0);
		//将角点存放在KeyPoint类中
		KeyPoint keypoint;
		keypoint.pt = corners[i];
		keypoints.push_back(keypoint);

	}
	/*
	drawKeypoints(img2, keypoints, img2,Scalar(255,255,255));
	imshow("用circle()绘制角点的结果", img);
	imshow("用绘制关键点函数绘制角点的结果", img2);
	waitKey(0);
	//destroyAllWindows();*/
	return 0;
}

	




 

  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值