Harris角点检测
如果某一点在任意方向的一个微小变动都会引起灰度很大的变化,那么我们就把它称之为角点。
角点作为图像上的特征点,包含有重要的信息,在图像融合和目标跟踪及三维重建中有重要的应用价值。它们在图像中可以轻易地定位,同时,在人造物体场景,比如门、窗、桌等处也随处可见。因为角点位于两条边缘的交点处,代表了两个边缘变化的方向上的点,所以它们是可以精确定位的二维特征,甚至可以达到亚像素的精度。又由于其图像梯度有很高的变化,这种变化是可以用来帮助检测角点的。需要注意的是,角点与位于相同强度区域上的点不同,与物体轮廓上的点也不同,因为轮廓点难以在相同的其他物体上精确定位。
harris角点检测是一种直接基于灰度图像的角点提取算法,稳定性高,尤其对L型角点检测精度高。但由于采用了高斯滤波,运算速度相对较慢,角点信息有丢失和位置偏移的现象,而且角点提取有聚簇现象。
void cornerHarris(InputArray src,outputArray dst, int blockSize,int ksize,double k, intborderType=BORDER_DEFAULT )
//第一个参数:输入图像,即源图像且须为单通道8位或者浮点型图像;第二个参数:用于存放 Harris角点检测的输出结果,和源图片有一样的尺寸和类型;第三个参数:表示邻域的大小;第四个参数:表示Sobel()算子的孔径大小;第五个参数:Harris参数;第六个参数:图像像素的边界模式。
#include <opencv2/opencv.hpp>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
using namespace std;
#define WINDOW_NAME1 "【程序窗口1】" //为窗口标题定义的宏
#define WINDOW_NAME2 "【程序窗口2】" //为窗口标题定义的宏
Mat g_srcImage, g_srcImage1, g_grayImage;
int thresh = 30; //当前阈值
int max_thresh = 175; //最大阈值
void on_CornerHarris(int, void*);//回调函数
int main(int argc, char** argv)
{
//【1】载入原始图并进行克隆保存
g_srcImage = imread("1.jpg", 1);
if (!g_srcImage.data) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false; }
imshow("原始图", g_srcImage);
g_srcImage1 = g_srcImage.clone();
//【2】存留一张灰度图
cvtColor(g_srcImage1, g_grayImage, COLOR_BGR2GRAY);
//【3】创建窗口和滚动条
namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
createTrackbar("阈值: ", WINDOW_NAME1, &thresh, max_thresh, on_CornerHarris);
//【4】调用一次回调函数,进行初始化
on_CornerHarris(0, 0);
waitKey(0);
return(0);
}
//-----------------------------------【on_HoughLines( )函数】--------------------------------
// 描述:回调函数
//----------------------------------------------------------------------------------------------
void on_CornerHarris(int, void*)
{
//---------------------------【1】定义一些局部变量-----------------------------
Mat dstImage;//目标图
Mat normImage;//归一化后的图
Mat scaledImage;//线性变换后的八位无符号整型的图
//---------------------------【2】初始化---------------------------------------
//置零当前需要显示的两幅图,即清除上一次调用此函数时他们的值
dstImage = Mat::zeros(g_srcImage.size(), CV_32FC1);
g_srcImage1 = g_srcImage.clone();
//---------------------------【3】正式检测-------------------------------------
//进行角点检测
cornerHarris(g_grayImage, dstImage, 2, 3, 0.04, BORDER_DEFAULT);
// 归一化与转换
normalize(dstImage, normImage, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
convertScaleAbs(normImage, scaledImage);//将归一化后的图线性变换成8位无符号整型
//---------------------------【4】进行绘制-------------------------------------
// 将检测到的,且符合阈值条件的角点绘制出来
for (int j = 0; j < normImage.rows; j++)
{
for (int i = 0; i < normImage.cols; i++)
{
if ((int)normImage.at<float>(j, i) > thresh + 80)
{
circle(g_srcImage1, Point(i, j), 5, Scalar(10, 10, 255), 2, 8, 0);
circle(scaledImage, Point(i, j), 5, Scalar(0, 10, 255), 2, 8, 0);
}
}
}
//---------------------------【4】显示最终效果---------------------------------
imshow(WINDOW_NAME1, g_srcImage1);
imshow(WINDOW_NAME2, scaledImage);
}
Shi-Tomasi角点检测
void goodFeaturesToTrack (InputArray image,outputArray corners,int maxCorners,double qualityLevel,double minDistance,InputArray mask=noArray () ,int blockSize=3,bool useHarrisDetector=false,double k=0.04 )
//第一个参数:输入图像,须为8位或浮点型 32位单通道图像;第二个参数:检测到的角点的输出向量;第三个参数:角点的最大数量;第四个参数:角点检测可接受的最小特征值;其实实际用于过滤角点的最小特征值是qualityLevel 与图像中最大特征值的乘积。所以 qualityLevel通常不会超过1(常用的值为0.10或者0.01)。而检测完所有的角点后,还要进一步剔除掉一些距离较近的角点;第五个参数:double类型的minDistance,角点之间的最小距离,此参数用于保证返回的角点之间的距离不小于minDistance个像素。
//第六个参数:InputArray类型的mask,可选参数,表示感兴趣区域,有默认值 noArray();第七个参数:int类型的 blockSize,有默认值3,是计算导数自相关矩阵时指定的邻域范围;第八个参数:bool类型的useHarrisDetector,默认值 false,指示是否使用Harris角点检测;第九个参数:double类型的k,有默认值0.04,为用于设置Hessian自相关矩阵行列式的相对权重的权重系数。
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
#define WINDOW_NAME "【Shi-Tomasi角点检测】" //为窗口标题定义的宏
Mat g_srcImage, g_grayImage;
int g_maxCornerNumber = 33;
int g_maxTrackbarNumber = 500;
RNG g_rng(12345);//初始化随机数生成器
//-----------------------------【on_GoodFeaturesToTrack( )函数】----------------------------
// 描述:响应滑动条移动消息的回调函数
//----------------------------------------------------------------------------------------------
void on_GoodFeaturesToTrack(int, void*)
{
//【1】对变量小于等于1时的处理
if (g_maxCornerNumber <= 1) { g_maxCornerNumber = 1; }
//【2】Shi-Tomasi算法(goodFeaturesToTrack函数)的参数准备
vector<Point2f> corners;
double qualityLevel = 0.01;//角点检测可接受的最小特征值
double minDistance = 10;//角点之间的最小距离
int blockSize = 3;//计算导数自相关矩阵时指定的邻域范围
double k = 0.04;//权重系数
Mat copy = g_srcImage.clone(); //复制源图像到一个临时变量中,作为感兴趣区域
//【3】进行Shi-Tomasi角点检测
goodFeaturesToTrack(g_grayImage,//输入图像
corners,//检测到的角点的输出向量
g_maxCornerNumber,//角点的最大数量
qualityLevel,//角点检测可接受的最小特征值
minDistance,//角点之间的最小距离
Mat(),//感兴趣区域
blockSize,//计算导数自相关矩阵时指定的邻域范围
false,//不使用Harris角点检测
k);//权重系数
//【4】输出文字信息
cout << "\t>此次检测到的角点数量为:" << corners.size() << endl;
//【5】绘制检测到的角点
int r = 4;
for (int i = 0; i < corners.size(); i++)
{
//以随机的颜色绘制出角点
circle(copy, corners[i], r, Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255),
g_rng.uniform(0, 255)), -1, 8, 0);
}
//【6】显示(更新)窗口
imshow(WINDOW_NAME, copy);
}
int main()
{
//【1】载入源图像并将其转换为灰度图
g_srcImage = imread("1.jpg", 1);
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
//【2】创建窗口和滑动条,并进行显示和回调函数初始化
namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE);
createTrackbar("最大角点数", WINDOW_NAME, &g_maxCornerNumber, g_maxTrackbarNumber, on_GoodFeaturesToTrack);
imshow(WINDOW_NAME, g_srcImage);
on_GoodFeaturesToTrack(0, 0);
waitKey(0);
return(0);
}
亚像素级角点检测
void cornerSubPix(InputArray image,InputoutputArray corners,size winsize,size zerozone,TermCriteria criteria)
//第一个参数:输入图像;第二个参数:提供输入角点的初始坐标和精确的输出坐标;第三个参数:搜索窗口的一半尺寸;第四个参数:表示死区的一半尺寸,而死区为不对搜索区的中央位置做求和运算的区域,用来避免自相关矩阵出现的某些可能的奇异性,值为(-1,-1)表示没有死区;
//第五个参数:求角点的迭代过程的终止条件;即角点位置的确定,要么迭代数大于某个设定值,或者是精确懂达到某个设定值,criteria可以是最大迭代数目,或者是设定的精确度,也可以是它们的组合。
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
#define WINDOW_NAME "【亚像素级角点检测】" //为窗口标题定义的宏
Mat g_srcImage, g_grayImage;
int g_maxCornerNumber = 33;
int g_maxTrackbarNumber = 500;
RNG g_rng(12345);//初始化随机数生成器
void on_GoodFeaturesToTrack(int, void*)
{
//【1】对变量小于等于1时的处理
if (g_maxCornerNumber <= 1) { g_maxCornerNumber = 1; }
//【2】Shi-Tomasi算法(goodFeaturesToTrack函数)的参数准备
vector<Point2f> corners;
double qualityLevel = 0.01;//角点检测可接受的最小特征值
double minDistance = 10;//角点之间的最小距离
int blockSize = 3;//计算导数自相关矩阵时指定的邻域范围
double k = 0.04;//权重系数
Mat copy = g_srcImage.clone(); //复制源图像到一个临时变量中,作为感兴趣区域
//【3】进行Shi-Tomasi角点检测
goodFeaturesToTrack(g_grayImage,//输入图像
corners,//检测到的角点的输出向量
g_maxCornerNumber,//角点的最大数量
qualityLevel,//角点检测可接受的最小特征值
minDistance,//角点之间的最小距离
Mat(),//感兴趣区域
blockSize,//计算导数自相关矩阵时指定的邻域范围
false,//不使用Harris角点检测
k);//权重系数
//【4】输出文字信息
cout << "\n\t>-------------此次检测到的角点数量为:" << corners.size() << endl;
//【5】绘制检测到的角点
int r = 4;
for (unsigned int i = 0; i < corners.size(); i++)
{
//以随机的颜色绘制出角点
circle(copy, corners[i], r, Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255),
g_rng.uniform(0, 255)), -1, 8, 0);
}
//【6】显示(更新)窗口
imshow(WINDOW_NAME, copy);
//【7】亚像素角点检测的参数设置
Size winSize = Size(5, 5);
Size zeroZone = Size(-1, -1);
TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 40, 0.001);
//【8】计算出亚像素角点位置
cornerSubPix(g_grayImage, corners, winSize, zeroZone, criteria);
//【9】输出角点信息
for (int i = 0; i < corners.size(); i++)
{
cout << " \t>>精确角点坐标[" << i << "] (" << corners[i].x << "," << corners[i].y << ")" << endl;
}
}
int main()
{
//【1】载入源图像并将其转换为灰度图
g_srcImage = imread("1.jpg", 1);
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
//【2】创建窗口和滑动条,并进行显示和回调函数初始化
namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE);
createTrackbar("最大角点数", WINDOW_NAME, &g_maxCornerNumber, g_maxTrackbarNumber, on_GoodFeaturesToTrack);
imshow(WINDOW_NAME, g_srcImage);
on_GoodFeaturesToTrack(0, 0);
waitKey(0);
return(0);
}