在openCV中创建2D LoG内核,就像在Matlab中的fspecial一样

时间:2014-05-05 11:13:17

标签: matlab opencv filter kernel

我的问题不是如何使用高斯拉普拉斯过滤图像(基本上使用带有相关内核的filter2D等)。

我想知道的是我如何生成 NxN内核。

我将举例说明如何在openCV中生成[Winsize x WinSize]高斯内核。

在Matlab中:

gaussianKernel = fspecial('gaussian', WinSize, sigma);

在openCV中:

cv::Mat gaussianKernel = cv::getGaussianKernel(WinSize, sigma, CV_64F);
cv::mulTransposed(gaussianKernel,gaussianKernel,false);

预定义sigma和WinSize。

我想为高斯拉普拉斯算法做同样的事。

在Matlab中:

LoGKernel = fspecial('log', WinSize, sigma);

如何在openCV中获得确切的内核(精确到几乎可以忽略不计的数值差异)?

我正在开发一个特定的应用程序,在那里我需要实际的内核值,只是通过近似高斯的差异找到另一种实现LoG过滤的方法并不是我所追求的。

谢谢!

7 个答案:

答案 0 :(得分:4)

您可以使用公式

手动生成它

LoG(x,y)=(1 /(pi * sigma ^ 4))*(1 - (x ^ 2 + y ^ 2)/(sigma ^ 2))*(e ^( - (x ^ 2 + y ^ 2)/ 2sigma ^ 2)

http://homepages.inf.ed.ac.uk/rbf/HIPR2/log.htm

cv::Mat kernel(WinSize,WinSize,CV_64F);
int rows = kernel.rows;
int cols = kernel.cols;
double halfSize = (double) WinSize / 2.0; 
for (size_t i=0; i<rows;i++)
  for (size_t j=0; j<cols;j++)
    { 
     double x = (double)j - halfSize;
     double y = (double)i - halfSize;
     kernel.at<double>(j,i) = (1.0 /(M_PI*pow(sigma,4))) * (1 - (x*x+y*y)/(sigma*sigma))* (pow(2.718281828, - (x*x + y*y) / 2*sigma*sigma));
     }

如果上面的函数不正常,你可以简单地重写fspecial的matlab版本:

 case 'log' % Laplacian of Gaussian
 % first calculate Gaussian
 siz   = (p2-1)/2;
 std2   = p3^2;

 [x,y] = meshgrid(-siz(2):siz(2),-siz(1):siz(1));
 arg   = -(x.*x + y.*y)/(2*std2);

 h     = exp(arg);
 h(h<eps*max(h(:))) = 0;

 sumh = sum(h(:));
 if sumh ~= 0,
   h  = h/sumh;
 end;
 % now calculate Laplacian     
 h1 = h.*(x.*x + y.*y - 2*std2)/(std2^2);
 h     = h1 - sum(h1(:))/prod(p2); % make the filter sum to zero

答案 1 :(得分:1)

我要感谢老不明飞行物在正确的方向上推动我。 我希望我不必通过快速的matlab重新发明轮子 - &gt; openCV转换,但我猜这是我用于快速解决方案的最佳解决方案。

注意 - 我这样做仅用于方形内核(否则很容易修改,但我没有必要这样......)。 也许这可以用更优雅的形式写成,但是我做的很快,所以我可以继续处理更紧迫的事情。

来自主要功能:

int WinSize(7); int sigma(1); // can be changed to other odd-sized WinSize and different sigma values
cv::Mat h = fspecialLoG(WinSize,sigma);

实际功能是:

// return NxN (square kernel) of Laplacian of Gaussian as is returned by     Matlab's: fspecial(Winsize,sigma)
cv::Mat fspecialLoG(int WinSize, double sigma){
 // I wrote this only for square kernels as I have no need for kernels that aren't square
cv::Mat xx (WinSize,WinSize,CV_64F);
for (int i=0;i<WinSize;i++){
    for (int j=0;j<WinSize;j++){
        xx.at<double>(j,i) = (i-(WinSize-1)/2)*(i-(WinSize-1)/2);
    }
}
cv::Mat yy;
cv::transpose(xx,yy);
cv::Mat arg = -(xx+yy)/(2*pow(sigma,2));
cv::Mat h (WinSize,WinSize,CV_64F);
for (int i=0;i<WinSize;i++){
    for (int j=0;j<WinSize;j++){
        h.at<double>(j,i) = pow(exp(1),(arg.at<double>(j,i)));
    }
}
double minimalVal, maximalVal;
minMaxLoc(h, &minimalVal, &maximalVal);
cv::Mat tempMask = (h>DBL_EPSILON*maximalVal)/255;
tempMask.convertTo(tempMask,h.type());
cv::multiply(tempMask,h,h);

if (cv::sum(h)[0]!=0){h=h/cv::sum(h)[0];}

cv::Mat h1 = (xx+yy-2*(pow(sigma,2))/(pow(sigma,4));
cv::multiply(h,h1,h1);
h = h1 - cv::sum(h1)[0]/(WinSize*WinSize);
return h;
}

答案 2 :(得分:0)

您的函数和matlab版本之间存在一些差异: http://br1.einfach.org/tmp/log-matlab-vs-opencv.png

上面是matlab fspecial('log', 31, 6),下面是具有相同参数的函数的结果。不知何故,帽子更加弯曲&#39; - 这是打算在以后的处理中产生什么影响?

我可以创建一个与具有这些函数的matlab非常类似的内核,它直接反映了LoG公式:

float LoG(int x, int y, float sigma) {
    float xy = (pow(x, 2) + pow(y, 2)) / (2 * pow(sigma, 2));
    return -1.0 / (M_PI * pow(sigma, 4)) * (1.0 - xy) * exp(-xy);
}

static Mat LOGkernel(int size, float sigma) {
   Mat kernel(size, size, CV_32F);
   int halfsize = size / 2;
   for (int x = -halfsize; x <= halfsize; ++x) {
        for (int y = -halfsize; y <= halfsize; ++y) {
            kernel.at<float>(x+halfsize,y+halfsize) = LoG(x, y, sigma);
        }
   }
   return kernel;

}

答案 3 :(得分:0)

这是一个NumPy版本,直接从MATLAB中的fspecial函数翻译过来。

import numpy as np
import sys


def get_log_kernel(siz, std):
    x = y = np.linspace(-siz, siz, 2*siz+1)
    x, y = np.meshgrid(x, y)
    arg = -(x**2 + y**2) / (2*std**2)
    h = np.exp(arg)
    h[h < sys.float_info.epsilon * h.max()] = 0
    h = h/h.sum() if h.sum() != 0 else h
    h1 = h*(x**2 + y**2 - 2*std**2) / (std**4)
    return h1 - h1.mean()

答案 4 :(得分:0)

下面的代码与fspecial('log', p2, p3)完全等效:

def fspecial_log(p2, std):
   siz = int((p2-1)/2)
   x = y = np.linspace(-siz, siz, 2*siz+1)
   x, y = np.meshgrid(x, y)
   arg = -(x**2 + y**2) / (2*std**2)
   h = np.exp(arg)
   h[h < sys.float_info.epsilon * h.max()] = 0
   h = h/h.sum() if h.sum() != 0 else h
   h1 = h*(x**2 + y**2 - 2*std**2) / (std**4)
   return h1 - h1.mean()

答案 5 :(得分:0)

我知道这个话题很老,但是关于CV_User的答案,我有MATLAB实现:

sigma=3;
kernelSize=3;

lin = round(linspace(-floor(kernelSize/2),floor(kernelSize/2),kernelSize));

[X,Y] = meshgrid(lin,lin);

hg = exp(-(X.^2 + Y.^2)/(2*(sigma^2)));

kernel_t = hg.*(X.^2 + Y.^2-2*sigma^2)/(sigma^4*sum(hg(:)));

% make the filter sum to zero

kernel = kernel_t - sum(kernel_t(:))/kernelSize^2;

提供一个完全不同的结果,只有当sigma为1时,它才是相同的结果,才应该检查实现。

通过这种方式输入错字:

cv::Mat h1 = (xx+yy-2*(pow(sigma,2))/(pow(sigma,4)); and extra parenthesis is required 

答案 6 :(得分:0)

我在OpenCV中编写了Matlab fspecial函数的确切实现

功能:

Mat C_fspecial_LOG(double* kernel_size,double sigma)
{
    double size[2]={  (kernel_size[0]-1)/2   , (kernel_size[1]-1)/2};
    double std = sigma;
    const double eps = 2.2204e-16;
    cv::Mat kernel(kernel_size[0],kernel_size[1],CV_64FC1,0.0);
    int row=0,col=0;
    for (double y = -size[0]; y <= size[0]; ++y,++row)
    {
       col=0;
       for (double x = -size[1]; x <= size[1]; ++x,++col)
       {
            kernel.at<double>(row,col)=exp( -( pow(x,2)  +  pow(y,2)  )  /(2*pow(std,2)));
       }
    }

    double MaxValue;
    cv::minMaxLoc(kernel,nullptr,&MaxValue,nullptr,nullptr);
    Mat condition=~(kernel < eps*MaxValue)/255;
    condition.convertTo(condition,CV_64FC1);
    kernel = kernel.mul(condition);

    cv::Scalar SUM = cv::sum(kernel);
    if(SUM[0]!=0)
    {
       kernel /= SUM[0];
    }

    return kernel;
} 

此功能的用法:

double kernel_size[2] = {4,4};    // kernel size set to 4x4
double sigma =  2.1;
Mat kernel = C_fspecial_LOG(kernel_size,sigma);

将OpenCV结果与Matlab进行比较:

opencv结果:

[0.04918466596701741, 0.06170341496034986, 0.06170341496034986, 0.04918466596701741;
 0.06170341496034986, 0.07740850411228289, 0.07740850411228289, 0.06170341496034986;
 0.06170341496034986, 0.07740850411228289, 0.07740850411228289, 0.06170341496034986;
 0.04918466596701741, 0.06170341496034986, 0.06170341496034986, 0.04918466596701741]

fspecial('gaussian', 4, 2.1)的Matlab结果:

0.0492    0.0617    0.0617    0.0492
0.0617    0.0774    0.0774    0.0617
0.0617    0.0774    0.0774    0.0617
0.0492    0.0617    0.0617    0.0492