Harris角点检测,及其Matlab和OpenCV实现

1、Harris角点检测算法实现步骤
(1)计算图像 I ( x , y ) I(x,y) I(x,y) X X X Y Y Y两个方向的梯度 I x , I y {{I}_{x}},{{I}_{y}} Ix,Iy I x = ∂ I ∂ x = I ⊗ [ − 1 0 1 ] {{I}_{x}}=\frac{\partial I}{\partial x}=I\otimes \left[ \begin{matrix} -1 & 0 & 1 \\\end{matrix} \right] Ix=xI=I[101] I y = ∂ I ∂ y = I ⊗ [ − 1 0 1 ] T {{I}_{y}}=\frac{\partial I}{\partial y}=I\otimes {{\left[ \begin{matrix} -1 & 0 & 1 \\\end{matrix} \right]}^{T}} Iy=yI=I[101]T(2)计算图像两个方向梯度的乘积;
I x 2 = I x I x , I y 2 = I y I y , I x y = I x I y I_{x}^{2}={{I}_{x}}{{I}_{x}},I_{y}^{2}={{I}_{y}}{{I}_{y}},{{I}_{xy}}={{I}_{x}}{{I}_{y}} Ix2=IxIx,Iy2=IyIy,Ixy=IxIy(3)使用高斯函数对 I x 2 , I y 2 , I x y I_{x}^{2},I_{y}^{2},{{I}_{xy}} Ix2,Iy2,Ixy进行高斯加权(取 σ = 1 \sigma =1 σ=1),生成矩阵 M M M的元素 A , B , C A,B,C A,B,C
A = g ( I x 2 ) = I x 2 ⊗ w A=g(I_{x}^{2})=I_{x}^{2}\otimes w A=g(Ix2)=Ix2w B = g ( I y 2 ) = I y 2 ⊗ w B=g(I_{y}^{2})=I_{y}^{2}\otimes w B=g(Iy2)=Iy2w C = g ( I x y ) = I x y ⊗ w C=g({{I}_{xy}})={{I}_{xy}}\otimes w C=g(Ixy)=Ixyw(5)在 3 × 3 3\times 3 3×3 5 × 5 5\times 5 5×5的邻域内进行非最大值抑制,局部最大值点记为图像中的角点。
2、Matlab实现

close all
clear
clc
%% 0、读取图像并进行灰度处理
img=imread('lena.png');
[m,n,c]=size(img);
if c>1
   img_gray=rgb2gray(img);
else
   img_gray=img;
end
%% 1、计算两个方向的梯度Ix,Iy
temp=zeros(m+2,n+2);
Ix=temp;
Iy=temp;
temp(2:m+1,2:n+1)=img_gray;
Ix(2:m+1,2:n+1)=temp(2:m+1,3:n+2)-temp(2:m+1,1:n);
Iy(2:m+1,2:n+1)=temp(3:m+2,2:n+1)-temp(1:m,2:n+1);
%% 2、计算图像两个方向的梯度乘积Ix2,Iy2,Ixy
Ix2=Ix(2:m+1,2:n+1).*Ix(2:m+1,2:n+1);
Iy2=Iy(2:m+1,2:n+1).*Iy(2:m+1,2:n+1);
Ixy=Ix(2:m+1,2:n+1).*Iy(2:m+1,2:n+1);
%% 3、使用高斯函数对Ix2,Iy2,Ixy进行高斯加权(sigma=1),生成矩阵M的元素A,B,C
h=fspecial('gaussian',[5,5],1);
A=filter2(h,Ix2);
B=filter2(h,Iy2);
C=filter2(h,Ixy);
%% 4、计算每个像素的Harris响应值R,并对小于阈值t的R置零
R=zeros(m,n);
k=0.06;
Rmax=0;
for i=1:m
   for j=1:n
      M=[A(i,j),C(i,j);C(i,j),B(i,j)];
      R(i,j)=det(M)-k*(trace(M))^2;
      if R(i,j)>Rmax
         Rmax=R(i,j); 
      end
   end
end
t=0.02*Rmax;
%% 5、非极大值抑制
s=5;    % 邻域大小
corner=zeros(m,n);
for i=(s+1)/2:m-(s+1)/2+1
    for j=(s+1)/2:n-(s+1)/2+1
       if R(i,j)==max(R(i-(s+1)/2+1:i+(s+1)/2-1,j-(s+1)/2+1:j+(s+1)/2-1),[],'all') && R(i,j)>t
          corner(i,j)=1;
       else
          corner(i,j)=0;
       end
    end
end
%% 角点显示
[x,y]=find(corner>0);   % 角点坐标
figure
imshow(img)
hold on
plot(y,x,'r+','MarkerSize',10);
hold off

结果如图所示:
在这里插入图片描述
3、OpenCV实现

// Harris角点检测
#include <iostream>
#include <opencv2\opencv.hpp>
using namespace std;
using namespace cv;

int main()
{
	Mat img = imread("lena.png");
	Mat img_gray;
	if (img.channels() > 1)
		cvtColor(img, img_gray, COLOR_BGR2GRAY);
	else
		img_gray = img;
	Size mn = size(img_gray);
	int n = mn.height, m = mn.width;
	float k = 0.06, Rmax = 0, t;
	img_gray.convertTo(img_gray, CV_32FC1);

	// 1、计算两个方向的梯度Ix,Iy
	Mat temp = Mat::zeros(mn + Size(2, 2), CV_32FC1);
	Mat R = Mat::zeros(mn, CV_32FC1), corner = R.clone();
	Mat Ix, Iy, Ix2, Iy2, Ixy, A, B, C, M;
	temp.copyTo(Ix);
	temp.copyTo(Iy);
	img_gray.copyTo(temp(Rect(1, 1, m, n)));
	Ix(Rect(1, 1, m, n)) = temp(Rect(2, 1, m, n)) - temp(Rect(0, 1, m, n));
	Iy(Rect(1, 1, m, n)) = temp(Rect(1, 2, m, n)) - temp(Rect(1, 0, m, n));

	// 2、计算图像两个方向的梯度乘积Ix2,Iy2,Ixy
	Ix2 = Ix(Rect(1, 1, m, n)).mul(Ix(Rect(1, 1, m, n)));
	Iy2 = Iy(Rect(1, 1, m, n)).mul(Iy(Rect(1, 1, m, n)));
	Ixy = Ix(Rect(1, 1, m, n)).mul(Iy(Rect(1, 1, m, n)));
	
	// 3、使用高斯函数对Ix2,Iy2,Ixy进行高斯加权(sigma=1),生成矩阵M的元素A,B,C
	GaussianBlur(Ix2, A, Size(5, 5), 1, 0);
	GaussianBlur(Iy2, B, Size(5, 5), 1, 0);
	GaussianBlur(Ixy, C, Size(5, 5), 1, 0);

	// 4、计算每个像素的Harris响应值R,并对小于阈值t的R置零
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			M = (Mat_<float>(2, 2) << A.at<float>(i, j), C.at<float>(i, j), C.at<float>(i, j), B.at<float>(i, j));
			R.at<float>(i, j) = determinant(M) - k * (trace(M).val[0]) * (trace(M).val[0]);
			if (R.at<float>(i, j) > Rmax)
				Rmax = R.at<float>(i, j);
		}
	}
	t = 0.02*Rmax;

	// 5、 非极大值抑制
	int s = 5;	// 邻域大小
	for (int i = (s + 1) / 2 - 1; i < n - (s + 1) / 2 + 1; i++)
	{
		for (int j = (s + 1) / 2 - 1; j < m - (s + 1) / 2 + 1; j++)
		{
			double Rm;
			minMaxIdx(R(Rect(j - (s - 1) / 2, i - (s - 1) / 2, s, s)), NULL, &Rm, NULL, NULL);
			if (fabsf(R.at<float>(i, j) - (float)Rm) < 1e-10 && (R.at<float>(i, j) > t))
			{
				corner.at<float>(i, j) = 255;
				drawMarker(img, Point(j, i), Scalar(0, 0, 255), MARKER_CROSS, 10, 1);
			}
			else
				corner.at<float>(i, j) = 0;
		}
	}
	imshow("img", img);
	waitKey(0);
	return 0;
}

结果如图所示:
在这里插入图片描述
注意:(1)Matlab中图像坐标系 x x x轴竖直向下, y y y轴水平向右,OpenCV中图像坐标系 x x x轴水平向右, y y y轴水平向右竖直向下;(2)Matlab和OpenCV中的Harris角点检测算法有些许出入,“猜想”是因为:在高斯加权时,Matlab和OpenCV所用的高斯核不一样。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值