精华内容
下载资源
问答
  • 环境vs2008+opencv2.4.3,Harris原理PPT与源码
  • Harris原理及OpenCV实

    千次阅读 2013-09-10 21:22:03
    Harris原理及OpenCV实现 概述 Harris算法是一种角点检测算法。 基本思想 在角点处,绿色小框在图像中沿着任意方向移动,方框覆盖的像素值都会发生很大的改变;平坦区域沿着任意方向都不会有太大变化;边缘...

    Harris原理及OpenCV实现

    概述

    Harris算法是一种角点检测算法。

    基本思想

       

    在角点处,绿色小框在图像中沿着任意方向移动,方框覆盖的像素值都会发生很大的改变;平坦区域沿着任意方向都不会有太大变化;边缘区域其实向任意方向移动也不会有什么变化,除非是在边缘的末端。(是不是角点动一动就知道了,是骡子是马拉出来溜溜)

    数学描述

    表示像素以移动之后像素值变化的方差和:

            

            

    数学特性    

    一届泰勒展开:

            

    向指定方向移动,窗口内的像素值的变化量:

            

    为滤波后的梯度散布矩阵,简写为。关键的地方在于,沿方向(u,v)算出来的值都是由ix,iy这个不变的东西决定的!

    下面用三张图片验证:

    上图是用PS加上5%的杂色,杂色不是很明显,下图第一栏转换成double型后的显示效果,

    第二栏是的分布,可以看出,平面的梯度散布范围很小,而边缘则呈扁椭圆,角点呈三角,但可以看到右上角的点均比较大即我们要找的角点。

    对应的特征值如下:

    eigenvalue

    Plane

    Edge

    Corner

    68483668088

    116292777117498

    62741886125931

    3358193434

    7446530637

    60918946323957

    上述只是定性的分析的关系,定量判定如下:

            

    其中经验值越大说明越有可能是角点。

    上图为对应的响应

    SIFT算法中使用了另一种判定方法:

    设最大的特征值/最小的特征值为,例如则

    考虑下式:

            

    令上式为为单调递增函数,故时判断为角点。经验值为什么角点沿任意方向移动,窗口内的像素都会有很大变化,而平坦区域沿任意方向移动都不会有变化,而边缘沿特定方向移动不会有变化呢?

    为什么会有如此特性了,这就取决于M。

    从梯度的散布形状可以判断该点是否是角点。梯度的散布形状又可以由散布矩阵的特征值大小、比例关系反映。因此,对对 进行特征值分解得到特征值
    不变性分析
    • 旋转不变性

       

    • 局部仿射不变性

    • 尺度不变性-不具备

    Harris-Laplace算法具有尺度不变性

    算法

    1. 计算梯度,(考虑干扰用Sobel算子滤波),得到三张图片
    2. 对得到的三张图片继续滤波,实现在窗口下的累积和.
    3. 计算行列式、迹

    OpenCV源码分析

    cornerEigenValsVecs(constMat&src,Mat&eigenv,intblock_size,

    intaperture_size,intop_type,doublek=0.,

    intborderType=BORDER_DEFAULT )

    {

    #ifdef HAVE_TEGRA_OPTIMIZATION

    if (tegra::cornerEigenValsVecs(src, eigenv, block_size, aperture_size, op_type, k, borderType))

    return;

    #endif

     

    int depth =src.depth();

    double scale = (double)(1 << ((aperture_size > 0 ?aperture_size : 3) - 1)) *block_size;//1 << 2 *2 =8

    if(aperture_size < 0 )

    scale *= 2.;

    if( depth ==CV_8U )

    scale *= 255.;

    scale = 1./scale;

     

    CV_Assert(src.type() ==CV_8UC1 ||src.type() ==CV_32FC1 );

     

    Mat Dx, Dy;

    if(aperture_size > 0 )

    {

            //[-1 0 1]

            //|-2 0 2|

            //[-1 0 1]

    Sobel(src, Dx,CV_32F, 1, 0,aperture_size, scale, 0,borderType );//3

    Sobel(src, Dy,CV_32F, 0, 1,aperture_size, scale, 0,borderType );//为什么来个这么大的scale??

    }

    else

    {

    Scharr(src, Dx,CV_32F, 1, 0, scale, 0,borderType );

    Scharr(src, Dy,CV_32F, 0, 1, scale, 0,borderType );

    }

     

    Size size =src.size();

    Mat cov( size,CV_32FC3 );    //dx^2,dxdy,dy^2

    int i, j;

     

    for( i = 0; i < size.height; i++ )

    {

    float* cov_data = (float*)(cov.data + i*cov.step);

    constfloat* dxdata = (constfloat*)(Dx.data + i*Dx.step);

    constfloat* dydata = (constfloat*)(Dy.data + i*Dy.step);

     

    for( j = 0; j < size.width; j++ )

    {

    float dx = dxdata[j];

    float dy = dydata[j];

     

    cov_data[j*3] = dx*dx;

    cov_data[j*3+1] = dx*dy;

    cov_data[j*3+2] = dy*dy;

    }

    }

     

    boxFilter(cov, cov, cov.depth(),Size(block_size,block_size),Point(-1,-1),false,borderType );

        anchor – anchor point;default value Point(-1,-1) means that the anchor is at the kernel center.

        //改成Gaussian滤波

        //GaussianBlur(cov, cov, Size(5, 5), 0,0 );

    if( op_type == MINEIGENVAL )

    calcMinEigenVal( cov, eigenv );

    elseif( op_type == HARRIS )

    calcHarris( cov, eigenv, k );

    elseif( op_type == EIGENVALSVECS )

    calcEigenValsVecs( cov, eigenv );

    }

    }

    calcHarris(constMat&_cov,Mat&_dst,doublek )

    {

            ……………………

    for( ; j < size.width; j++ )

    {

    float a = cov[j*3];

    float b = cov[j*3+1];

    float c = cov[j*3+2];

    dst[j] = (float)(a*c - b*b -k*(a + c)*(a + c));//R = det(M)-k*trace(M)

    }

    ………………

    }

    Note:matlab实现可参见《现代数字图像处理技术提高及应用案例详解(MATLAB版)》-赵小川

    展开全文
  • Harris原理及opencv源码分析

    千次阅读 2017-01-12 21:37:21
    一、前言 Harri角点检测的原理分析网上已经一大堆,这里则简单介绍Harris角点检测,并结合原理分析opencv实现的源码。 参考资料: http://blog.csdn.net/ZengDong_1991/article/details/45563301 ...

    一、前言

    Harri角点检测的原理分析网上已经一大堆,这里则简单介绍Harris角点检测,并结合原理分析opencv实现的源码。

    参考资料:

    http://blog.csdn.net/ZengDong_1991/article/details/45563301

    http://docs.opencv.org/2.4/doc/tutorials/features2d/trackingmotion/harris_detector/harris_detector.html

    二、Harris角点原理

    感觉Harris角点在Opencv Turorials上已经讲解的很清楚了,原理简介如下:




    论文中k=0.04~0.06,opencv指出是0.05-0.5;故通过设定阈值与R进行可以比较,则可获得角点位置。opencv中的cornerHarris实现了计算图像中每个像素的角点响应值。

    三、cornerHarris函数分析

    a) opencv中的角点响应函数值实现函数为:

    void cornerHarris(InputArray src, OutputArray dst, int blockSize, int ksize, double k, int borderType=BORDER_DEFAULT )


    各形参的意义为:
    src- 输入单通道8bit或浮点图像
    dst- 存储所计算得的角点响应值,为CV_32FC1类型且与src具有相同大小
    blockSize- 领域大小,也即窗口函数大小W(x, y)
    ksize- 用sobel函数计算的模板大小
    k- 计算角点响应值的K值
    borderType - 支持BORDER_REFLECT101和borderType两种边界处理


    b)opencv 源代码分析

    /*Harris角点实现函数,截取cornerHarris中的关键代码并做了简化....
    /*出自博客 http://blog.csdn.net/ZengDong_1991/article/details/45563301
     */
    void myHarris(const Mat& src, Mat& eigenv, int block_size, int aperture_size, double k )
    {
    	eigenv.create(src.size(), CV_32F);
    	Mat Dx, Dy;
    	//sobel operation get Ix, Iy
    	Sobel(src, Dx, CV_32F, 1, 0, aperture_size);
    	Sobel(src, Dy, CV_32F, 0, 1, aperture_size);
    
    	//get covariance matrix
    	Size size = src.size();
    	Mat cov(size, CV_32FC3);   //创建一个三通道cov矩阵分别存储[Ix*Ix, Ix*Iy; Iy*Ix, Iy*Iy];
    
    	for (int i = 0; i < size.height; i++)
    	{
    		float* cov_data = cov.ptr<float>(i);
    		const float* dxdata = Dx.ptr<float>(i);
    		const float* dydata = Dy.ptr<float>(i);
    
    		for (int j = 0; j < size.width; j++)
    		{
    			float dx = dxdata[j];
    			float dy = dydata[j];
    
    			cov_data[j * 3] = dx * dx;      //即   Ix*Ix
    			cov_data[j * 3 + 1] = dx * dy;   //即  Ix*Iy
    			cov_data[j * 3 + 2] = dy * dy;  //即   Iy*Iy
    
    		}
    
    	}
    
    	//方框滤波 W(x,y)卷积   ,  也可用高斯核加权...
    	//W(X,Y)与矩阵cov卷积运算得到  H 矩阵,后面通过H矩阵的特征值决定是否是角点
    	boxFilter(cov, cov, cov.depth(), Size(block_size, block_size), Point(-1, -1), false);
    
    	//cale Harris
    	size = cov.size();
    	if (cov.isContinuous() && eigenv.isContinuous())
    	{
    		size.width *= size.height;
    		size.height = 1;
    		//cout << "yes" << endl;
    	}
    
    	//此处计算响应R= det(H) - k*trace(H)*trace(H);
    	for (int i = 0; i < size.height; i++)
    	{
    		const float* covPtr = cov.ptr<float>(i);
    		float* dstPtr = eigenv.ptr<float>(i);
    
    		for (int j = 0; j < size.width; j++)
    		{
    			float a = covPtr[j * 3];
    			float b = covPtr[j * 3 + 1];
    			float c = covPtr[j * 3 + 2];
    
    			//根据公式  R = det(H) - k* trace(H)*trace(H);  
    			dstPtr[j] = (float)(a*c - b*b - k*(a + c)*(a + c));
    		}
    
    	}
    
    }
    c)测试代码
    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    
    using namespace cv;
    using namespace std;
    
    /// Global variables
    Mat src, src_gray;
    int thresh = 200;
    int max_thresh = 255;
    
    char* source_window = "Source image";
    char* corners_window = "Corners detected";
    
    /// Function header
    void cornerHarris_demo(int, void*);
    void myHarris(const Mat& src, Mat& eigenv, int block_size, int aperture_size, double k = 0.);
    
    /** @function main */
    int main(int argc, char** argv)
    {
    	/// Load source image and convert it to gray
    	//src = imread(argv[1], 1);
    	src = imread( "lena.bmp" , 1);
    	cvtColor(src, src_gray, CV_BGR2GRAY);
    
    	/// Create a window and a trackbar
    	namedWindow(source_window, CV_WINDOW_AUTOSIZE);
    	createTrackbar("Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo);
    	imshow(source_window, src);
    
    	cornerHarris_demo(0, 0);
    
    	waitKey(0);
    	return(0);
    }
    
    /** @function cornerHarris_demo */
    void cornerHarris_demo(int, void*)
    {
    
    	Mat dst, dst_norm, dst_norm_scaled;
    	dst = Mat::zeros(src.size(), CV_32FC1);
    
    	/// Detector parameters
    	int blockSize = 2;
    	int apertureSize = 3;
    	double k = 0.04;
    
    	/// Detecting corners
    	//cornerHarris(src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT);
    	myHarris(src_gray, dst, blockSize, apertureSize, k);
    
    	/// Normalizing
    	normalize(dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
    	convertScaleAbs(dst_norm, dst_norm_scaled);
    
    	/// Drawing a circle around corners
    	for (int j = 0; j < dst_norm.rows; j++)
    	{
    		for (int i = 0; i < dst_norm.cols; i++)
    		{
    			if ((int)dst_norm.at<float>(j, i) > thresh)
    			{
    				circle(dst_norm_scaled, Point(i, j), 5, Scalar(0), 2, 8, 0);
    			}
    		}
    	}
    	/// Showing the result
    	namedWindow(corners_window, CV_WINDOW_AUTOSIZE);
    	imshow(corners_window, dst_norm_scaled);
    }

    d)测试结果


    四、opencv goodFeaturesToTrack

    以上cornerHarris函数需通过设置阈值对角点响应值进行判断,而opencv中的goodFeaturesToTrack已定义了一些角点选择方法。

    a) goodFeaturesToTrack函数
    goodFeaturesToTrack(InputArray image, OutputArray corners, int maxCorners, double qualityLevel, double minDistance, InputArray mask=noArray(), int blockSize=3, bool useHarrisDetector=false, double k=0.04 )


    各形参的意义为:
    image- 单通道8bit或32bit浮点型图像
    corners- 检测得的角点存放的容器
    maxCorners- 返回的角点个数,如果检测的角点超过这个数目,从大到小依次返回
    qualityLevel- 其与最大角点响应值的乘积作为角点响应阈值,小于该阈值则不考虑作为角点
    minDistance- 两角点之间的最小欧式距离
    mask- 掩模,必须与image具有同样大小,数据类型为CV_8UC1,非0值表示需要检测区域
    blockSize- 内部调用cornerHarris函数用到的w(x, y)大小
    useHarrisDetector- 是否使用HarrisDetector
    k- cornerHarris中的计算角点响应函数值的 K


    b)关键代码

    //GoodFeaturesToTrack关键代码截取
    void myGoodFeaturesToTrack( Mat& image, double qualityLevel, double minDistance, int maxCorners )
    {
        Mat eig;
        Mat tmp;
        cornerHarris(image, eig, 5, 3, 0.06); //Harris corners;
    
        double maxVal = 0;
        minMaxLoc(eig, 0, &maxVal, 0, 0, Mat());
        //cout << maxVal << endl << maxVal*255. << endl;
    
        //除去角点响应小于   角点最大响应qualityLevel倍的点
        threshold(eig, eig, qualityLevel*maxVal, 0, THRESH_TOZERO);  //eig is CV_32F
        //normalize(eig, result, 0, 255, NORM_MINMAX, CV_8U);   //normalize to show image.
    
        //get corners  max in 3*3  if Mat();
        //为什么膨胀操作:膨胀的本质是用当前像素周围的最大值替代当前像素值,
        //因此,通过膨胀前后比较能取得局部角点响应最大的点。
        //第一次是在《OpenCV Programming Cookbook》中看到这种做法,觉得这想法太给力了...
        //最后结果存储在tmpCorners中    
        dilate(eig, tmp, Mat());   //for later operation
    
    
        vector<const float*> tmpCorners;
        Size imageSize = image.size();
    
    
        {
    //      HANDLE hSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
    //      CRITICAL_SECTION g_cs;
            //#pragma omp parallel for              //【此处并行为什么出错呢???????????????】
            for ( int y = 1; y < imageSize.height -1; y++ )
            {
                float* eig_data = (float*)eig.ptr<float>(y);     //角点响应
                float* tmp_data = (float*)tmp.ptr<float>(y);    // 膨胀之后
    
                //#pragma omp parallel for
                for ( int x =1; x < imageSize.width -1; x++ )
                {
                    float val = eig_data[x];
                    if ( val != 0 && val == tmp_data[x] )     //如果膨胀前后的值不变,说明这个像素点是[3*3]邻域的最大值
                    {
        //              #pragma omp atomic              //原子操作
        //              WaitForSingleObject(hSemaphore, NULL);
                        //EnterCriticalSection(&g_cs);
                        tmpCorners.push_back(eig_data + x);
                        //LeaveCriticalSection(&g_cs);
        //              ReleaseSemaphore(hSemaphore, NULL, NULL);
                    }
                }
            }
        }
        //ShellExecuteEx
        //tmpCorners存储角点的地址, 排序操作
        sort(tmpCorners, greaterThanPtr<float>());
        vector<Point2f> corners;
        size_t i, j, total = tmpCorners.size(), ncorners = 0;
        if ( minDistance >= 1 )     //如果有角点之间最小距离限制
        {
            //将图片分为各个grid...每个grid的边长为minDistance
            int w = image.cols;
            int h = image.rows;
    
            //cvRound :Rounds floating-point number to the nearest integer
            const int cell_size = cvRound(minDistance);  
            const int grid_width = (w + cell_size -1) / cell_size;
            const int grid_height = (h + cell_size -1) /cell_size;
    
            //每个grid用一个vector<Point2f>  存储角点
            vector<vector<Point2f> >    grid(grid_width*grid_height);  
            minDistance *= minDistance;
    
            for ( i =0; i < total; i++ )
            {
                //先得到当前点的坐标
                int ofs = (int)((const uchar*)tmpCorners[i] - eig.data);
                int y = (int)(ofs / eig.step);
                int x = (int)((ofs - y*eig.step) / sizeof(float));
    
                bool good = true;
    
                //确定当前点对应哪个grid
                int x_cell = x / cell_size;
                int y_cell = y / cell_size;
    
                //得到上下,左右[-1,1]范围内grid
                int x1 = x_cell - 1;
                int y1 = y_cell - 1;
                int x2 = x_cell + 1;
                int y2 = y_cell + 1;
    
                x1 = max(0, x1);
                y1 = max(0, y1);
                x2 = min(grid_width-1, x2);
                y2 = min(grid_height-1, y2);
    
    
                //上面说过每个grid用一个vector<Point2f> 存储位于这个区域内的角点
                //对当前角点,先得到坐标,然后找到属于哪个grid,并和周围的8(最大是8)个grid中
                //的 Point2f 比较距离,如果两点之间的距离小于minDistance则放弃这个角点
                //因为我们是按角点响应的降序依次访问的...
                for ( int yy = y1; yy <= y2; yy++ )
                {
                    for ( int xx = x1; xx <= x2; xx++ )
                    {
                        //m存储对应grid中角点。一个grid中可能有多个角点
                        vector<Point2f>& m = grid[yy*grid_width + xx];
                        if ( m.size() )
                        {
                            //求当前角点到这个grid内所有角点的距离,若小于当前grid中的某个点,直接跳到break_out,其他
                            //grid不用再比较,直到周围grid都没有距离小于minstance的值,则将角点push进当前grid中
                            for ( j =0; j < m.size(); j++ )
                            {
                                float dx = x - m[j].x;
                                float dy = y - m[j].y;
    
                                if ( dx*dx + dy*dy < minDistance )
                                {
                                    good = false;
                                    goto break_out;
                                }
                            }
                        }
                    }
                }
    
                break_out:
    
                if ( good )
                {
                    //将当前角点存入grid中
                    grid[y_cell*grid_width + x_cell].push_back(Point2f((float)x, (float)y));
    
                    circle(image, Point(x, y), 5, Scalar(255), 2);
                    corners.push_back(Point2f((float)x, (float)y));
                    ++ncorners;
                    if ( maxCorners > 0 && (int)ncorners == maxCorners )
                    {
                        break;
                    }
                }
    
            }
    
        }
        else    //如果不考虑角点间最小距离限制
        {
            for ( i = 0; i < total; i++ )
            {
                //因为eig.step 是Number of bytes each matrix row occupies.
                int ofs = (int)((const uchar*)tmpCorners[i] - eig.data);   
                //通过tmpCorner存储的角点在内存中的地址还原得到图像中的坐标..
                int y = (int)(ofs / eig.step);
                int x = (int)((ofs - y*eig.step) / sizeof(float));
                circle(image, Point(x, y), 5, Scalar(255), 2);       
                corners.push_back(Point2f((float)x, (float)y));
                ++ncorners;
                if ( maxCorners > 0 && (int)ncorners == maxCorners )
                {
                    break;
                }
            }
        }
    
    
        imshow("eig", image);
    
    }




    展开全文
  • Harris算法原理

    2010-10-11 00:02:00
    Harris算法原理:+角点:最直观的印象就是在水平、竖直两个方向上变化均较大的点,即Ix、Iy都较大+边缘:仅在水平、或者仅在竖直方向有较大的变化量,即Ix和Iy只有其一较大+平坦地区:在水平、竖直方向的变化量均较...
  • Harris角点检测原理详解

    万次阅读 多人点赞 2017-01-20 23:34:03
    网上也有很多博客对Harris角点检测原理进行描述,但基本上只是描述了算法流程,而其中有关细节并未作出解释,这里我想对有些地方做出解释,如有不对,还请指正。 1. 首先,何为角点? 下面有两副不同视角的图像,...

    关于角点的应用在图像处理上比较广泛,如图像匹配(FPM特征点匹配)、相机标定等。网上也有很多博客对Harris角点检测原理进行描述,但基本上只是描述了算法流程,而其中相关细节并未作出解释,这里我想对有些地方做出补充说明,正所谓知其然知其所以然,如有不对,还望指正。

    1. 何为角点?

    下面有两幅不同视角的图像,通过找出对应的角点进行匹配。


    再看下图所示,放大图像的两处角点区域:


    我们可以直观的概括下角点所具有的特征:

    >轮廓之间的交点;

    >对于同一场景,即使视角发生变化,通常具备稳定性质的特征;

    >该点附近区域的像素点无论在梯度方向上还是其梯度幅值上有着较大变化;


    2. 角点检测算法基本思想是什么?

    算法基本思想是使用一个固定窗口在图像上进行任意方向上的滑动,比较滑动前与滑动后两种情况,窗口中的像素灰度变化程度,如果存在任意方向上的滑动,都有着较大灰度变化,那么我们可以认为该窗口中存在角点。


    3.如何用数学方法去刻画角点特征?

    当窗口发生[u,v]移动时,那么滑动前与滑动后对应的窗口中的像素点灰度变化描述如下:


    公式解释:

    >[u,v]是窗口的偏移量

    >(x,y)是窗口内所对应的像素坐标位置,窗口有多大,就有多少个位置

    >w(x,y)是窗口函数,最简单情形就是窗口内的所有像素所对应的w权重系数均为1。但有时候,我们会将w(x,y)函数设定为以窗口中心为原点的二元正态分布。如果窗口中心点是角点时,移动前与移动后,该点的灰度变化应该最为剧烈,所以该点权重系数可以设定大些,表示窗口移动时,该点在灰度变化贡献较大;而离窗口中心(角点)较远的点,这些点的灰度变化几近平缓,这些点的权重系数,可以设定小点,以示该点对灰度变化贡献较小,那么我们自然想到使用二元高斯函数来表示窗口函数,这里仅是个人理解,大家可以参考下。

    所以通常窗口函数有如下两种形式:


    根据上述表达式,当窗口处在平坦区域上滑动,可以想象的到,灰度不会发生变化,那么E(u,v) = 0;如果窗口处在比纹理比较丰富的区域上滑动,那么灰度变化会很大。算法最终思想就是计算灰度发生较大变化时所对应的位置,当然这个较大是指针任意方向上的滑动,并非单指某个方向。


    4.E(u,v)表达式进一步演化

    首先需要了解泰勒公式,任何一个函数表达式,均可有泰勒公式进行展开,以逼近原函数,我们可以对下面函数进行一阶展开(如果对泰勒公式忘记了,可以翻翻本科所学的高等数学)


    那么,






    所以E(u,v)表达式可以更新为:


    这里矩阵M为,


    5.矩阵M的关键性

    难道我们是直接求上述的E(u,v)值来判断角点吗?Harris角点检测并没有这样做,而是通过对窗口内的每个像素的x方向上的梯度与y方向上的梯度进行统计分析。这里以Ix和Iy为坐标轴,因此每个像素的梯度坐标可以表示成(Ix,Iy)。针对平坦区域,边缘区域以及角点区域三种情形进行分析:


    下图是对这三种情况窗口中的对应像素的梯度分布进行绘制:


    如果使用椭圆进行数据集表示,则绘制图示如下:


    不知道大家有没有注意到这三种区域的特点,平坦区域上的每个像素点所对应的(IX,IY)坐标分布在原点附近,其实也很好理解,针对平坦区域的像素点,他们的梯度方向虽然各异,但是其幅值都不是很大,所以均聚集在原点附近;边缘区域有一坐标轴分布较散,至于是哪一个坐标上的数据分布较散不能一概而论,这要视边缘在图像上的具体位置而定,如果边缘是水平或者垂直方向,那么Iy轴方向或者Ix方向上的数据分布就比较散;角点区域的x、y方向上的梯度分布都比较散。我们是不是可以根据这些特征来判断哪些区域存在角点呢?

    虽然我们利用E(u,v)来描述角点的基本思想,然而最终我们仅仅使用的是矩阵M。让我们看看矩阵M形式,是不是跟协方差矩阵形式很像,像归像,但是还是有些不同,哪儿不同?一般协方差矩阵对应维的随机变量需要减去该维随机变量的均值,但矩阵M中并没有这样做,所以在矩阵M里,我们先进行各维的均值化处理,那么各维所对应的随机变量的均值为0,协方差矩阵就大大简化了,简化的最终结果就是矩阵M,是否明白了?我们的目的是分析数据的主要成分,相信了解PCA原理的,应该都了解均值化的作用。

    如果我们对协方差矩阵M进行对角化,很明显,特征值就是主分量上的方差,这点大家应该明白吧?不明白的话可以复习下PCA原理。如果存在两个主分量所对应的特征值都比较大,说明什么? 像素点的梯度分布比较散,梯度变化程度比较大,符合角点在窗口区域的特点;如果是平坦区域,那么像素点的梯度所构成的点集比较集中在原点附近,因为窗口区域内的像素点的梯度幅值非常小,此时矩阵M的对角化的两个特征值比较小;如果是边缘区域,在计算像素点的x、y方向上的梯度时,边缘上的像素点的某个方向的梯度幅值变化比较明显,另一个方向上的梯度幅值变化较弱,其余部分的点都还是集中原点附近,这样M对角化后的两个特征值理论应该是一个比较大,一个比较小,当然对于边缘这种情况,可能是呈45°的边缘,致使计算出的特征值并不是都特别的大,总之跟含有角点的窗口的分布情况还是不同的。

    注:M为协方差矩阵,需要大家自己去理解下,窗口中的像素集构成一个矩阵(2*n,假设这里有n个像素点),使用该矩阵乘以该矩阵的转置,即是协方差矩阵

    因此可以得出下列结论:

    >特征值都比较大时,即窗口中含有角点

    >特征值一个较大,一个较小,窗口中含有边缘

    >特征值都比较小,窗口处在平坦区域


    6. 如何度量角点响应?

    通常用下面表达式进行度量:


    其中k是常量,一般取值为0.04~0.06,这个参数仅仅是这个函数的一个系数,它的存在只是调节函数的形状而已。

    但是为什么会使用这样的表达式呢?一下子是不是感觉很难理解?其实也不难理解,函数表达式一旦出来,我们就可以绘制它的图像,而这个函数图形正好满足上面几个区域的特征。 通过绘制函数图像,直观上更能理解。绘制的R函数图像如下:



    所以说难点不在于理解这个函数表达式,而在于如何创造出这个函数表达式。Harris也许对很多函数模型非常了解,对于创造出这样的一个函数表达式,易如反掌,当然在我们看来感觉是很了不起的,那是因为我们见过的函数模型太少。如果你也能构造一个函数模型,更能精确满足上述的三个特征,那么你比Harris更牛偷笑,纯属玩笑。

    最后设定R的阈值,进行角点判断。当然其中还有些后处理步骤就不再说了,比如说角点的极大值抑制等,就到这里吧,欢迎讨论留言。


    NOTE:
    有些朋友在问是如何通过矩阵判断角点的? 其实上面,我们已经推导出E(u,v)的表达式,大家看看这个表达式有什么特征,其中矩阵M是实对称矩阵,那么E表达式其实就是二次型,对于二次型想必大家会有印象,U,V代表窗口滑动方向以及滑动量,E代表灰度变化,通过矩阵M进行特征值求解,而特征值所对应的特征向量即为灰度变化方向。如果两个特征值较大,则表示有两个方向灰度变化较快。所以可以直接通过求解M的特征值进行角点判断
    展开全文
  • harris corner原理

    2014-05-14 21:47:56
    原理: 灰度变化率有函数如下: 其中的W(x,y)函数如下 对公式中中括号中的部分Taylor展开并取一阶式,得到 设 则矩阵形式 Harris采用了一种新的角点判定方法。矩阵M的两...

    原理:

    灰度变化率有函数如下:

    其中的W(x,y)函数如下

    对公式中中括号中的部分Taylor展开并取一阶式,得到

    则矩阵形式

    Harris采用了一种新的角点判定方法。矩阵M的两个特征向量l1和l2与矩阵M的主曲率成正比。Harris利用l1, l2来表征变化最快和最慢的两个方向.若两个都很大就是角点,一个大一个小就是边缘,两个都小就是在变化缓慢的图像区域.

                                

    图1- 4用矩阵M的特征向量分类图像像素点

    但是解特征向量需要比较多的计算量,且两个特征值的和等于矩阵M的迹,两个特征值的积等于矩阵M的行列式。所以用(1-4)式来判定角点质量。(k常取0.04-0.06)

    Harris算法总结

    Step 1:对每一像素点计算相关矩阵M。

    Step 2:计算每像素点的Harris 角点响应。 

    Step 3.在w*w范围内寻找极大值点,若Harris 角点响应大于阀值,则视为角点。

    Harris算子对灰度的平移是不变的,因为只有差分,对旋转也有不变性,但是对尺度很敏感,在一个尺度下是角点, 在在另一个尺度下可能就不是了.

    编程实现:

    [objc]  view plain copy
    1. fx = [-1 0 1;-1 0 1;-1 0 1];          % 高斯函数一阶微分,x方向(用于改进的Harris角点提取算法)   
    2. %fx = [-2 -1 0 1 2];                 % x方向梯度算子(用于Harris角点提取算法)   
    3. Ix = filter2(fx,ori_im);              % x方向滤波   
    4. fy = [-1 -1 -1;0 0 0;1 1 1];          % 高斯函数一阶微分,y方向(用于改进的Harris角点提取算法)   
    5. % fy = [-2;-1;0;1;2];                 % y方向梯度算子(用于Harris角点提取算法)   
    6. Iy = filter2(fy,ori_im);              % y方向滤波   

    3)考虑到图像一般情况下的噪声影响,采用高斯滤波去除噪声点。

    [objc]  view plain copy
    1. Ix2 = Ix.^2;   
    2. Iy2 = Iy.^2;   
    3. Ixy = Ix.*Iy;   
    4. clear Ix;   
    5. clear Iy;   
    6. h= fspecial('gaussian',[7 7],2);      % 产生7*7的高斯窗函数,sigma=2   
    7.    
    8. Ix2 = filter2(h,Ix2);   
    9. Iy2 = filter2(h,Iy2);   
    10. Ixy = filter2(h,Ixy);   

    4)计算角点的准则函数R(即用一个值来判断该点来衡量这个点是否是角点),并标记角点(R(i,j)>0.01*Rmax,且R(i,j)为3x3邻域局部最大值)。

    M = [Ix2(i,j) Ixy(i,j);Ixy(i,j) Iy2(i,j)]; 
    R(i,j) = det(M)-k*(trace(M))^2; % 计算R

    【可以通过改变准则函数的计算来改进harris算法,上式中的k一般取0.04~0.06】

    [objc]  view plain copy
    1. [height,width] = size(ori_im);   
    2. result = zeros(height,width);         % 纪录角点位置,角点处result的值为1   
    3. R = zeros(height,width);   

      

    [objc]  view plain copy
    1. Rmax = 0;                              % 图像中最大的R值   
    2. for i = 1:height   
    3.     for j = 1:width   
    4.         M = [Ix2(i,j) Ixy(i,j);Ixy(i,j) Iy2(i,j)];         
    5.         R(i,j) = det(M)-0.06*(trace(M))^2;            
    6.         if R(i,j) > Rmax   
    7.             Rmax = R(i,j);   
    8.         end   
    9.     end  
    10. end  
    11.    
    12. cnt = 0; %角点个数  
    13. for i = 2:height-1   
    14.     for j = 2:width-1   
    15.         % 进行非极大抑制,窗口大小3*3   
    16.         if R(i,j) > 0.01*Rmax && R(i,j) > R(i-1,j-1) && R(i,j) > R(i-1,j) && R(i,j) > R(i-1,j+1) && R(i,j) > R(i,j-1) && R(i,j) > R(i,j+1) && R(i,j) > R(i+1,j-1) && R(i,j) > R(i+1,j) && R(i,j) > R(i+1,j+1)   
    17.             result(i,j) = 1;   
    18.             cnt = cnt+1;   
    19.         end  
    20.     end  
    21. end  
    22.    
    23. [posc, posr] = find(result == 1);   
    24. disp(cnt);                 % 显示角点个数   
    25. imshow(ori_im);   
    26. hold on;   
    27. plot(posr,posc,'r+');   

    以上信息来源:

    详细原理及公式推导http://www.cse.psu.edu/~rcollins/CSE486/lecture06.pdf

    算法精讲及总结http://blog.163.com/zhaowei0425@126/blog/static/47586030201132611115984/

    编程实现http://www.cnblogs.com/blue-lg/archive/2011/12/17/2291139.html

    展开全文
  • 2.Harris原理 Harris中也是根据角点定义经角点定义,Harris中使用该像素点周围像素块和其周围的其它像素块的相关性刻画角点,相关性用平方差之和进行计算(SSD),SSD越大,相关性差,中心像素点越有可能成为角点。其...
  • Harris角点检测原理

    2014-04-13 19:36:46
    Harris角点检测原理讲解 讲解了Harris原理,数学方法。
  • harris算子原理的介绍

    热门讨论 2009-02-05 11:27:46
    这部是介绍harris特征提取算子的论文,英文版,论文详细了推导了harris算子的原理
  • (一)论文学习之Harris算子的实现 本系列研究的是自适应超参数估计的Harris算子 ...文章目录(一)论文学习之Harris算子的实现前言一、Harris算子的前身Moravec算子二、Harris算子原理实现1.Moravec算子的不足2.S
  • Harris角点检测原理与流程
  • Harris角点检测原理分析

    万次阅读 多人点赞 2015-05-09 20:23:42
    转注:NewThinker_wei: 加了一些原理性的注解,注解部分在文中用 {{ }} 圈了起来。...Harris角点检测算子是于1988年由CHris Harris & Mike Stephens提出来的。在具体展开之前,不得不提一下Morave
  • Harris-Laplace原理

    千次阅读 2013-09-10 21:17:56
    Harris-Laplace原理 尺度不变性 尺度:可以理解为照相时的焦距,尺度越大,图像越模糊,反之相反。高斯模糊可模拟焦距的调节,自然越大,尺度越大,图像越模糊。 尺度不变性: 对于同一个角点,尺度变化...
  • Harris角点检测原理及实现

    千次阅读 2016-06-23 22:00:29
    一、原理 二、实现 close all; clear all; I=imread('test.tif'); [posX,posY]=harris(I); figure;imshow(I); hold on; plot(posX, posY, 'g*');function [posX,posY]=harris(I) %Harris角点检测 %I:输入...
  • 1. Harris角点检测的原理 2. Harris角点检测的详细源码分析
  • Harris 角点检测算法原理

    千次阅读 2017-06-22 15:14:11
    图像处理之角点检测算法(Harris Corner Detection) 原文地址:http://blog.csdn.net/jia20003/article/details/16908661,本文对其进行一定的理解性的注释的添加。 Harris角点检测是通过数学计算在图像上发现角...
  • harris角点检测原理

    2021-07-23 22:23:36
    目录 1、角点概述 2、数学知识 3、Harris角点检测基本原理 4、优化改进 1、角点概述 如果一个点在任意方向的一个微小变动都会引起灰度很大的变化,那么我们就把它称之为角点,也就是一阶导数(即灰度图的梯度)中的...
  • harris角点检测数学原理的参考资料,内附代码
  • Harris Corner Detector 原理及编程实现

    万次阅读 2013-05-08 10:19:16
    完整的Harris焦点检测原理:公式推导,直觉理解,算法实现

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,443
精华内容 1,377
关键字:

harris原理