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所用的高斯核不一样。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我理解了您的要求。那么我们可以采用以下步骤来实现Harris角点检测算法: 1. 将彩色图像转化为灰度图像。 2. 计算x和y方向的图像梯度。 3. 计算每个像素点的M矩阵,其M矩阵的定义如下: $$ M=\begin{bmatrix} \sum_{x,y}w(x,y)I_x^2 & \sum_{x,y}w(x,y)I_xI_y \\ \sum_{x,y}w(x,y)I_xI_y & \sum_{x,y}w(x,y)I_y^2 \end{bmatrix} $$ 其,$w(x,y)$是一个窗口函数,$I_x$和$I_y$分别是$x$和$y$方向的梯度。 4. 计算每个像素点的Harris响应函数: $$ R=det(M)-k(trace(M))^2 $$ 其,$det(M)$和$trace(M)$分别是M矩阵的行列式和迹,$k$是一个常数,通常取0.04到0.06。 5. 对于每个像素点,比较其Harris响应函数和周围像素的Harris响应函数,如果其Harris响应函数最大,则将其标记为点。 下面是用Python代码实现Harris角点检测算法的示例,您可以参考一下: ```python import cv2 import numpy as np # 定义窗口大小和常数k win_size = 3 k = 0.04 # 读取图像并转化为灰度图像 img = cv2.imread('image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 计算x和y方向的梯度 dx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3) dy = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3) # 计算M矩阵 M11 = cv2.boxFilter(dx*dx, cv2.CV_64F, (win_size, win_size)) M22 = cv2.boxFilter(dy*dy, cv2.CV_64F, (win_size, win_size)) M12 = cv2.boxFilter(dx*dy, cv2.CV_64F, (win_size, win_size)) # 计算Harris响应函数 detM = M11 * M22 - M12 * M12 traceM = M11 + M22 R = detM - k * traceM * traceM # 标记点 corner_thresh = 0.01 * R.max() corners = np.zeros_like(R, dtype=np.uint8) corners[R > corner_thresh] = 255 # 显示结果 cv2.imshow('Harris Corner Detection', corners) cv2.waitKey(0) cv2.destroyAllWindows() ``` 这段代码使用了OpenCV库来实现图像处理功能。其,`cv2.Sobel`函数用于计算图像梯度,`cv2.boxFilter`函数用于计算M矩阵,`cv2.imshow`函数用于显示结果。您可以将上述代码保存为Python文件并运行,然后替换掉`image.jpg`为您所需检的图像文件名即可。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值