segunda-feira, 4 de abril de 2016

Eigenfaces - Implementação Final

Eigenfaces procura implementar um sistema capaz, eficiente, simples e com acurácia para reconhecimento facial. O sistema não depende de conhecimento intuitivo da estrutura da face, como por exemplo olhos, nariz e boca. A motivação por trás do Eigenfaces é que trabalhos anteriores ignoram a questão de quais características são importante para a classificação ou não. O Eigenfaces procura essa resposta usando PCA das imangens dos rostos. Essa análise reduz a dimensionalidade do conjunto de teste deixando apenas as carecterísticas que são críticas para o reconhecimento facial.

Esse sistema é inicializado por uma base de treinamento, que idealmente tem que ter um número variado de exemplos com variação de luz e expressões. Eigenvectors e eigenvalues são computados pela matriz de convariância da base de treinamento. Os M maiores eigenvectors são mantidos. Finalmente, os indivíduos conhecidos são projetados dentro de um espaço vetorial, e seus pesos são armazenados.

O Eigenfaces que foi implementado por mim, foi implementado em Java e foi testado com oito imagens. O método mais importante da minha implementação está abaixo:


/** Cálculo do eigenfaces usando uma técnica matemática para facilitar o cálculo do eigenfaces com alta
* dimensionalidade. Ao fim do método os eigenfaces são visualizados em imagens
**/
public void eigenfacesImplementation(ArrayList<double[]> dados){
double[][] auxDados= arrayListToDouble(dados);
Matrix dadosMatrix = new Matrix(auxDados);
Matrix w=new Matrix(dados.get(0).length, dados.size(), 0.0);
        double[] average = new double[dados.get(0).length];
        for(int i = 0; i < dados.get(0).length; i++){
            average[i]=0;
            for(int j = 0; j < dados.size(); j++){
                average[i] = average[i] + dadosMatrix.get(i,j);
            }
            average[i]=average[i]/((double)dados.size());
            //System.out.println(average[i]);
        }


        for(int i=0;i<dados.get(0).length;i++){
            for(int j=0;j<dados.size();j++){
                w.set(i, j, dadosMatrix.get(i,j) - average[i]);
            }
        }

        Matrix auxMat = w.transpose().times(w); // = w'*w
        
        SingularValueDecomposition SVD =  new SingularValueDecomposition(auxMat);
        double[] mu = SVD.getSingularValues(); // Eigenvalues of w'w
        Matrix d=SVD.getU(); // LeftSingularVectors of w'w => Each column is an eigenvector
        Matrix e=w.times(d); // Eigenvector of ww'
       
        Matrix eigenfaces = new Matrix(w.getRowDimension(), w.getColumnDimension(), 0.0);
        double[] auxArray=new double[w.getRowDimension()];
        for(int i = 0; i < w.getColumnDimension(); i++){
            for(int j = 0; j < w.getRowDimension(); j++) auxArray[j] = e.get(j, i);
            Matrix eNormalized = normalize(e);
            for(int j = 0;j < w.getRowDimension(); j++) eigenfaces.set(j,i, eNormalized.get(j, i)); // eigenfaces are the normalized eigenvectors of ww'
        }
       
        /** SALVANDO EIGENFACES COMO IMAGENS **/
double[][] teste = eigenfaces.getArray();
double[] min = new double[teste[0].length];
double[] max = new double[teste[0].length];
for(int i = 0; i < min.length; i++){
min[i] = Double.MAX_VALUE;
max[i] = 0;
}
for(int i = 0; i < teste[0].length; i++){
for(int j = 0; j < teste.length; j++){
if(min[i] > teste[j][i])
min[i] = teste[j][i];
if(max[i] < teste[j][i])
max[i] = teste[j][i];
}
}
for(int i = 0; i < teste[0].length; i++){
for(int j = 0; j < teste.length; j++){
teste[j][i] = ((teste[j][i] - min[i])/(max[i] - min[i])) * 255;
}
}
int[][][] imagem = new int[teste[0].length][width][height];
for(int i = 0; i < teste[0].length; i++){
int index = 0;
for(int j = 0; j < width; j++){
for(int k = 0; k < height; k++){
imagem[i][j][k] = (int) teste[index][i]; //olhar isso
index++;
}
}
}
salvarImagem(imagem[0], "extra/imagem_final_1.png");
salvarImagem(imagem[1], "extra/imagem_final_2.png");
salvarImagem(imagem[2], "extra/imagem_final_3.png");
salvarImagem(imagem[3], "extra/imagem_final_4.png");
salvarImagem(imagem[4], "extra/imagem_final_5.png");
salvarImagem(imagem[0], "extra/imagem_final_6.png");
salvarImagem(imagem[1], "extra/imagem_final_7.png");
salvarImagem(imagem[2], "extra/imagem_final_8.png");
salvarImagem(imagem[3], "extra/imagem_final_9.png");
}

e as imagens obtidas por esse método são:










quarta-feira, 23 de março de 2016

Eigenfaces

Eigenfaces é uma técnica usada em problemas de visão computacional para reconhecimento de faces. Essa técnica usa um conjunto de eigenvectors para alcançar resultados para esses problemas. Eigenfaces pode ser gerado executando o processo matemático PCA, como foi visto nas outras postagens. Informalmente, Eigenfaces pode ser considerado um conjunto padronizado das partes importantes da face.

O primeiro passo para implementar o Eigenfaces é um conjunto S com M imagens, depois se obtém a média de cada imagem, então se subtrai as média das imagens. O próximo passo é procurar o conjunto de M ortonormal vetores que melhor descrevem a distribuição dos dados. Basicamente esse são os procedimentos.

Para meu caso, executei o Eigenfaces para três imagens. Estão as imagens originais seguidas dos Eigenfaces da imagens originais

:

















terça-feira, 15 de março de 2016

Recuperação dos Dados Originais PCA

Hoje, fiz a recuperação dos dados originais a partir dos dados finais do PCA. Mas antes de tudo acho importante explicar o processo de recuperação dos dados originais.

O passo final para chegar nos dados finais do PCA é dados da seguinte forma:

FinalData = RowFeatureVector x RowZeroMeanData

Onde RowFeatureVector é a matriz com os eigenvectors e RowZeroMeanData é a matriz transposta dos dados depois de ter a média subtraída. Para recuperar essa matriz transposta dos dados com a média subtraída devemos fazer:

RowZeroMeanData = RowFeatureVector^-1 x  FinalData

Onde RowFeatureVector^-1  é a matriz inversa de RowFeatureVector.

Logo, para recuperar os dados originais, o procedimento é o seguinte:

RowOriginalData = (RowFeatureVector^-1 x  FinalData) + OriginalMean

Esse é o processo para recuperação dos dados originais. Se reduzirmos a dimensionalidade, obviamente, quando os dados são reconstruídos perderemos alguma informação devido a redução de dimensionalidade. Como no meu caso eu não reduzi a dimensionalidade, meu resultado tem que ser igual aos dados originais, caso contrário, meus cálculos estão incorretos. O resultado que obtive foi:

Dados originais do Dataset ISIS:

5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
5.0,3.6,1.4,0.2,Iris-setosa
5.4,3.9,1.7,0.4,Iris-setosa
4.6,3.4,1.4,0.3,Iris-setosa
5.0,3.4,1.5,0.2,Iris-setosa
4.4,2.9,1.4,0.2,Iris-setosa
4.9,3.1,1.5,0.1,Iris-setosa
5.4,3.7,1.5,0.2,Iris-setosa
4.8,3.4,1.6,0.2,Iris-setosa
4.8,3.0,1.4,0.1,Iris-setosa
4.3,3.0,1.1,0.1,Iris-setosa
5.8,4.0,1.2,0.2,Iris-setosa
5.7,4.4,1.5,0.4,Iris-setosa
5.4,3.9,1.3,0.4,Iris-setosa
5.1,3.5,1.4,0.3,Iris-setosa
5.7,3.8,1.7,0.3,Iris-setosa
5.1,3.8,1.5,0.3,Iris-setosa
5.4,3.4,1.7,0.2,Iris-setosa
5.1,3.7,1.5,0.4,Iris-setosa
4.6,3.6,1.0,0.2,Iris-setosa
5.1,3.3,1.7,0.5,Iris-setosa
4.8,3.4,1.9,0.2,Iris-setosa
.
.
.
5.9,3.0,5.1,1.8,Iris-virginica



Dados originais recuperados do PCA sem as classes:

5.1 3.5 1.4 0.20000000000000007 
4.9 3.0 1.4 0.19999999999999996 
4.7 3.2 1.2999999999999994 0.19999999999999984 
4.6 3.1 1.4999999999999996 0.19999999999999973 
5.0 3.6 1.4 0.19999999999999996 
5.4 3.9 1.7000000000000002 0.40000000000000013 
4.6 3.4 1.4 0.30000000000000004 
5.0 3.4 1.4999999999999996 0.19999999999999996 
4.4 2.9 1.4 0.19999999999999973 
4.9 3.1 1.5000000000000004 0.09999999999999987 
5.4 3.7 1.5 0.19999999999999973 
4.8 3.4 1.6000000000000005 0.19999999999999984 
4.8 3.0 1.4000000000000004 0.10000000000000031 
4.300000000000001 3.0 1.1 0.09999999999999987 
5.8 4.0 1.2000000000000006 0.19999999999999984 
5.7 4.4 1.5 0.3999999999999999 
5.4 3.9 1.2999999999999998 0.40000000000000013 
5.1 3.5 1.4 0.30000000000000027 
5.7 3.8 1.7000000000000006 0.30000000000000016 
5.1 3.8 1.4999999999999996 0.29999999999999993 
5.4 3.4 1.7000000000000006 0.20000000000000007 
5.1 3.7 1.5 0.3999999999999999 
4.6 3.6 1.0 0.19999999999999996 
5.1 3.3 1.7000000000000002 0.5 
4.8 3.4 1.9000000000000004 0.19999999999999984 
.
.
.
5.9 3.0 5.1 1.8 


Como se pode observar, os dados foram recuperados corretamente, apenas com algumas diferenças no arrendondamento.

segunda-feira, 7 de março de 2016

Implementação FPCA

FPCA (Fractional PCA) é implementado da mesma forma que o PCA, a diferença é que a média subtraída de cada dimensão e cada instância das dimensṍes são elevados a um valor real r.

Seguindo o mesmo processo do PCA, os dados obtidos foram plotados nas imagens abaixo.

Dimensão 1:

Dimensão 2:

Dimensão 3:

Dimensão 4:

Como se pode observar os dados sofreram uma mudança na escala e na distribuição. Os artigos lidos para chegar a esses cálculos e conclusões sobre o funcionamento e a implementação do FPCA foram:

FRACTIONAL EIGENFACES T.B.A. de Carvalho, M.A.A. Sibaldo, I.R. Tsang, G.D.C. Cavalcanti, I.J. Tsang and J. Sijbers

Theory of fractional covariance matrix and its applications in PCA and 2D-PCA Chaobang Gao, Jiliu Zhou, Qiang


sábado, 5 de março de 2016

Implementação PCA

PCA é uma técnica de estatística muito usada em aplicações de reconhecimento facial e compressão de imagem, e é uma técnica usada para achar padrões em dados de alta dimensão (Smith, 2002).
 A base de dados usada para os teste nessa fase da pesquisa é a IRIS, que é uma base com 4 dimensões, 150 instâncias e 3 classes.

O PCA pode ser dividido em passos, e eles são:

1- Pegar alguns dados

2- Calcular a média de cada dimensão e subtrair essa média de cada dimensão a que a média é referente. Por exemplo, se a base de dados tiver 4 dimensões, então será encontrado 4 médias, uma referente a dimensão 1, outra a dimensão 2 e assim por diante. Então, a média da dimensão 1 é subtraída de cada elemento da dimensão 1, e o mesmo processo é repetido para as outras dimensões.

3- Calcular a matriz de covariância da base de dados.

4- Calcular a partir da matriz de covariância os eigenvectors e os eigenvalues. Uma vez calculado os eigenvectors e os eigenvalues, o eigenvector com o maior eigenvalue é o principal componente do conjunto de dados, portanto, se ordena os eigenvectors por ordem decrescente.

5- Escolher os componentes para formar o vetor de características, a partir dos eigenvectors, no caso de hoje eu não reduzi a dimensionalidade, ou seja, usei todos os eigenvectors.

6- Achar o novo conjunto de dados: DadosFinal = VetorDeCaracterísticas x DadosOriginaisComMédiaSubtraída.

Após seguir esses passos, usei a linguagem R para plotar cada dimensão em um gráfico para ver como ficou a distribuição dos dados.

Como dito antes, os eigenvectors são ordenados de forma decrescente, logo, o eigenvector com maior eigenvalue é o primeiro (o componente principal da base de dados), e isso pode ser observado nas imagens abaixo. Na imagem da dimensão 1 é possível ver as três classes separadas.


Dimensão 1:


 Dimensão 2:

Dimensão 3:

Dimensão 4: