package ip.gui;

import math.Mat;


public final class Kernels {
    private Kernels() {
    }

    private static double robinsonScaleFactor = .25;

    // Robinson level 5 detector, see Pratt.
    public static float[][] getRobinson1() {
        float k[][] = {
            {1, 0, -1},
            {2, 0, -2},
            {1, 0, -1}
        };
        Mat.scale(k, robinsonScaleFactor);
        return k;
    }

    public static float[][] getRobinson2() {
        float k[][] = {
            {0, -1, -2},
            {1, 0, -1},
            {2, 1, 0}
        };
        Mat.scale(k, robinsonScaleFactor);
        return k;
    }

    public static float[][] getRobinson3() {
        float k[][] = {
            {-1, -2, -1},
            {0, 0, 0},
            {1, 2, 1}
        };
        Mat.scale(k, robinsonScaleFactor);
        return k;
    }

    public static float[][] getRobinson4() {
        float k[][] = {
            {-2, -1, 0},
            {-1, 0, 1},
            {0, 1, 2}
        };
        Mat.scale(k, robinsonScaleFactor);
        return k;
    }

    public static float[][] getRobinson5() {
        float k[][] = {
            {-1, 0, 1},
            {-2, 0, 2},
            {-1, 0, 1}
        };
        Mat.scale(k, robinsonScaleFactor);
        return k;
    }

    public static float[][] getRobinson6() {
        float k[][] = {
            {0, 1, 2},
            {-1, 0, 1},
            {-2, -1, 0}
        };
        Mat.scale(k, 0.25);
        return k;
    }

    public static float[][] getRobinson7() {
        float k[][] = {
            {1, 2, 1},
            {0, 0, 0},
            {-1, -2, -1}
        };
        Mat.scale(k, robinsonScaleFactor);
        return k;
    }

    public static float[][] getRobinson8() {
        float k[][] = {
            {2, 1, 0},
            {1, 0, -1},
            {0, -1, -2}
        };
        Mat.scale(k, robinsonScaleFactor);
        return k;
    }

    public static double getMagnitudeOfTheDerivativeOfGauss(
            double x, double y,
            double xc, double yc, double sigma) {
        ConvolutionUtils.t2 = Math.pow(2.0 * x - 2.0 * xc, 2.0);
        ConvolutionUtils.t3 = sigma * sigma;
        ConvolutionUtils.t4 = ConvolutionUtils.t3 * ConvolutionUtils.t3;
        ConvolutionUtils.t5 = ConvolutionUtils.t4 * ConvolutionUtils.t4;
        ConvolutionUtils.t6 = 1 / ConvolutionUtils.t5;
        ConvolutionUtils.t9 = Math.pow(x - xc, 2.0);
        ConvolutionUtils.t11 = Math.pow(y - yc, 2.0);
        ConvolutionUtils.t16 = Math.pow(Math.exp(-(ConvolutionUtils.t9 + ConvolutionUtils.t11) / ConvolutionUtils.t3 / 2), 2.0);
        ConvolutionUtils.t17 = Math.PI * Math.PI;
        ConvolutionUtils.t19 = ConvolutionUtils.t16 / ConvolutionUtils.t17;
        ConvolutionUtils.t22 = Math.pow(2.0 * y - 2.0 * yc, 2.0);
        double ddx = ConvolutionUtils.t2 * ConvolutionUtils.t6 * ConvolutionUtils.t19;
        double ddy = ConvolutionUtils.t22 * ConvolutionUtils.t6 * ConvolutionUtils.t19;
        ConvolutionUtils.t26 = Math.sqrt(ddx + ddy);
        ConvolutionUtils.t27 = ConvolutionUtils.t26 / 4;
        return ConvolutionUtils.t27;
    }

    public static void printMagnitudeOfTheDerivativeOfGauss(
            int M, int N,
            double sigma) {
        float k[][] = getMagnitudeOfTheDerivativeOfGauss(M, N, sigma);
        //Mat.printKernel(k,"MagnitudeOfTheDerivativeOfGauss"+k.length);
    }

    public static float[][] getMagnitudeOfTheDerivativeOfGauss(
            int M, int N,
            double sigma) {
        float k[][] = new float[M][N];
        int xc = M / 2;
        int yc = N / 2;
        for (int x = 0; x < k.length; x++)
            for (int y = 0; y < k[0].length; y++)
                k[x][y] = (float)
                        getMagnitudeOfTheDerivativeOfGauss(x, y, xc, yc, sigma);
        Mat.normalize(k);
        return k;
    }

    public static short[][] getMedian2x1() {
        short k[][] = {
            {0, 1, 0},
            {0, 1, 0},
            {0, 0, 0}
        };
        return k;
    }

    public static short[][] getMedian1x2() {
        short k[][] = {
            {0, 0, 0},
            {1, 1, 0},
            {0, 0, 0}
        };
        return k;
    }

    // p0 p1 p2
    // p3 p4 p5
    // p6 p7 p8
    //
    //
    public static short[][] getSizeDetector(short f[][]) {
        short a[][] = new short[f.length][f[0].length];
        int p[] = new int[9];
        int sum = 0;
        for (int x = 1; x < f.length - 1; x++)
            for (int y = 1; y < f[0].length - 1; y++) {
                sum = 0;
                p[0] = f[x - 1][y + 1];
                p[1] = f[x][y + 1];
                p[2] = f[x + 1][y + 1];
                p[3] = f[x - 1][y];
                p[4] = f[x][y];
                p[5] = f[x + 1][y];
                p[6] = f[x - 1][y - 1];
                p[7] = f[x][y - 1];
                p[8] = f[x + 1][y - 1];
                for (int i = 0; i < p.length; i++)
                    sum += p[i];
                if (sum > 255 * 5)
                    a[x][y] = 255;
                else
                    a[x][y] = 0;
            }
        return a;
    }

    public static float[][] getLaplacian5() {
        float k[][] = {
            {-1, -1, -1, -1, -1},
            {-1, -1, -1, -1, -1},
            {-1, -1, 24, -1, -1},
            {-1, -1, -1, -1, -1},
            {-1, -1, -1, -1, -1}
        };
        return k;
    }

    public static float[][] getLaplacian3() {
        float k[][] = {
            {0, -1, 0},
            {-1, 4, -1},
            {0, -1, 0}
        };
        return k;
    }

    public static float[][] getLaplacianPrewitt() {
        float k[][] = {
            {-1, -1, -1},
            {-1, 8, -1},
            {-1, -1, -1}
        };
        return k;
    }

    public static double laplaceOfGaussian(double x, double y,
                                           double xc, double yc, double sigma) {
        ConvolutionUtils.t1 = sigma * sigma;
        ConvolutionUtils.t2 = ConvolutionUtils.t1 * ConvolutionUtils.t1;
        ConvolutionUtils.t5 = Math.pow(x - xc, 2.0);
        ConvolutionUtils.t7 = Math.pow(y - yc, 2.0);
        ConvolutionUtils.t11 = Math.exp(-(ConvolutionUtils.t5 + ConvolutionUtils.t7) / ConvolutionUtils.t1 / 2);
        ConvolutionUtils.t13 = 1 / Math.PI;
        ConvolutionUtils.t16 = Math.pow(2.0 * x - 2.0 * xc, 2.0);
        ConvolutionUtils.t18 = 1 / ConvolutionUtils.t2 / ConvolutionUtils.t1;
        ConvolutionUtils.t20 = ConvolutionUtils.t11 * ConvolutionUtils.t13;
        ConvolutionUtils.t23 = Math.pow(2.0 * y - 2.0 * yc, 2.0);
        ConvolutionUtils.t26 = 1 / ConvolutionUtils.t2 * ConvolutionUtils.t11 * ConvolutionUtils.t13 - ConvolutionUtils.t16 * ConvolutionUtils.t18 * ConvolutionUtils.t20 / 8 - ConvolutionUtils.t23 * ConvolutionUtils.t18 * ConvolutionUtils.t20 / 8;
        return ConvolutionUtils.t26;
    }

    public static void printLaplaceOfGaussianKernel(
            int M, int N,
            double sigma) {
        float k[][] = getLaplaceOfGaussianKernel(M, N, sigma);
        //Mat.printKernel(k,"LaplaceOfGaussian"+k.length);
    }

    public static float[][] getLaplaceOfGaussianKernel(
            int M, int N,
            double sigma) {
        float k[][] = new float[M][N];
        int xc = M / 2;
        int yc = N / 2;
        for (int x = 0; x < k.length; x++)
            for (int y = 0; y < k[0].length; y++)
                k[x][y] = (float) laplaceOfGaussian(x, y, xc, yc, sigma);
        Mat.normalize(k);
        return k;
    }

    public static float[][] getLaplacian9() {
        float k[][] = {
            {-1, -1, -1, -1, -1, -1, -1, -1, -1},
            {-1, -1, -1, -1, -1, -1, -1, -1, -1},
            {-1, -1, -1, -1, -1, -1, -1, -1, -1},
            {-1, -1, -1, 8, 8, 8, -1, -1, -1},
            {-1, -1, -1, 8, 8, 8, -1, -1, -1},
            {-1, -1, -1, 8, 8, 8, -1, -1, -1},
            {-1, -1, -1, -1, -1, -1, -1, -1, -1},
            {-1, -1, -1, -1, -1, -1, -1, -1, -1},
            {-1, -1, -1, -1, -1, -1, -1, -1, -1}};
        return k;
    }

    public static float[][] getHat13() {
        float k [][] = {
            {0, 0, 0, 0, 0, -1, -1, -1, 0, 0, 0, 0, 0},
            {0, 0, 0, -1, -1, -2, -2, -2, -1, -1, 0, 0, 0},
            {0, 0, -2, -2, -3, -3, -4, -3, -3, -2, -2, 0, 0},
            {0, -1, -2, -3, -3, -3, -2, -3, -3, -3, -2, -1, 0},
            {0, -1, -3, -3, -1, 4, 6, 4, -1, -3, -3, -1, 0},
            {-1, -2, -3, -3, 4, 14, 19, 14, 4, -3, -3, -2, -1},
            {-1, -2, -4, -2, 6, 19, 24, 19, 6, -2, -4, -2, -1},
            {-1, -2, -3, -3, 4, 14, 19, 14, 4, -3, -3, -2, -1},
            {0, -1, -3, -3, -1, 4, 6, 4, -1, -3, -3, -1, 0},
            {0, -1, -2, -3, -3, -3, -2, -3, -3, -3, -2, -1, 0},
            {0, 0, -2, -2, -3, -3, -4, -3, -3, -2, -2, 0, 0},
            {0, 0, 0, -1, -1, -2, -2, -2, -1, -1, 0, 0, 0},
            {0, 0, 0, 0, 0, -1, -1, -1, 0, 0, 0, 0, 0}};
        return k;
    }


}