Harris角点检测原理及C++实现

(1)角点检测的核心思想:
  使用一个固定窗口在图像上进行任意方向上的滑动,比较滑动前与滑动后两种情况,窗口中的像素灰度变化程度,如果存在任意方向上的滑动,都有着较大灰度变化,那么我们可以认为该窗口中存在角点。
(2)灰度变化描述
  当窗口发生[u,v]移动时,那么滑动前与滑动后对应的窗口中的像素点灰度变化描述如下:
  E(u,v)=∑(x,y)€Ww(x,y)[I(x+u,y+v)−I(x,y)]2
参数解释:

[u,v]是窗口W的偏移量;
(x,y)是窗口W所对应的像素坐标位置,窗口有多大,就有多少个位置;
I(x,y)是像素坐标位置(x,y)的图像灰度值;
I(x+u,y+v)是像素坐标位置(x+u,y+v)的图像灰度值;
w(x,y)是窗口函数,最简单情形就是窗口W内的所有像素所对应的w权重系数均为1.但有时候,我们会将w(x,y)函数设置为以窗口W中心为原点的二元正太分布。如果窗口W中心点是角点时,移动前与移动后,
该点在灰度变化贡献最大;而离窗口W中心(角点)较远的点,这些点的灰度变化几近平缓,这些点的权重系数,可以设定小值,以示该点对灰度变化贡献较小,那么我们自然而然想到使用二元高斯函数来表示窗口函数;

上述是Moravec角点检测算法,该算法是基于相邻像素之间的欧氏距离度量灰度变化量,缺点:不具有旋转不变性(同一张图片旋转一定角度后,检测到的角点不同),给实际工程应用带来不便。

针对上述问题:Harris运用泰勒公式做出改进,说不明白,上图如下:

Harris角点检测原理及C++实现

至于算法的推导,可参考:https://www.cnblogs.com/zyly/p/9508131.html#_label5_0

算法实现:

main.cpp

#include "iostream"
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "my_harris.h"
using namespace cv;
using namespace std;

int main()
{
    my_Harris Harris;
    Mat img = imread("D:\qtproject\img\4.jpg");
    //imshow("img",img);
    //waitKey(0);
    /*0.图像预处理之灰度化RGB2GRAY*/
    int cols = img.cols;
    int rows =  img.rows;
    Mat img_gray = Mat(rows,cols,CV_8UC1,Scalar(0));
    Harris.RGB2GRAY(img,img_gray);
    /*1.计算图像在x,y方向的梯度*/
    Mat gx_img = Mat(rows,cols,CV_8UC1,Scalar(0));
    Mat gy_img = Mat(rows,cols,CV_8UC1,Scalar(0));
    Harris.IMG_GRAD(img_gray,gx_img,gy_img);

    /*2.计算图像在两个方向梯度的乘积*/
    Mat gx_p = Mat(rows,cols,CV_8UC1,Scalar(0));
    Mat gy_p = Mat(rows,cols,CV_8UC1,Scalar(0));
    Mat gxy = Mat(rows,cols,CV_8UC1,Scalar(0));
    Harris.GRAD_MULTI(gx_img,gy_img,gx_p,gy_p,gxy);

    /*3.使用高斯函数加权*/
    Mat A = Mat(rows,cols,CV_8UC1,Scalar(0));
    Mat B = Mat(rows,cols,CV_8UC1,Scalar(0));
    Mat C = Mat(rows,cols,CV_8UC1,Scalar(0));
    Harris.GAUSS_WEI(gx_p,gy_p,gxy,A,B,C);
    /*4.计算每个像素点的harris响应值*/
    Mat R = Mat(rows,cols,CV_8UC1,Scalar(0));
    Harris.GET_RESPONSE(A,B,C,R);
    /*5.过滤大于某一阈值t的R值*/
    Mat CORNER = Mat(rows,cols,CV_8UC1,Scalar(0));
    Harris.FILTER_THRESH(R,img,CORNER);
    return 0;
}

my_harris.cpp

#include "my_harris.h"
#define pi 3.14
my_Harris::my_Harris()
{
}
void my_Harris::RGB2GRAY(Mat rgb_img, Mat &gray_img)
{
    Mat img_src = rgb_img.clone();
    int rows =  img_src.rows;
    int cols = img_src.cols;
    Mat img_gray = Mat(rows,cols,CV_8UC1,Scalar(0));
    for(int i = 0; i < rows; i++)
    {
        for(int j = 0; j<cols; j++)
        {
            img_gray.at<uchar>(i,j) = (0.1*img_src.at<Vec3b>(i,j)[0])+(0.6*img_src.at<Vec3b>(i,j)[1])+(0.3*img_src.at<Vec3b>(i,j)[2]);//粗略参数
        }
    }
    gray_img = img_gray;
}


void my_Harris::IMG_GRAD(Mat img, Mat &x_grad, Mat &y_grad)
{
    Mat img_src = img.clone();
    int rows = img_src.rows;
    int cols = img_src.cols;
    Mat x_g = Mat(rows,cols,CV_8UC1,Scalar(0));
    Mat y_g = Mat(rows,cols,CV_8UC1,Scalar(0));
    for(int i = 1; i <  rows-1; i++)
    {
        for(int j = 1; j < cols -1; j++)
        {
       //使用sobel算子求梯度 x_g.at
<uchar>(i,j) = abs((img_src.at<uchar>(i+1,j-1) - img_src.at<uchar>(i-1,j-1))+ 2*(img_src.at<uchar>(i+1,j) - img_src.at<uchar>(i-1,j)) + (img_src.at<uchar>(i+1,j+1) - img_src.at<uchar>(i-1,j+1)))/3; y_g.at<uchar>(i,j) = abs((img_src.at<uchar>(i-1,j+1) - img_src.at<uchar>(i-1,j-1))+2*(img_src.at<uchar>(i,j+1) - img_src.at<uchar>(i,j-1)) + (img_src.at<uchar>(i+1,j+1) - img_src.at<uchar>(i+1,j-1)))/3; } } x_grad = x_g; y_grad = y_g; } void my_Harris::GRAD_MULTI(Mat x_grad, Mat y_grad, Mat &p_x, Mat &p_y, Mat &p_xy) { Mat x_g = x_grad.clone(); Mat y_g = y_grad.clone(); int rows = x_g.rows; int cols = x_g.cols; Mat px = Mat(rows,cols,CV_8UC1,Scalar(0)); Mat py = Mat(rows,cols,CV_8UC1,Scalar(0)); Mat pxy = Mat(rows,cols,CV_8UC1,Scalar(0)); for(int i = 0; i < rows; i++) { for(int j = 0; j < cols; j++) { px.at<uchar>(i,j) = x_g.at<uchar>(i,j)*x_g.at<uchar>(i,j); py.at<uchar>(i,j) = y_g.at<uchar>(i,j)*y_g.at<uchar>(i,j); pxy.at<uchar>(i,j) = x_g.at<uchar>(i,j)*y_g.at<uchar>(i,j); } } p_x = px; p_y = py; p_xy = pxy; } void my_Harris::GAUSS_WEI(Mat p_x, Mat p_y, Mat p_xy, Mat &A, Mat &B, Mat &C) { Mat Ix = p_x.clone(); Mat Iy = p_y.clone(); Mat Ixy = p_xy.clone(); int rows = Ix.rows; int cols = Ix.cols; Mat g_Ix = Mat(rows,cols,CV_8UC1,Scalar(0)); Mat g_Iy = Mat(rows,cols,CV_8UC1,Scalar(0)); Mat g_Ixy = Mat(rows,cols,CV_8UC1,Scalar(0)); int k = 3; Mat gauss_plate = Mat(k,k,CV_8UC1,Scalar(0)); //GET_GAUSS(3,0.5, gauss_plate); g_Ix = GAUSS_PRO(Ix); g_Iy = GAUSS_PRO(Iy); g_Ixy = GAUSS_PRO(Ixy); A = g_Ix; B = g_Iy; C = g_Ixy; } Mat my_Harris::GAUSS_PRO(Mat g) { Mat Ix = g.clone(); float gauss_plate[3][3]={0.0113437, 0.0838195, 0.0113437, 0.0838195, 0.619347, 0.0838195,0.0113437,0.0838195,0.0113437}; int rows = Ix.rows; int cols = Ix.cols; Mat g_f = Mat(rows,cols,CV_8UC1,Scalar(0)); for(int i = 1; i < rows-1; i++) { for(int j = 1; j < cols-1; j++) { g_f.at<uchar>(i,j) = Ix.at<uchar>(i-1,j-1)*gauss_plate[0][0] + Ix.at<uchar>(i,j-1)*gauss_plate[1][0] + Ix.at<uchar>(i+1,j-1)*gauss_plate[2][0] + Ix.at<uchar>(i-1,j)*gauss_plate[0][1] + Ix.at<uchar>(i,j-1)*gauss_plate[1][1] + Ix.at<uchar>(i+1,j-1)*gauss_plate[2][1] + Ix.at<uchar>(i-1,j+1)*gauss_plate[0][2] + Ix.at<uchar>(i,j+1)*gauss_plate[1][2] + Ix.at<uchar>(i+1,j+1)*gauss_plate[2][2]; } } return g_f; } void my_Harris::GET_RESPONSE(Mat A_, Mat B_, Mat C_, Mat &R) { Mat A = A_.clone(); Mat B = B_.clone(); Mat C = C_.clone(); int rows = A.rows; int cols = B.cols; Mat M_R = Mat(rows, cols, CV_8UC1, Scalar(0)); for(int i = 0; i < rows; i++) { for(int j = 0; j < cols; j++) { float k = 0.15; float a = A.at<uchar>(i,j); float b = B.at<uchar>(i,j); float c = C.at<uchar>(i,j); float r = (a*b-c*c-k*((a+b)*(a+b))); M_R.at<uchar>(i,j) = int(r); if(abs(int(r)) > 48000) { M_R.at<uchar>(i,j) = 255; } else { M_R.at<uchar>(i,j) = 0; }
}
} R
= M_R; } void my_Harris::FILTER_THRESH(Mat R, Mat img, Mat &F_R) { Mat img_src = R.clone(); int rows = img_src.rows; int cols = img_src.cols; for(int i = 0; i < rows; i++) { for(int j = 0; j < cols; j++) { if(abs(img_src.at<uchar>(i,j))>254) { img.at<Vec3b>(i,j)[0]=0; img.at<Vec3b>(i,j)[1]=0; img.at<Vec3b>(i,j)[2]=255; } } } imshow("img_src",img); waitKey(0); }

my_harris.h

#ifndef MY_HARRIS_H
#define MY_HARRIS_H
#include "iostream"
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;
using namespace std;
class my_Harris
{
public:
    my_Harris();
    void RGB2GRAY(Mat rgb_img, Mat &gray_img);
    void IMG_GRAD(Mat img, Mat &x_grad, Mat &y_grad);
    void GRAD_MULTI(Mat x_grad, Mat y_grad, Mat &p_x, Mat &p_y, Mat &p_xy);
    void GAUSS_WEI(Mat p_x, Mat p_y, Mat p_xy, Mat &A, Mat &B, Mat &C);
    Mat GAUSS_PRO( Mat g);
    void GET_RESPONSE(Mat A_, Mat B_, Mat C_, Mat &R);
    void FILTER_THRESH(Mat R, Mat img, Mat &F_R);
};

#endif // MY_HARRIS_H

效果图:

Harris角点检测原理及C++实现   Harris角点检测原理及C++实现   Harris角点检测原理及C++实现

 

实现方法简单,可继续改进!

参考:https://www.cnblogs.com/zyly/p/9508131.html#_label5_0

 

原文链接: https://www.cnblogs.com/zhibei/p/12293119.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    Harris角点检测原理及C++实现

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/328308

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月1日 下午4:38
下一篇 2023年3月1日 下午4:38

相关推荐