Classificação de Imagens Hiperespectrais com PCA e MATLAB: Um Estudo de Caso com Indian Pines

Preparação e Limpeza do Conjunto de Dados

O processamento de imagens hiperespectrais requer inicialmente a reestruturação do cubo de dados tridimensional (linhas, colunas e bandas espectrais) para uma matriz tabular bidimensional. Nesta etapa, pixels de fundo que não contêm informações de classes válidas são isolados e removidos do espaço de amostragem para evitar ruído nas análises estatísticas subsequentes.

% Inicialização do ambiente de trabalho
clear; clc; close all;

% Importação do cubo hiperespectral e dos rótulos reais (ground truth)
raw_cube = load('Indian_pines.mat');
labels_raw = load('Indian_pines_gt.mat');
data_cube = raw_cube.indian_pines;
gt_labels = labels_raw.indian_pines_gt;

% Reestruturação para formato tabular (amostras x características)
[rows, cols, bands] = size(data_cube);
features_2d = reshape(data_cube, [rows * cols, bands]);
labels_1d = gt_labels(:);

% Filtragem de ruído de fundo (classe 0)
valid_idx = (labels_1d > 0);
X = features_2d(valid_idx, :);
y = labels_1d(valid_idx);

fprintf('Dimensão final do conjunto de dados: %d amostras, %d bandas\n', size(X, 1), size(X, 2));
fprintf('Distribuição de classes: %d categorias distintas\n', numel(unique(y)));

Análise de Componentes Principais (PCA)

A alta dimensionalidade dos dados hiperespectrais introduz redundância e o fenômeno conhecido como a maldição da dimensionalidade. A aplicação do PCA permite projetar os dados em um subespaço ortogonal de dimensão inferior, maximizando a variância retida. Em vez de calcular manualmente as matrizes de covariância, utilizamos a implementação otimizada nativa do ambiente.

% Padronização estatística (média 0, desvio padrão 1) e execução do PCA
X_norm = zscore(X);
[pca_coeff, pca_scores, ~, ~, pca_explained] = pca(X_norm);

% Cálculo da variância cumulativa
cumulative_var = cumsum(pca_explained) / 100;

% Visualização da distribuição de variância
figure('Name', 'Análise de Variância PCA', 'Position', [100, 100, 900, 400]);
tiledlayout(1, 2, 'TileSpacing', 'compact');

nexttile;
bar(pca_explained(1:40), 'FaceColor', '#0072BD');
title('Variância por Componente Individual');
xlabel('Índice do Componente Principal');
ylabel('Variância Explicada (%)');

nexttile;
plot(cumulative_var(1:40), '-o', 'LineWidth', 1.5, 'Color', '#D95319');
yline(0.95, 'r--', 'Limiar de 95%', 'LineWidth', 1.5);
title('Variância Explicada Cumulativa');
xlabel('Número de Componentes Retidos');
ylabel('Proporção Acumulada');

optimal_k_95 = find(cumulative_var >= 0.95, 1, 'first');
fprintf('Componentes necessários para reter 95%% da variância: %d\n', optimal_k_95);

Extração de Características e Configuração Experimental

Para avaliar empiricamente o impacto da redução de dimensionalidade no desempenho dos modelos preditivos, extraímos subconjuntos de dados contendo diferentes quantidades de componentes principais. Esses subespaços serão utilizados como entrada para os algoritmos de aprendizado de máquina.

% Definição do espaço de busca de hiperparâmetros (número de componentes)
k_values = [5, 10, 20, 30, 40, 50];
projected_data = cell(length(k_values), 1);

for i = 1:length(k_values)
    k = k_values(i);
    % Projeção ortogonal no subespaço de dimensão k
    projected_data{i} = X_norm * pca_coeff(:, 1:k);
end

Avaliação de Modelos Preditivos

A performance da redução de dimensionalidade é testada utiliznado algoritmos supervisionados. Dividimos os dados válidos em conjuntos de treinamneto e teste utilizando validação cruzada do tipo Hold-Out para garantir uma estimativa não enviesada da acurácia de generalização.

rng(123); % Garantia de reprodutibilidade estatística
cv_scheme = cvpartition(y, 'HoldOut', 0.3);

% Inicialização de uma tabela para armazenamento estruturado de métricas
metrics = table('Size', [length(k_values), 3], ...
                'VariableTypes', {'double', 'double', 'double'}, ...
                'VariableNames', {'K_Components', 'SVM_Accuracy', 'Tree_Accuracy'});

for i = 1:length(k_values)
    X_train = projected_data{i}(cv_scheme.training, :);
    y_train = y(cv_scheme.training);
    X_test = projected_data{i}(cv_scheme.test, :);
    y_test = y(cv_scheme.test);

    % Treinamento de Máquina de Vetores de Suporte Multi-classe (One-vs-One)
    mdl_svm = fitcecoc(X_train, y_train, 'Learners', 'svm', 'Coding', 'onevsone', 'Verbose', 0);
    pred_svm = predict(mdl_svm, X_test);

    % Treinamento de Árvore de Decisão (CART)
    mdl_tree = fitctree(X_train, y_train);
    pred_tree = predict(mdl_tree, X_test);

    % Consolidação das métricas de desempenho
    metrics.K_Components(i) = k_values(i);
    metrics.SVM_Accuracy(i) = sum(pred_svm == y_test) / numel(y_test);
    metrics.Tree_Accuracy(i) = sum(pred_tree == y_test) / numel(y_test);
end

disp('Resultados da Validação Cruzada:');
disp(metrics);

Visualização Analítica dos Resultados

A interpretação visual é crucial para compreender a relação entre a complexidade do modelo (número de componentes) e sua acurácia, bem como para analisar o custo computacional inerente ao treinamento de cada arquitetura.

figure('Name', 'Métricas de Classificação e Análise Latente', 'Position', [150, 150, 1100, 800]);
t = tiledlayout(2, 2, 'TileSpacing', 'compact', 'Padding', 'compact');

% Gráfico de Acurácia vs Dimensionalidade
nexttile;
plot(metrics.K_Components, metrics.SVM_Accuracy, '-s', 'LineWidth', 2, 'MarkerSize', 6);
hold on;
plot(metrics.K_Components, metrics.Tree_Accuracy, '-^', 'LineWidth', 2, 'MarkerSize', 6);
xlabel('Dimensão Reduzida (K)');
ylabel('Acurácia no Conjunto de Teste');
legend('SVM (RBF)', 'Árvore de Decisão', 'Location', 'southeast');
title('Desempenho Preditivo vs. Redução PCA');
grid on;

% Matriz de Confusão do Modelo Ótimo
[~, best_svm_idx] = max(metrics.SVM_Accuracy);
best_k = metrics.K_Components(best_svm_idx);

best_X_train = projected_data{best_svm_idx}(cv_scheme.training, :);
best_X_test = projected_data{best_svm_idx}(cv_scheme.test, :);
best_mdl = fitcecoc(best_X_train, y(cv_scheme.training), 'Learners', 'svm', 'Verbose', 0);
best_preds = predict(best_mdl, best_X_test);

nexttile;
cm = confusionchart(y(cv_scheme.test), best_preds);
cm.Title = sprintf('Matriz de Confusão SVM (K=%d)', best_k);
cm.RowSummary = 'row-normalized';
cm.ColumnSummary = 'column-normalized';

% Dispersão no Espaço Latente 2D
nexttile;
gscatter(pca_scores(:,1), pca_scores(:,2), y, 'lines', '.', 15);
title('Projeção no Espaço Latente (PC1 vs PC2)');
xlabel('Componente Principal 1');
ylabel('Componente Principal 2');
legend('off');

% Benchmark de Tempo de Treinamento
nexttile;
time_svm = zeros(length(k_values), 1);
time_tree = zeros(length(k_values), 1);
for i = 1:length(k_values)
    X_tr = projected_data{i}(cv_scheme.training, :);
    y_tr = y(cv_scheme.training);
    
    tic; fitcecoc(X_tr, y_tr, 'Learners', 'svm', 'Verbose', 0); time_svm(i) = toc;
    tic; fitctree(X_tr, y_tr); time_tree(i) = toc;
end
bar(metrics.K_Components, [time_svm, time_tree]);
xlabel('Dimensão Reduzida (K)');
ylabel('Tempo de Treinamento (segundos)');
legend('SVM', 'Árvore', 'Location', 'northwest');
title('Custo Computacional de Treinamento');
grid on;

Comparação Avançada de Algoritmos

Utilizando a dimensionalidade ótima identificada na etapa anterior, expandimos a avaliação para incluir uma gama mais ampla de classificadores, abrangendo métodos baseados em instâncias e algoritmos de ensemble.

fprintf('\n--- Avaliação Multialgoritmo com Dimensionalidade Ótima ---\n');

% Isolamento dos dados projetados com o melhor K
X_opt_train = projected_data{best_svm_idx}(cv_scheme.training, :);
y_opt_train = y(cv_scheme.training);
X_opt_test = projected_data{best_svm_idx}(cv_scheme.test, :);
y_opt_test = y(cv_scheme.test);

% Dicionário de funções de treinamento para diferentes arquiteturas
models = {
    'SVM Linear', @(X,Y) fitcecoc(X,Y, 'Learners', templateSVM('KernelFunction','linear'), 'Verbose', 0);
    'SVM RBF', @(X,Y) fitcecoc(X,Y, 'Learners', templateSVM('KernelFunction','rbf'), 'Verbose', 0);
    'Árvore CART', @(X,Y) fitctree(X,Y);
    'KNN (k=7)', @(X,Y) fitcknn(X,Y, 'NumNeighbors',7);
    'Random Forest', @(X,Y) TreeBagger(100, X, Y, 'Method', 'classification', 'OOBPredictorImportance', 'off')
};

final_report = table('Size', [size(models,1), 2], 'VariableTypes', {'string', 'double'}, 'VariableNames', {'Algoritmo', 'Acuracia'});

for idx = 1:size(models, 1)
    alg_name = models{idx, 1};
    train_func = models{idx, 2};
    
    % Treinamento do modelo
    trained_model = train_func(X_opt_train, y_opt_train);
    
    % Inferência e tratamento de saídas específicas (ex: cell arrays no TreeBagger)
    if strcmp(alg_name, 'Random Forest')
        raw_preds = predict(trained_model, X_opt_test);
        predictions = str2double(raw_preds);
    else
        predictions = predict(trained_model, X_opt_test);
    end
    
    % Cálculo da métrica de sucesso
    acc = mean(predictions == y_opt_test);
    final_report.Algoritmo(idx) = alg_name;
    final_report.Acuracia(idx) = acc;
    
    fprintf('%-15s : %.2f%%\n', alg_name, acc * 100);
end

Tags: MATLAB PCA Classificação de Imagens Indian Pines Aprendizado de Máquina

Publicado em 6-17 02:26