简体   繁体   English

如何轻松地将高斯滤波器应用于双精度列表/数组

[英]How to easily apply a Gauss filter to a list/array of doubles

My code works already, but IMHO ugly:我的代码已经工作,但恕我直言丑陋:

public IList<OxyPlot.DataPoint> Points { get; private set; }
public IList<OxyPlot.DataPoint> Points2 { get; private set; }

void ApplyGaussFilter()
{
    var gauss = MathNet.Numerics.Window.Gauss(5, 0.8);
    Points2 = new List<OxyPlot.DataPoint>();
    var inputArray = Points.ToArray();

    for (int i=2; i< inputArray.Length-2; ++i)
    {
        double smoothedVal = (inputArray[i - 2].Y * gauss[0] +
                      inputArray[i - 1].Y * gauss[1] +
                      inputArray[i].Y * gauss[2] +
                      inputArray[i + 1].Y * gauss[3] +
                      inputArray[i + 2].Y * gauss[4]) / gauss.Sum();

        Points2.Add(new DataPoint(inputArray[i].X, smoothedVal));
    }
}

平滑测量

Is there an easier way?有更容易的方法吗? Additionally I don't know how to correctly handle the two outer most array values.另外我不知道如何正确处理两个最外面的数组值。 And for changing the Gauss width from 5 to any other value, the for loop needs to be manually updated as well.并且要将高斯宽度从 5 更改为任何其他值,也需要手动更新 for 循环。

All examples I have found so far are based on images to filter these.到目前为止我发现的所有例子都是基于图像来过滤这些的。 EG guassian smoothening formula application . EG guassian 平滑公式应用
Applying the filter with image libraries with two lines of code looks much nicer compared to my ugly for loop.与我丑陋的 for 循环相比,使用带有两行代码的图像库应用过滤器看起来要好得多。

GaussianBlur filter = new GaussianBlur(4, 11);
filter.ApplyInPlace(graph);

I tried to get MathNet.Numerics.Window.Gauss() to work, but I couldn't.我试图让MathNet.Numerics.Window.Gauss()工作,但我不能。 Maybe I am doing something wrong, but I have found other solutions that work for me, for example this one:也许我做错了什么,但我找到了其他适合我的解决方案,例如这个:

private static double[] gaussianKernel1d( int kernelRadius, double sigma )
{
    double[] kernel = new double[kernelRadius + 1 + kernelRadius];
    for( int xx = -kernelRadius; xx <= kernelRadius; xx++ )
        kernel[kernelRadius + xx] = Math.Exp( -(xx * xx) / (2 * sigma * sigma) ) /
                (Math.PI * 2 * sigma * sigma);
    return kernel;
}

Once you have that, one-dimensional gaussian filtering can be achieved as follows:一旦你有了,一维高斯滤波可以实现如下:

double[]  array        = (your array)
double    sigma        = (your sigma)
int       kernelRadius = (int)Math.Ceiling( sigma * 2.57 ); // significant radius
double[]  kernel       = gaussianKernel1d( kernelRadius, sigma );
double[]  result       = filter( array, kernel );

static double[] filter( double[] array, double[] kernel )
{
    Assert( kernel.Length % 2 == 1 ); //kernel size must be odd.
    int       kernelRadius = kernel.Length / 2;
    int       width  = array.GetLength( 0 );
    double[] result = new double[width];
    for( int x = 0; x < width; x++ )
    {
        double sumOfValues  = 0;
        double sumOfWeights = 0;
        for( int i = -kernelRadius; i <= kernelRadius; i++ )
        {
            double value = array[clamp( x + i, 0, width - 1 )];
            double weight = kernel[kernelRadius + i];
            sumOfValues  += value * weight;
            sumOfWeights += weight;
        }
        result[x] = sumOfValues / sumOfWeights;
    }
    return result;
}

The clamp() function is this little thing: clamp()函数是这个小东西:

private static int clamp( int value, int min, int max )
{
    if( value < min )
        return min;
    if( value > max )
        return max;
    return value;
}

and it ensures that the value at the boundary of your data will be used in place of any values that lie beyond that boundary.并确保使用数据边界处的值代替超出该边界的任何值。 This is one way of handling what you are referring to as your "two outer most array values".这是处理您所说的“两个最外层数组值”的一种方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM