Search code examples
javagaussianblur

Inaccurate result from gaussian function


I have this Gaussian function. which is not producing desired result. for that reason image cannot be blurred properly. In the bellow code I have taken the kernel size(5) and sigma value(1), which is same as I took in the link below. it would be very helpful if someone could point out the problem.

here is the link of of a website Gaussian kernle link

public class KernelDemo {

public double[][] Calculate(int lenght, double weight) {
    double[][] Kernel = new double[lenght][lenght];
    double sumTotal = 0;
    int kernelRadius = lenght / 2;
    double distance = 0;

    double calculatedEuler = 1.0 / (2.0 * Math.PI * Math.pow(weight, 2));

    for (int filterY = -kernelRadius; filterY <= kernelRadius; filterY++) {
        for (int filterX = -kernelRadius; filterX <= kernelRadius; filterX++) {
            distance = ((filterX * filterX) + (filterY * filterY)) / (2 * (weight * weight));

            Kernel[filterY + kernelRadius][filterX + kernelRadius] = calculatedEuler * Math.exp(-distance);

            sumTotal += Kernel[filterY + kernelRadius][filterX + kernelRadius];
        }
    }

    for (int y = 0; y < lenght; y++) {
        for (int x = 0; x < lenght; x++) {
            Kernel[y][x] = Kernel[y][x] * (1.0 / sumTotal);
        }
    }
    return Kernel;
}

public static void main(String args[]) {
    KernelDemo kd = new KernelDemo();
    double terms[][];
    terms = kd.Calculate(5,1);
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            System.out.print(terms[i][j]);
        }
        System.out.println();
    }

}
}

Solution

  • This is how I have handled generating a 2d Gaussian distribution kernel. The Kernel class is just a double[][] wrapped to enforce certain stipulations (e.g. squared array 5x5 7x7, and also ensures that the length is odd)

    public static Kernel generateBlurKernel(int length, double std){
        Kernel out = new Kernel(length);
    
        int center = length/2;
        for(int i=0;i<length;i++){
            for(int j=0;j<length;j++){
                int x = Math.abs(j-center);
                int y = Math.abs(i-center);
                out.setValueAt(j, i, ((1d/(2*Math.PI*std*std))*Math.pow(Math.E, -((x*x)+(y*y))/(2*std*std))));
            }
        }
        out.normalize();
        return out;
    } 
    

    In case you want it, here is my Kernel class too:

    public class Kernel {
    
        private final double[][] matrix;
    
        public Kernel(int sidelength){
            if((sidelength&1)==0)throw new IllegalArgumentException();
            matrix = new double[sidelength][sidelength];
        }
    
    
        public double getValueAt(int x, int y){
            return matrix[x][y];
        }
        public void setValueAt(int x, int y, double value){
            matrix[x][y] = value;
        }
        public double sum(){
            double sum = 0.0d;
            for(double[] da:matrix){
                for(double d:da){
                    sum+=d;
                }
            }
            return sum;
        }
        public double[][] getFullKernal(){
            return matrix;
        }
        public int getSideLegth(){
            return matrix.length;
        }
        public void normalize(){
            double normalizedConstant = 1d/sum();
            for(int i=0;i<matrix.length;i++){
                for(int j=0;j<matrix.length;j++){
                    matrix[i][j] = matrix[i][j]*normalizedConstant;
                }
            }
        }
    }