1.Harris角点
1.1基本定义
首先,什么是角点,角点是指一个边缘轮廓的一角。角点可以在一个物体的边缘处,但是边缘不同于角点,简单来说角点就是同时是边缘和角的点。
1.2判断依据
计算机完成角点检测是通过一个小窗口逐步扫描过去来完成的,在移动过程中的灰度的变换则作为判断角点的依据:
①.当检测窗口移动时,灰度几乎没有发生变化 ->认为是“平整地带”;
②.当检测窗口移动时,灰度只在一个方向上发生突变 ->认为是“边缘地带”;
③.当检测窗口移动时,灰度在各个方向上均发生突变 ->认为是“角点地带”;
1.3数学推导
E(u,v)具体含义我也不知道,可以理解为沿着某个方向的变化大小的期望,配合之前的解释,沿着多个方向若灰度变化都很大则定义为角点。
化成矩阵的形式后记 M2 = [A, C; C, B]
A 是 图像在x方向上的二次偏导数;
B 是 图像在y方向上的二次偏导数;
C 是 图像在xy方向上的梯度乘积;
为了求A , C ,B我们需要首先计算两个方向上的梯度;梯度的计算表可以用sobel算子等相关算子进行计算。
这里需要注意的一点是,为了将中心像素对周围像素的影像考虑进来,对于求得的M2矩阵进行高斯滤波可以改善,最终得到M矩阵。
对于M矩阵特征值的判断来得出结论如下,
图像中的直线:一个特征值大,另一个特征值小,λ1≫λ2或λ2≫λ1。自相关函数值在某一方向上大,在其他方向上小。
图像中的平面:两个特征值都小,且近似相等;自相关函数数值在各个方向上都小。
图像中的角点:两个特征值都大,且近似相等,自相关函数在所有方向都增大。
1.4计算方法
得到的矩阵M并不需要直接去判断他的特征值,harris算法找到了一个更为简单的判断方式,那就是R; R = detM - k(trace(M))^2
其中:
det M = λ1λ2=A * C−B^2;
trace M = λ2 + λ2 = A + C;
k 取0.04-0.06;
角点处R为大数值正数;边缘处R为大数值复数;平坦区处R绝对值是小数值。
1.5 算法实现步骤
1.利用Soble或其他方式计算出XY方向的梯度值
2.计算出二阶偏导与梯度乘积
3.利用高斯函数对M矩阵进行滤波
4.计算局部特征结果矩阵M的特征值和响应函数R = det(M)-k(trace(M))^2 (0.04<=k<=0.06)
5.将计算出响应函数的值C进行非极大值抑制,滤除一些不是角点的点,同时要满足大于设定的阈值
2程序清单
2.1内部库函数学习
①、滑块拖动函数
createTrackbar("Threshold", output_title, &thresh, max_count, Harris_Demo);
Harris_Demo(0,0);
参数1:滑块名称;
参数2:滑块所在的窗口名称;
参数3:滑块改变的变量名称,注意要加 ’&‘,同样表示初始值大小;
参数4:滑块终点数字大小;
参数5:滑块操作的子函数名称,且下一行需要调用这个函数;
②、harris角点检测函数
cornerHarris(img_gray, dst, blockSize, ksize, k, BORDER_DEFAULT);
参数1:原始图像,必须是灰度;
参数2:操作后返回的图像;
参数3:blockSize特征值计算矩阵的维数 一般是2;
参数4:ksize平移扫过图像的矩阵块;
参数5:表示对图像边缘的处理,这里直接BORDER_DEFAULT表示默认;
③、像素大小标准化函数
//此处只使用了最大值最小值的标准化模式
normalize(dst, norm_dst, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
参数1:原始图像;
参数2:操作后返回的图像;
参数3:double 类参数1 表示标准化的最小值;
参数4:double 类参数2 表示标准化的最大值;
参数5:标准化方式,NORM_MINMAX表示最大最小值标准化;
参数6:32位float类型数据;
参数7:我也不知道 Mat();
④、转换图像像素类型
//使用线性变换转换输入数组元素成8位无符号整型
convertScaleAbs(norm_dst, normScaleDst);;
参数1:原始图像;
参数2:操作后返回的图像;
⑤、画出一个小圆圈,在给定位置
circle(resultImg, Point(col, row), 2, Scalar(0, 0, 255), 2, 8, 0);
参数1:需要画圈的操作图像;
参数2:画圈的操作位置;
参数3:圆圈半径;
参数4:画出圆圈的颜色Scalar(B,G, R)颜色配比;
参数5:内部填充,越大涂的越多,不要大于参数3;
参数6:按照默认;
参数7:按照默认;
⑥、指针操作遍历整个图像
for (int row = 0; row < resultImg.rows; row++) {
//定义每一行的指针
uchar* currentRow = normScaleDst.ptr(row);//表示了行指针的开始
for (int col = 0; col < resultImg.cols; col++) {
int value = (int)*currentRow; //第一次默认指针的第一列
...
...
...
currentRow++; //+1之后向下一列进发
}
}
2.2整体程序
#include
#include
#include
using namespace std;
using namespace cv;
int thresh = 130;
int max_count = 255;
Mat img, img_gray;
const char* output_title = "Harris Corner Dectction Result";
void Harris_Demo(int, void *);
int main(int argv, char** argc) {
img = imread("E:/OpenCV/image/home.jpg");
if (img.empty()) {
printf("colud not load image...");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", img);
//以上是图像处理的标准开头
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
cvtColor(img, img_gray, CV_BGR2GRAY);
createTrackbar("Threshold", output_title, &thresh, max_count, Harris_Demo);
Harris_Demo(0, 0);
waitKey(0);
return 0;
}
void Harris_Demo(int, void *) {
Mat dst, norm_dst, normScaleDst;
dst = Mat::zeros(img_gray.size(), CV_32FC1);
//harris角点核心函数
int blockSize = 2;
int ksize = 3;
int k = 0.04;
cornerHarris(img_gray, dst, blockSize, ksize, k, BORDER_DEFAULT);
//上述输出的取值范围并不是0-255 需要按照最大最小值进行归一化
normalize(dst, norm_dst, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
convertScaleAbs(norm_dst, normScaleDst);
Mat resultImg = img.clone();
//用彩色来显示
for (int row = 0; row < resultImg.rows; row++) {
//定义每一行的指针
uchar* currentRow = normScaleDst.ptr(row);
for (int col = 0; col < resultImg.cols; col++) {
int value = (int)*currentRow;
if (value > thresh) {
circle(resultImg, Point(col, row), 2, Scalar(0, 0, 255), 2, 8, 0);
}
currentRow++;
}
}
imshow(output_title, resultImg);
}
纯属个人学习总结 ,有问题请指正,谢谢