OpenCV2.4.13源码分析-getGaussianKernel

基本原理

在数字图像处理中,一般取二维高斯函数为


由(1)可以知道,二维高斯函数,可以看成两个一维高斯函数乘积,因此先计算一维高斯模板,再计算需要的二维高斯模板。

两个归一化的一维模板相乘得到的二维高斯模板,同样为归一化结果,例:


如图1所示,

a)为两个归一化的一维高斯模板,即,a+b+c=1,d+e+f+g+h=1;

b)为两个一维高斯系数相乘得到的二维高斯模板,

ad + ae + af + ag + ah + bd + be + bf + bg +bh + cd + ce + cf + cg + ch

= a(d+e+f+g+h)+ b(b+e+f+g+h) + c(b+e+f+g+h)

=(a+b+c)(d+e+f+g+h) = 1 * 1 = 1

源码分析

OpenCV中获取一维归一化的高斯模板的函数为

// n – 模板尺寸,sigma( 标准差

cv::Mat cv::getGaussianKernel( int n, double sigma, int ktype )

主要流程为:

源码分析如下:

	【函数名称】 
	      cv::Mat cv::getGaussianKernel( int n, double sigma, int ktype )
	【函数描述】用于计算一维高斯函数的模板系数    
	【参数描述】n     — 模板尺寸,n必须为大于0的正整数,一般取n为奇数,但是通
	                        过源代码分析可以知道,取n为偶数,同样可以计算得到对
	                        应结果。    
	           sigma — 高斯标准差(公式中的σ),如果sigma取小于等于0的数,则
	                        函数根据当前n值计算对应的sigma值,
	                                       sigma = ((n-1)*0.5 – 1)*0.3 + 0.8。
	           ktype — 数据类型,CV_32F或者CV_64F    
	【返回值】 返回n行1列归一化的一维高斯系数    
	cv::Mat cv::getGaussianKernel( int n, double sigma, int ktype )  
	{  
	     // 预置的高斯系数数组,只有在
	     // (1)0<n<=7,n为奇数,
	     // (2)sigma为无效参数,即sigma<=0
	     // 同时满足时才会使用预置的高斯系数数组
	    const int SMALL_GAUSSIAN_SIZE = 7;  // 预置的最大模板的尺寸
	    static const float small_gaussian_tab[][SMALL_GAUSSIAN_SIZE] =  
	    {  
	        {1.f},  
	        {0.25f, 0.5f, 0.25f},  
	        {0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f},  
	        {0.03125f, 0.109375f, 0.21875f, 0.28125f, 0.21875f, 0.109375f, 0.03125f}
	    };  
	    // 判断是否满足采用预置高斯系数的条件
	    const float* fixed_kernel = n % 2 == 1 && n <= SMALL_GAUSSIAN_SIZE && sigma <= 0 ?  
	        small_gaussian_tab[n>>1] : 0;  
	    // 确定ktype参数的合法性,只能去CV_32F或者CV_64F
	    CV_Assert( ktype == CV_32F || ktype == CV_64F );  
	    Mat kernel(n, 1, ktype);  // 创建n行一列系数矩阵
	    float* cf = (float*)kernel.data;  // cf赋值为数据地址
	    double* cd = (double*)kernel.data;  // cd赋值为数据地址
	    // 如果sigma<0,则利用公式根据模板尺寸n计算sigma
	    double sigmaX = sigma > 0 ? sigma : ((n-1)*0.5 - 1)*0.3 + 0.8;  
	    double scale2X = -0.5/(sigmaX*sigmaX);  // 计算e^(-x^2/2σ^2 ) 中的-1/2σ^2
	    double sum = 0;  // 每一个元素之和,归一化时作为除数
	  
	    int i;  
	    for( i = 0; i < n; i++ )  
	    {  
	        double x = i - (n-1)*0.5;  // 计算索引为0的元素的x坐标
	        double t = fixed_kernel ? (double)fixed_kernel[i] : std::exp(scale2X*x*x);  // 取预置数组中对应元素或由高斯公式计算,1/√2π σ_x在归一化时
	                 // 会约去,所以不用计算。
	        // 根据元素类型为CV_32F或CV_64F赋值,并累加和
	         if( ktype == CV_32F )  
	        {  
	            cf[i] = (float)t;  
	            sum += cf[i];  
	        }  
	        else  
	        {  
	            cd[i] = t;  
	            sum += cd[i];  
	        }  
	    }  
	    // 做归一化计算
	    sum = 1./sum;  
	    for( i = 0; i < n; i++ )  
	    {  
	        if( ktype == CV_32F )  
	            cf[i] = (float)(cf[i]*sum);  
	        else  
	            cd[i] *= sum;  
	    }  
	  
	    return kernel;  
} 

注:

当n = 1、3、5、7并且sigma <= 0时,不采用预置模板,采用sigma = ((n-1)*0.5 - 1)*0.3 + 0.8计算时,如下表所示:


可以看出,此时和预置模板系数并不完全一致。


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值