% APRENDIZAJE AUTOMÁTICO: UN ENFOQUE PRÁCTICO
% Autores: María Guijarro, P. Javier Herrera y Gonzalo Pajares
% Copyright RA-MA, 2010
% Capítulo 3: COMBINACIÓN DE CLASIFICADORES

function [] = clasificar(h,M,N,s,c,colores,pixel,g1,g2,g3)

global DATOS_CLASES;
global ClasesFuzzy ClasesBayes ClasesParzen;
global v_clas;
global I_clas;

% Variables del clasificador híbrido:
global ClasesYagerUnion ClasesYagerIntersec ClasesYagerUnInt ClasesYagerIntUn ClasesMaxRule ClasesMinRule ClasesMedianRule ClasesIntegralFuzzy ClasesMajorityVote;

% Fase de clasificación de imagenes:
m = 2;
barraprogreso % Crea la figura y determina el progreso

for ii=1:1:M
    for jj=1:1:N
        pixel(:) = I_clas(ii,jj,:);

        %%%%%%%%%%%%%%%%%%%%%% Fuzzy %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %Clasificador Fuzzy
        % calculo de los grados de pertenencia a cada una de las clases
        for i=1:1:c
            dd(i) = (1/sum((pixel - v_clas(i,:)).^2))^(2/(m-1));
        end

        SUMA = sum(dd);
        for i=1:1:c
            mu(i) = dd(i)/SUMA;
            FUZZY(ii,jj,i) = mu(i);  %matriz con los valores de las clases
        end

        [fila, col, valor] = find(mu == max(mu));
        if size(col,2) ~= 1
            columna = col(1,1);
        else
            columna = col;
        end
        ClasesFuzzy(ii,jj,:) = colores(columna,:);
        %%%%%%%%%%%%%%%%%%%%%% fin Fuzzy %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        %%%%%%%%%%%%%%%%%%%%%% Bayesiano %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %Clasificador Bayesiano
        % calculo de la distancia de Mahalonobis (dM)
        d = s; %dimensión de los datos
        for i=1:1:c
            dM(i) = (DATOS_CLASES(i).mediaBayes - pixel)*pinv(DATOS_CLASES(i).covarianzaBayes)*(DATOS_CLASES(i).mediaBayes - pixel)';
            pBayes(i) = 1/((2*pi)^(d/2)*abs(det(DATOS_CLASES(i).covarianzaBayes)))*exp(-0.5*dM(i));
            BAYES(ii,jj,i) = pBayes(i);  %matriz con los valores de las clases
        end

        SUMA = sum(pBayes);
        pBayes = pBayes/(SUMA+eps);  %normalización al rango [0,1]

        for i=1:1:c
            BAYES(ii,jj,i) = pBayes(i);  %matriz con los valores de las clases
        end


        [fila, col, valor] = find(pBayes == max(pBayes));
        if size(col,2) ~= 1
            columna = col(1,1);
        else
            columna = col;
        end
        ClasesBayes(ii,jj,:) = colores(columna,:);
        %%%%%%%%%%%%%%%%%%%%%% fin Bayesiano %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        %%%%%%%%%%%%%%%%%%%%%% Parzen %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %Clasificador de Parzen
        % calculo de las probabilidades
        for i=1:1:c
            n = DATOS_CLASES(i).numero_muestras;
            d = size(DATOS_CLASES(1).muestras,2); %dimensión de las muestras
            %K = (1/n)*(1/((2*pi)^d/2)*abs(det(DATOS_CLASES(i).covarianzaBayes))^(1/2)*h^d);
            K = 1;
            SumaExp = 0;
            for j=1:1:n
                p1 = K*exp(-1/(2*h^2)*(pixel-DATOS_CLASES(i).muestras(j,:))*pinv(DATOS_CLASES(i).covarianzaBayes)*(pixel - DATOS_CLASES(i).muestras(j,:))');
                SumaExp = SumaExp + p1;
            end
            Parzen(i) = SumaExp;
        end

        Sp = sum(Parzen);
        pParzen = Parzen/Sp;  %probabilidad restringida al rango [0,1]

        for i=1:1:c
            PARZEN(ii,jj,i) = pParzen(i);  %matriz con los valores de las clases
        end

        [fila, col, valor] = find(pParzen == max(pParzen));
        if size(col,2) ~= 1
            columna = col(1,1);
        else
            columna = col;
        end
        ClasesParzen(ii,jj,:) = colores(columna,:);
        %%%%%%%%%%%%%%%%%%%%%% fin Parzen %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        
        %%%%%%%%%%%%%%%%%%%%%% HIBRIDO %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        % Fase de agregación Fuzzy de operadores:
        %   utilizamos los datos del fuzzy clustering, Bayes y Parzen
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        % Hibridación de Fuzzy + Bayes + Parzen: son vectores que contienen
        a1 = pBayes; a2 = mu; a3 = pParzen;         

        %Yager (Bayes U Fuzzy) U Parzen  (U Union)
        p = 4;  % parámetro
        a = min(1,(a1.^p+a2.^p).^(1/p));
        a = min(1,(a.^p+a3.^p).^(1/p));
        columna = ObtenerColumna(a);
        ClasesYagerUnion(ii,jj,:) = colores(columna,:);

        %Yager (Bayes ^ Fuzzy) ^ Parzen (^ = intersección)
        p = 4;  % parámetro
        a = 1 - min(1,((1-a1).^p+(1-a2).^p).^(1/p));
        a = 1 - min(1,((1-a).^p+(1-a3).^p).^(1/p));
        columna = ObtenerColumna(a);
        ClasesYagerIntersec(ii,jj,:) = colores(columna,:);
          
        %Yager union (Bayes U Fuzzy) ^ Parzen  (U Union)
        p = 4;  % parámetro
        a = min(1,(a1.^p+a2.^p).^(1/p));
        a = 1 - min(1,((1-a).^p+(1-a3).^p).^(1/p));
        columna = ObtenerColumna(a);
        ClasesYagerUnInt(ii,jj,:) = colores(columna,:);
          
        %Yager union (Bayes ^ Fuzzy) U Parzen  (U Union)
        p = 4;  % parámetro
        a = 1 - min(1,((1-a1).^p+(1-a2).^p).^(1/p));
        a = min(1,(a.^p+a3.^p).^(1/p));
        columna = ObtenerColumna(a);
        ClasesYagerIntUn(ii,jj,:) = colores(columna,:);

        
        a1 = mu; a2 = pBayes; a3 = pParzen;       
        % generamos una matriz donde las filas son los resultados de cada clasificador y 
        % las columnas los valores por clases de cada clasificador
        
        P = [a1; a2; a3];
        
        % Max rule
        [fila, columna] = find(P == max(max(P))); 
        ClasesMaxRule(ii,jj,:) = colores(columna,:);
        
        % claculor del error
%         ErrorMax = ActualizarError(ErrorMax,columna,ii,jj);
        
        % Min rule
        [fila, columna] = find(P == max(min(P))); 
        ClasesMinRule(ii,jj,:) = colores(columna,:);
        
        % Median rule
        [fila, columna] = find(P == max(median(P))); 
        ClasesMedianRule(ii,jj,:) = colores(columna,:);

        %------------------------------------------------------------------
        %Integral fuzzy
        g = [g1 g2 g3]; % Estos tres valores los introduce el usuario. Valores por defecto: [0.8 0.2 0.5]
        gb = prod(g)*poly(-1./g);        % encontrar los coeficientes de p(lambda)
        gb(end-1:end) = gb(end-1:end)-1; % corregir las dos últimas
        gc = roots(gb);                  % encontraar las raices de p(lambda) = 0
        iii = (imag(gc) == 0) & (gc >= -1) & (abs(gc)>10^-10); 
        lambda = (gc(iii));               % encontrar lambda
        gF(1)= g(1);
        gF(2)= g(2)+gF(1)+lambda*g(2)*gF(1);
        gF(3)= g(3)+gF(2)+lambda*g(3)*gF(2);
        for k=1:1:c
            PD(k,1)= mu(k);
            PD(k,2)= pBayes(k);
            PD(k,3)= pParzen(k);
            sort(PD(k), 'descend');
        end
        for i=1:1:c
            gamma(i,1) = min(PD(i,1),g(1));
            gamma(i,2) = min(PD(i,2),g(2));
            gamma(i,3) = min(PD(i,3),g(3));
            max1= max(gamma(i,1), gamma(i,2));
            gamma(i,4)=max(max1, gamma(i,3));
        end
        for i=1:1:c
            gammaFinal(i)=gamma(i,4);
        end
        [fila, col, valor] = find(gamma(:,4) == max(gammaFinal));
        if size(fila,2) ~= 1
            filaF = fila(1,1);
        else
            filaF = fila;
        end
        ClasesIntegralFuzzy(ii,jj,:) = colores(filaF,:);
        errorIF=0;
        aciertoIF=0;
      %sort descend, coger todos los valores de fuzzy baye y parcen para hacer la pd  
        %------------------------------------------------------------------
        %
        
        % Majority vote
        % la columna indica la clase que elige cada clasificador 
        [fila, columna(1)] = find(a1 == max(max(a1)));
        [fila, columna(2)] = find(a2 == max(max(a2)));        
        [fila, columna(3)] = find(a3 == max(max(a3)));        
        
        % cómputo de los votos
        VotosClases = zeros(1,c);
        for i=1:1:3
          VotosClases(columna(i)) = VotosClases(columna(i)) + 1;
        end
        [fila, columna] = find(VotosClases == max(max(VotosClases)));
        
        [s1,s2] = size(columna);
        if s2 ~= 1
          % esto quiere decir que cada clasificador ha votado a tres clases
          % distintas, por tanto elegimos por ejemplo el de Bayes
          columna = columna(2);
        end
        % en este caso obtenemos la clase más votada
        ClasesMajorityVote(ii,jj,:) = colores(columna,:);
        %%%%%%%%%%%%%%%%%%%%%%% fin hibrido %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        
    end
    barraprogreso(ii/M) % actualiza figura
end