public MeshGridContainer meshgrid(int start, int end)
        {
            int meshgridheight = end - start + 1;
            int meshgridwidth  = end - start + 1;

            int[][] fx = new int[meshgridheight][];
            int[][] fy = new int[meshgridheight][];
            for (int i = 0; i < meshgridheight; i++)
            {
                fx[i] = new int[meshgridwidth];
                fy[i] = new int[meshgridwidth];
            }

            int row, col;

            row = start;
            for (int i = 0; i < meshgridheight; i++, row++)
            {
                col = start;
                for (int j = 0; j < meshgridwidth; j++, col++)
                {
                    fx[i][j] = col;
                    fy[i][j] = row;
                }
            }
            MeshGridContainer cont = new MeshGridContainer(end - start + 1, end - start + 1, end - start + 1, end - start + 1);

            cont.container1 = fx;
            cont.container2 = fy;

            return(cont);
        }
        public double[][][] createGabor(int[] or, int nn)
        {
            //or=param.OrientationsPerScale, n=param.ImageSize[0] + 2 * param.BoundaryExtension
            int Nscales  = or.Length;   //Nscales = 4
            int Nfilters = or.Sum();    //Nfilters = 32

            int[] n = new int[2];
            n[0] = nn;
            n[1] = nn;

            double[][] param = new double[Nfilters][];
            for (int i = 0; i < Nfilters; i++)
            {
                param[i] = new double[Nscales];
            }

            int l = 0;

            for (int i = 0; i < Nscales; i++)       //Nscales = 4
            {
                for (int j = 0; j < or[i]; j++)
                {
                    param[l][0] = .35;
                    param[l][1] = .3 / Math.Pow(1.85, (i));
                    param[l][2] = 16 * Math.Pow(or[i], 2) / (32 * 32);
                    param[l][3] = Math.PI / (or[i]) * (j);
                    l           = l + 1;
                }
            }

            //frequencies
            MeshGridContainer cont = new MeshGridContainer();
            int meshgridstart      = -(n[0] / 2);
            int meshgridend        = (n[0] / 2) - 1;

            cont = meshgrid(meshgridstart, meshgridend);

            int meshgridheight = meshgridend - meshgridstart + 1;
            int meshgridwidth  = meshgridend - meshgridstart + 1;

            double[][] fr = new double[meshgridheight][];
            for (int i = 0; i < meshgridheight; i++)
            {
                fr[i] = new double[meshgridwidth];
            }

            fr = fftshiftCreateGabor(meshgridwidth, meshgridheight, cont.container1, cont.container2);

            double[][] t = new double[meshgridheight][];
            for (int i = 0; i < meshgridheight; i++)
            {
                t[i] = new double[meshgridwidth];
            }

            t = fftshiftCreateGaborAngle(meshgridwidth, meshgridheight, cont.container1, cont.container2);


            // Transfer functions:

            //Allocate G();
            double[][][] G = new double[n[0]][][];
            for (int i = 0; i < n[0]; i++)
            {
                G[i] = new double[n[0]][];
                for (int j = 0; j < n[0]; j++)
                {
                    G[i][j] = new double[Nfilters];
                }
            }

            //Init G with 0
            for (int i = 0; i < n[0]; i++)
            {
                for (int j = 0; j < n[0]; j++)
                {
                    for (int k = 0; k < Nfilters; k++)
                    {
                        G[i][j][k] = 0;
                    }
                }
            }


            double[][] tr = new double[meshgridheight][];
            for (int i = 0; i < meshgridheight; i++)
            {
                tr[i] = new double[meshgridwidth];
            }

            for (int i = 0; i < Nfilters; i++)
            {
                ArrayAddParami(ref tr, t, param[i][3], meshgridheight, meshgridwidth);
                ArrayAddtr(ref tr, meshgridheight, meshgridwidth);
                ArrayAddG(ref G, tr, fr, param, i, n[1], meshgridheight, meshgridwidth);
            }

            //for(int j=0;j<meshgridheight;j++)
            //{
            //    for(int k=0;k<meshgridwidth;k++)
            //    {
            //        for (int i=0; i<Nfilters;i++)
            //        {
            //            tr[j][k] = t[j][k] + param[i][3];
            //            //tr[j][k] = tr[j][k] + 2 * Math.PI *isSmallerThanNPI(tr[j][k]) - 2 * Math.PI * isGreaterThanPI(tr[j][k]);

            //            //G[j][k][i] = Math.Exp(-10 * param[i][0] * Math.Pow((fr[j][k]/n[1]/param[i][1]-1),2) - 2 * param[i][2] * Math.PI * Math.Pow(tr[j][k],2)    );
            //        }
            //    }
            //}

            //Console.Write("{0} ", G[191][191][31]);

            return(G);
        }
        public double[][] TestPrefilt()
        {
            int bitmapImageWidth  = 2;
            int bitmapImageHeight = 2;

            double[][] a = new double[bitmapImageHeight][];
            a[0] = new double[] { .1, .2 };
            a[1] = new double[] { .3, .4 };
            //a[2] = new double[] { .9, 1.0, 1.1, 1.2 };
            //a[3] = new double[] { 1.3, 1.4, 1.5, 1.6 };

            int    w  = 1;
            int    fc = 4;
            double s1 = fc / Math.Sqrt(Math.Log(2.0));


            for (int i = 0; i < bitmapImageWidth; i++)
            {
                for (int j = 0; j < bitmapImageHeight; j++)
                {
                    a[i][j] = Math.Log(a[i][j] + 1);
                }
            }

            int sw = bitmapImageWidth + 2 * w;
            int sh = bitmapImageHeight + 2 * w;

            double[][] b = new double[sh][];
            for (int i = 0; i < sh; i++)
            {
                b[i] = new double[sw];
            }
            b = ProcessPadArray(a, bitmapImageHeight, bitmapImageWidth, w, w, "both");

            Console.Write("Printing b after first pad\n");
            Print2DArray(b, sw, sh);
            Console.WriteLine();

            int c = 1;
            int N = 1;
            int n = Math.Max(sw, sh);

            n = n + (n % 2);

            double[][] img = new double[sh + n - sw][];
            for (int i = 0; i < sh; i++)
            {
                img[i] = new double[sw + n - sh];
            }

            img = ProcessPadArray(b, sh, sw, n - sw, n - sh, "post");



            MeshGridContainer cont = new MeshGridContainer();
            int meshgridstart      = -(n / 2);
            int meshgridend        = (n / 2) - 1;

            cont = meshgrid(meshgridstart, meshgridend);

            int meshgridheight = meshgridend - meshgridstart + 1;
            int meshgridwidth  = meshgridend - meshgridstart + 1;

            double[][] gf = new double[meshgridheight][];
            for (int i = 0; i < meshgridheight; i++)
            {
                gf[i] = new double[meshgridwidth];
            }
            gf = fftshiftPrefilt(cont.container1_row, cont.container1_col, cont.container1, cont.container2, s1);
            Print2DArray(gf, meshgridheight, meshgridwidth);

            //skipping repmat()


            Complex[,] data = new Complex[sh, sw];

            data = fft2(img, sh, sw);

            //data = ifft2(data, sm, sn);

            for (int i = 0; i < sh; i++)
            {
                for (int j = 0; j < sw; j++)
                {
                    data[i, j] = data[i, j] * gf[i][j];
                }
            }
            data = ifft2(data, sh, sw);

            double[][] output = new double[sh][];
            for (int i = 0; i < sh; i++)
            {
                output[i] = new double[sw];
            }

            for (int i = 0; i < sh; i++)
            {
                for (int j = 0; j < sw; j++)
                {
                    output[i][j] = img[i][j] - data[i, j].Real;
                }
            }

            Console.Write("Priniting after whitening\n");
            Print2DArray(output, sh, sw);

            //end of whitening

            //Local contrast normalization

            double[][] outputSquare = new double[sh][];
            for (int i = 0; i < sh; i++)
            {
                outputSquare[i] = new double[sw];
            }

            for (int i = 0; i < sh; i++)
            {
                for (int j = 0; j < sw; j++)
                {
                    outputSquare[i][j] = Math.Pow(output[i][j], 2);
                }
            }

            data = fft2(outputSquare, sh, sw);
            for (int i = 0; i < sh; i++)
            {
                for (int j = 0; j < sw; j++)
                {
                    data[i, j] = data[i, j] * gf[i][j];
                }
            }

            data = ifft2(data, sh, sw);

            for (int i = 0; i < sh; i++)
            {
                for (int j = 0; j < sw; j++)
                {
                    outputSquare[i][j] = Math.Sqrt(Math.Abs(data[i, j].Real));
                    outputSquare[i][j] = .2 + outputSquare[i][j];
                    output[i][j]       = output[i][j] / outputSquare[i][j];
                }
            }

            Console.Write("Priniting after Local contrast normalization\n");
            Print2DArray(output, sh, sw);

            //Crop output to have same size than the input

            double[][] prefiltOut = new double[bitmapImageHeight][];
            for (int i = 0; i < bitmapImageHeight; i++)
            {
                prefiltOut[i] = new double[bitmapImageWidth];
            }

            for (int i = 0; i < bitmapImageHeight; i++)
            {
                for (int j = 0; j < bitmapImageWidth; j++)
                {
                    prefiltOut[i][j] = output[i + w][j + w];
                }
            }

            Console.Write("Priniting after croping\n");
            Print2DArray(prefiltOut, bitmapImageHeight, bitmapImageWidth);

            return(prefiltOut);
        }