package registro;

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import senales.*;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2006</p>
 * <p>Company: </p>
 * @author not attributable
 * @version 1.0
 */


public class ImagenNormal extends basico {
    public void principal()
    {
        double I1[][] = LeeImagen("c:\\fie2\\alg_gen\\imagenes\\lena.jpg");
        //double I2[][] = LeeImagen("c:\\fie2\\alg_gen\\imagenes\\paztraslated.jpg");
        //double I2[][] = LeeImagen("c:\\fie2\\alg_gen\\imagenes\\pazskewed.jpg");
        //double I2[][] = LeeImagen("c:\\fie2\\alg_gen\\imagenes\\pazrotated.jpg");
        //double I2[][] = LeeImagen("c:\\fie2\\alg_gen\\imagenes\\pazscaled.jpg");
        //nr = 128; nc = 128;
        //double I1[][] = new double[nr][nc];
        double I2[][] = new double[nr][nc];
        double N1[][] = new double[nr][nc];
        double N2[][] = new double[nr][nc];
        double dif[][] = new double[nr][nc];
        double Pr[] = {nc/2, nc/2};
        //double T[] = {0, -1, 0, 1, 0, 0};
        double T[] = {0.7, 0, 30, 0, 0.7, 30};
        //double T[] = {1.2, 0.3, 10, 0.3, 1.2, 10};
        //double T[] = {1, 0, -20, 0, 1, -20};
        //double T[] = {0.9, 0, 0, 0, 0.9, 0};
        esc = 2;
        //creaImagenes(I1, I2);


        double Tf[][];
        int i,j, x, y;

        funciones.afinC(I1, I2, T);
        //Afines(I1, I2, T);



        Pr = Centroides(I2);
        Tf = Normaliza(I2, Pr);
        CalculaAfin(I2, N2, Tf, Pr);


        Pr = Centroides(I1);
        Tf = Normaliza(I1, Pr);
        CalculaAfin(I1, N1, Tf, Pr);

        /*

        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
                if(N1[i][j] > 0.5) System.out.println(i + " " + j);
        */

        GraficaImagen(I1, 0);
        GraficaImagen(I2, 1);

        GraficaImagen(N1, 2);
        GraficaImagen(N2, 3);
        GuardaImagen(I2, "origen.png");
        GuardaImagen(N2, "destino.png");

        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
                dif[i][j] = (N1[i][j] - N2[i][j])*(N1[i][j] - N2[i][j]);

        //GraficaImagen(dif, 1);
        GuardaImagen(dif, "dif.png");

    }

    public void creaImagenes(double I1[][], double I2[][])
    {
        for(int i=0; i<nr; i++)
            for(int j=0; j<nc; j++)
            {
              I1[i][j] = 0;
              I2[i][j] = 0;
            }

        I1[35][31] = 1.0;
        I1[35][52] = 1.0;
        I1[54][26] = 1.0;
        I1[51][47] = 1.0;
        I1[65][62] = 1.0;

        I2[56][5] = 1.0; I2[40][11] = 1.0; I2[55][41] = 1.0;
        I2[50][9] = 1.0; I2[50][10] = 1.0;
    }

    public void Afines(double I1[][], double I2[][], double T[])
    {
        int i, j, in, jn, mr=nr/2, mc = nc/2;
        double x, y;

        for(i=0; i<nc; i++)
            for(j=0; j<nc; j++)
            {

                x = T[0] * (j - mc) + T[1] * (i - mr) + T[2] + mc;
                y = T[3] * (j - mc) + T[4] * (i - mr) + T[5] + mr;

                jn = (int) x;
                in = (int) y;

                if(in >=0 && in <nr && jn >=0 && jn <nc)
                  I2[in][jn] = I1[i][j];
            }
    }

    public void CalculaAfin(double I1[][], double N1[][], double T[][], double Pr[])
    {
        int i, j;
        double x,y, Tf[][] = new double[2][2], det;

        det = T[0][0]*T[1][1] - T[0][1]*T[1][0];
        Tf[0][0] =  T[1][1]/det; Tf[0][1] = -T[0][1]/det;
        Tf[1][0] = -T[1][0]/det; Tf[1][1] = T[0][0]/det;

        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
            {
                x = (int)(Tf[0][0] *((double)j-nr/2) + Tf[0][1] *((double)i -nc/2) + Pr[0]);
                y = (int)(Tf[1][0] *((double)j-nr/2) + Tf[1][1] *((double)i -nc/2) + Pr[1]);


                N1[i][j] = funciones.bilineal(I1, x, y);
            }
    }

    public void CalculaAfin2(double I1[][], double N1[][], double Tf[][], double Pr[])
    {
        int i, j, x,y;

        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
            {
                x = (int)(Tf[0][0] *((double)j-Pr[0]) + Tf[0][1] *((double)i -Pr[1]) + nr/2);
                y = (int)(Tf[1][0] *((double)j-Pr[0]) + Tf[1][1] *((double)i -Pr[1]) + nc/2);
                if(x <nc && x >=0 && y <nr && y >=0)
                  N1[y][x] = I1[i][j];
            }
    }

    public double[][] Normaliza(double I[][], double Pr[])
    {
        double P[][] = new double[nr*nc][2];
        double In[][] = new double[nr][nc];
        int i, j, k=0;
        double suma =0;
        //, radio;
        double Tf[] = new double[6];

        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
            {
                P[k][0] = (double) j;
                P[k][1] = (double) i;
                //radio =(i-nr/2.0)*(i-nr/2.0) + (j-nc/2.0)*(j-nc/2.0);

                //if(radio < 100000) suma += I[i][j];
                //else I[i][j] =0;

                suma += I[i][j];

                k++;
        }

        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
                In[i][j] = I[i][j]/suma;

       double T[][] =Normal(P, 100, Pr, In);

       return T;
    }

    public double[][] Normal(double P[][], double C, double Pr[], double I[][])
    {
        double u20, u02, u11, l1, l2, d, u12, u21, u30, u03, t1, t2;
        double T[][] = new double[2][2], phi;
        double T2[][] = new double[2][2], Tf[][];
        int i, n = P.length;
        double Pn[][] = new double[n][2], Pc[][] = new double[n][2];
        double aux2[] = new double[2];
        double Cen[] = new double[2];
        Cen[0] = Pr[0]; Cen[1] = Pr[1];
        System.out.println("Centroides " + Cen[0] + " " + Cen[1]);

        u20 = Momento(P, Cen, I, 2, 0);
        u02 = Momento(P, Cen, I, 0, 2);
        u11 = Momento(P, Cen, I, 1, 1);
        System.out.println(u20 +" " + u02 + " " + u11);

        d = Math.sqrt((u20 - u02)*(u20 - u02) + 4.0*u11*u11);


        l1 = (u20 + u02 + d)/2.0;
        l2 = (u20 + u02 - d)/2.0;

        if(l1 < l2)
        {
            double aux = l2;
            l2 = l1;
            l1 = aux;
        }

        //C = Math.pow(l1*l2, 0.25);
        //System.out.println("C es igual a " + C);

        System.out.println(l1 + " " + l2);
        d = Math.sqrt((l1-u20)*(l1-u20) + u11*u11);

        T[0][0] = u11/d;      T[0][1] = (l1-u20)/d;
        T[1][0] = -(l1-u20)/d; T[1][1] = u11/d;

        System.out.println("Eigenvectores");

        System.out.println(T[0][0] + " " + T[0][1]);
        System.out.println(T[1][0] + " " + T[1][1]);

        System.out.println("eigenvalores " + C/Math.sqrt(l1) + " " + C/Math.sqrt(l2));

        T[0][0] *= C/Math.sqrt(l1);
        T[0][1] *= C/Math.sqrt(l1);
        T[1][0] *= C/Math.sqrt(l2);
        T[1][1] *= C/Math.sqrt(l2);

        System.out.println(T[0][0] + " " + T[0][1]);
        System.out.println(T[1][0] + " " + T[1][1]);
        System.out.println("Puntos Compactos");

        for(i=0; i<n; i++)
        {
            aux2[0] = P[i][0] - Cen[0];
            aux2[1] = P[i][1] - Cen[1];
            multiplica(T, aux2, Pc[i]);
        }

        //El conjunto compacto tiene centroide en Cero.

        Cen[0] = 0; Cen[1] = 0;

        u20 = Momento(Pc, Cen, I, 2, 0);
        u02 = Momento(Pc, Cen, I, 0, 2);
        u11 = Momento(Pc, Cen, I, 1, 1);
        u12 = Momento(Pc, Cen, I, 1, 2);
        u21 = Momento(Pc, Cen, I, 2, 1);
        u30 = Momento(Pc, Cen, I, 3, 0);
        u03 = Momento(Pc, Cen, I, 0, 3);

        t1 = C*C*(u12 + u30);
        t2 = C*C*(u03 + u21);

        phi = Math.atan(-t1/t2);
        if((-t1*Math.sin(phi) + t2*Math.cos(phi)) < 0) phi += Math.PI;

        System.out.println("Phi = " + phi);

        System.out.println(u20 +" " + u02 + " " + u11);

        System.out.println("Puntos Normalizados");

        T2[0][0] = Math.cos(phi); T2[0][1] = Math.sin(phi);
        T2[1][0] =-Math.sin(phi); T2[1][1] = Math.cos(phi);

        Tf = multiplica(T2, T);

        for(i=0; i<n; i++)
        {
            aux2[0] = P[i][0] - Pr[0];
            aux2[1] = P[i][1] - Pr[1];
            multiplica(Tf, aux2, Pn[i]);
        }

        u20 = Momento(Pn, Cen, I, 2, 0);
        u02 = Momento(Pn, Cen, I, 0, 2);
        u11 = Momento(Pn, Cen, I, 1, 1);
        System.out.println(u20 +" " + u02 + " " + u11);
        return Tf;
    }

    public void multiplica(double A[][], double b[], double resul[])
    {
        int n=A.length, m = A[0].length, l = b.length;
        int i, j, k;
        double suma;

        for(i=0; i<n; i++)
        {
            suma = 0;
            for (j = 0; j < m; j++)
                suma += A[i][j] * b[j];
            resul[i] = suma;
        }
    }

    public double[][] multiplica(double A[][], double b[][])
    {
        int n = A.length, m = A[0].length, r = b.length, s = b[0].length;
        int i, j, k;
        double suma=0, resul[][] = new double[n][s];
        System.out.println(n + " " + m + " " + r + " " +s);

        for (i = 0; i < n; i++) {
            for (j = 0; j < s; j++)
            {
                suma = 0;
                for (k = 0; k < m; k++)
                    suma += A[i][k] * b[k][j];

                resul[i][j] = suma;
            }
        }
        return resul;
    }


    public double[] Centroides(double P[][])
    {

        int i, j;
        double sx =0, sy = 0;
        double C[] = new double[2];
        double suma =0;

        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
                suma += P[i][j];

        for(i=0; i<nr; i++)
        {
            for(j=0; j<nc; j++)
            {
                sx += j*P[i][j]/suma;
                sy += i*P[i][j]/suma;
            }
        }

        C[0] = sx ;
        C[1] = sy ;

        return C;
    }

    public double Momento(double P[][], double C[], double f[][], int k, int l)
    {
        int i, j, kk, n = P.length;
        double sx, sy, suma = 0;

        kk = 0;

        for (i = 0; i < nr; i++)
            for (j = 0; j < nc; j++) {
                sx = Math.pow(P[kk][0] - C[0], k);
                sy = Math.pow(P[kk][1] - C[1], l);
                suma += sx * sy * f[i][j];
                kk++;
            }
        return suma;
    }
}
