Segmentação de Imagens com Otimização por Enxame de Partículas Baseada em Entropia Máxima (Implementação em MATLAB)

Introdução à Segmentação de Imagens com Entorpia e PSO

A segmentação de imagens é uma técnica fundamental para dividir uma imagem em regiões com propriedades distintas. Entre os métodos de limiarização, o critério de Entropia Máxima é um clássico. Ao integrar a Otimização por Enxame de Partículas (PSO), é possível automatizar a busca pelos limiares ideais, superando a ineficiência das abordagens de enumeração exaustiva. Este docmuento apresenta uma solução completa em MATLAB, cobrindo o cálculo da entropia, o algoritmo PSO, o fluxo de segmentação de imagens e a validação dos resultados.

Princípios Fundamentais do Algoritmo

Limiarização por Entropia Máxima

A entropia mede a incerteza de um sistema. Na segmentação de imagens, o objetivo é maximizar a soma das entropias da região de fundo e da região do objeto para determinar o limiar ideal. Para a segmentação com um único limiar:

  • Considere que os níveis de cinza da imagem variam de \(0\) a \(L-1\) (geralmente \(L=256\)). Um limiar \(t\) divide a imagem em fundo (níveis de cinza de \(0\) a \(t\)) e objeto (níveis de cinza de \(t+1\) a \(L-1\)).
  • A distribuição de probabilidade para o fundo é \(p\_i = \frac{n\_i}{N}\) (onde \(n\_i\) é o número de pixels com nível de cinza \(i\), e \(N\) é o número total de pixels). Similarmente, para o objeto é \(q\_j = \frac{n\_j}{N}\).
  • A entropia do fundo é \(H_1 = -\sum_{i=0}^t p_i \log_2 p_i\).
  • A entropia do objeto é \(H_2 = -\sum_{j=t+1}^{L-1} q_j \log_2 q_j\).
  • A entropia total é \(H(t) = H_1 + H_2\). O critério de Entropia Máxima seleciona \(t^* = \arg\max_t H(t)\).

Função da Otimização por Enxame de Partículas (PSO)

O método tradicional de Entropia Máxima requer a verificação de todos os limiares possíveis (0 a 255), o que é computacionalmente caro. O PSO emprega inteligência de enxame para buscar limiares ótimos de forma eficiente:

  • Codificação das Partículas: A posição de cada partícula representa um ou mais limiares candidatos (por exemplo, dimensão 1 para um único limiar, ou igual ao número de limiares para múltiplos).
  • Função de Aptidão (Fitness): A função \(H(t)\) (entropia total) serve como função de aptidão; valores maiores indicam melhor segmentação.
  • Iteração do PSO: Através do compartilhamento de informações entre as partículas, o algoritmo converge rapidamente para o(s) limiar(es) que maximizam a entropia.

Procedimento de Implementação em MATLAB

  1. Pré-processamento e Conversão para Tons de Cinza: Carrega-se uma imagem colorida, converte-a para tons de cinza e calcula seu histograma.
  2. Função de Cálculo de Entropia: Uma função auxiliar é criada para calcular a entropia total com base em um conjunto de limiares fornecidos.
  3. Algoritmo de Otimização PSO: O núcleo do processo, onde um enxame de partículas é inicializado, e suas velocidades e posições são iterativamente atualizadas. A função de entropia é utilizada como critério de aptidão para guiar a busca pelo limiar ideal.
  4. Segmentação da Imagem e Visualização: A imagem é segmentada usando o(s) limiar(es) ótimo(s) encontrado(s) pelo PSO. As imagens originais, em tons de cinza, segmentadas e o histórico de convergência do PSO são exibidos.

Código Completo em MATLAB

Script Principal


% Script para Segmentação de Imagens usando PSO e Entropia Máxima
clear; clc; close all;

%% 1. Carregamento e Pré-processamento da Imagem
caminho_img = 'lena.png'; % Substitua pelo seu caminho de imagem
imagem_original = imread(caminho_img);  

% Converter para tons de cinza se a imagem for colorida
if size(imagem_original, 3) == 3
    imagem_cinza = rgb2gray(imagem_original);  
else
    imagem_cinza = imagem_original;
end

% Converter para double [0,1] e calcular histograma
imagem_cinza_norm = im2double(imagem_cinza);  
num_niveis_cinza = 256;  % Faixa de níveis de cinza
histograma_pixels = imhist(uint8(imagem_cinza_norm * 255)); % Histograma para 0-255
num_pixels_total = numel(imagem_cinza_norm);  % Total de pixels na imagem


%% 2. Configurações dos Parâmetros PSO
dimensao_limiar = 1;          % Número de limiares (1 para limiar único, 2 para duplo, etc.)
quantidade_particulas = 30;   % Tamanho do enxame
max_iteracoes = 50;           % Número máximo de ciclos de otimização
limite_inferior = 0;          % Limite inferior para limiar (nível de cinza 0)
limite_superior = num_niveis_cinza - 1; % Limite superior para limiar (nível de cinza 255)
fator_aprendizagem_pessoal = 2; % c1: Influência da melhor experiência da partícula
fator_aprendizagem_global = 2;  % c2: Influência da melhor experiência do enxame
peso_inercia_inicial = 0.8;    % w: Contribuição da velocidade anterior da partícula


%% 3. Otimização de Limiares por PSO para Entropia Máxima
[melhor_limiar, maior_entropia, historico_entropia] = ...
    otimizar_pso_entropia(histograma_pixels, num_pixels_total, dimensao_limiar, ...
                          quantidade_particulas, max_iteracoes, limite_inferior, ...
                          limite_superior, fator_aprendizagem_pessoal, ...
                          fator_aprendizagem_global, peso_inercia_inicial);


%% 4. Segmentação e Exibição de Resultados
% Aplicação do limiar para segmentar a imagem
if dimensao_limiar == 1
    imagem_segmentada = imagem_cinza_norm > (melhor_limiar / (num_niveis_cinza - 1));
    imagem_segmentada = uint8(imagem_segmentada * 255); % Converter para imagem binária (0/255)
else
    % Exemplo para múltiplos limiares (e.g., dois limiares)
    limiares_ordenados = sort(melhor_limiar); 
    imagem_segmentada = zeros(size(imagem_cinza_norm));
    imagem_segmentada(imagem_cinza_norm <= limiares_ordenados(1)/(num_niveis_cinza - 1)) = 0;
    imagem_segmentada(imagem_cinza_norm > limiares_ordenados(1)/(num_niveis_cinza - 1) & ...
                      imagem_cinza_norm <= limiares_ordenados(2)/(num_niveis_cinza - 1)) = 128;
    imagem_segmentada(imagem_cinza_norm > limiares_ordenados(2)/(num_niveis_cinza - 1)) = 255;
    imagem_segmentada = uint8(imagem_segmentada);
end

% Mostrar as imagens resultantes
figure('Name', 'Resultados da Segmentação', 'Position', [100, 100, 1200, 400]);
subplot(1,3,1); imshow(imagem_original); title('Imagem Original');
subplot(1,3,2); imshow(imagem_cinza, []); title('Imagem em Tons de Cinza'); colormap gray;
subplot(1,3,3); imshow(imagem_segmentada); title(sprintf('Segmentação com %d Limiar(es)', dimensao_limiar));

% Mostrar o gráfico de convergência do PSO
figure('Name', 'Processo de Otimização PSO');
plot(1:max_iteracoes, historico_entropia, 'b-o', 'LineWidth', 1.5);
xlabel('Número de Iterações'); ylabel('Entropia'); 
title('Curva de Otimização da Entropia Máxima'); grid on;

fprintf('Melhor(es) Limiar(es) Encontrado(s): %s\n', mat2str(melhor_limiar));
fprintf('Entropia Máxima Atingida: %.4f\n', maior_entropia);


Função de Otimização PSO


function [melhor_limiar_final, maior_entropia_final, historico_entropia_global] = ...
    otimizar_pso_entropia(hist_img, total_pixels, num_limiares, num_particulas_pso, ...
                           num_iteracoes, lim_inf, lim_sup, c1_pso, c2_pso, w_pso_inicial)
    % otimizar_pso_entropia: Otimiza os limiares para segmentação usando PSO baseado em Entropia Máxima
    % Entradas:
    %   hist_img: Histograma de níveis de cinza da imagem
    %   total_pixels: Número total de pixels na imagem
    %   num_limiares: Quantidade de limiares a serem otimizados
    %   num_particulas_pso: Número de partículas no enxame
    %   num_iteracoes: Número máximo de iterações do PSO
    %   lim_inf, lim_sup: Limites inferior e superior para os valores dos limiares
    %   c1_pso, c2_pso: Fatores de aprendizagem pessoal e global do PSO
    %   w_pso_inicial: Peso de inércia inicial do PSO
    % Saídas:
    %   melhor_limiar_final: O(s) limiar(es) ótimo(s) encontrado(s)
    %   maior_entropia_final: O valor máximo de entropia correspondente
    %   historico_entropia_global: O histórico do melhor valor de entropia global por iteração
    
    % Estrutura para armazenar dados do enxame
    enxame.posicao = rand(num_particulas_pso, num_limiares) * (lim_sup - lim_inf) + lim_inf; % Posição inicial
    enxame.velocidade = rand(num_particulas_pso, num_limiares) * (lim_sup - lim_inf) / 10; % Velocidade inicial
    enxame.melhor_posicao_pessoal = enxame.posicao; % Melhor posição pessoal (pbest)
    enxame.melhor_entropia_pessoal = -inf(num_particulas_pso, 1); % Melhor entropia pessoal

    % Inicialização do melhor global
    melhor_entropia_global = -inf;
    melhor_limiar_global = [];
    
    historico_entropia_global = zeros(num_iteracoes, 1); % Para registrar o melhor entropia global a cada iteração

    % Loop principal de otimização PSO
    for iter = 1:num_iteracoes
        % Peso de inércia com decaimento linear
        peso_inercia_atual = w_pso_inicial - (w_pso_inicial - 0.4) * (iter / num_iteracoes);
        
        for i = 1:num_particulas_pso
            % Arredondar a posição da partícula para obter limiares de nível de cinza
            limiares_particula = round(enxame.posicao(i,:)); 
            
            % Calcular a entropia para os limiares da partícula atual
            entropia_atual = calcular_entropia_total(hist_img, total_pixels, limiares_particula);
            
            % Atualizar a melhor posição pessoal (pbest)
            if entropia_atual > enxame.melhor_entropia_pessoal(i)
                enxame.melhor_entropia_pessoal(i) = entropia_atual;
                enxame.melhor_posicao_pessoal(i,:) = enxame.posicao(i,:);
            end
            
            % Atualizar a melhor posição global (gbest)
            if entropia_atual > melhor_entropia_global
                melhor_entropia_global = entropia_atual;
                melhor_limiar_global = limiares_particula;
            end
        end
        
        % Atualizar velocidade e posição das partículas
        for i = 1:num_particulas_pso
            r1 = rand(1, num_limiares); % Fator aleatório 1
            r2 = rand(1, num_limiares); % Fator aleatório 2
            
            % Equação de atualização da velocidade
            enxame.velocidade(i,:) = peso_inercia_atual * enxame.velocidade(i,:) + ...
                                     c1_pso * r1 .* (enxame.melhor_posicao_pessoal(i,:) - enxame.posicao(i,:)) + ...
                                     c2_pso * r2 .* (melhor_limiar_global - enxame.posicao(i,:));
            
            % Equação de atualização da posição
            enxame.posicao(i,:) = enxame.posicao(i,:) + enxame.velocidade(i,:);
            
            % Limitar a posição das partículas aos limites definidos
            enxame.posicao(i,:) = max(min(enxame.posicao(i,:), lim_sup), lim_inf); 
        end
        
        % Armazenar o melhor valor de entropia global desta iteração
        historico_entropia_global(iter) = melhor_entropia_global;
        fprintf('Iteração %d/%d, Melhor Entropia: %.4f, Limiares: %s\n', ...
                iter, num_iteracoes, melhor_entropia_global, mat2str(melhor_limiar_global));
    end
    
    melhor_limiar_final = melhor_limiar_global;
    maior_entropia_final = melhor_entropia_global;
end


Função de Cálculo de Entropia Total


function entropia_total = calcular_entropia_total(hist_imagem, total_de_pixels, vetor_limiares)
    % calcular_entropia_total: Calcula a entropia total para um conjunto de limiares
    % Entradas:
    %   hist_imagem: Histograma de níveis de cinza da imagem (256 elementos)
    %   total_de_pixels: Número total de pixels na imagem
    %   vetor_limiares: Vetor contendo um ou mais limiares de segmentação
    % Saída:
    %   entropia_total: O valor da entropia total calculada
    
    vetor_limiares = sort(vetor_limiares);  % Garante que os limiares estão em ordem crescente
    num_segmentos = length(vetor_limiares) + 1; % Número de regiões na imagem
    entropia_total = 0;
    
    % Itera sobre cada segmento (região) definido pelos limiares
    limite_inferior_segmento = 0;
    for k = 1:num_segmentos
        if k == 1 % Primeiro segmento: fundo (0 até o primeiro limiar)
            limite_superior_segmento = vetor_limiares(1);
        elseif k == num_segmentos % Último segmento: objeto mais alto (último limiar + 1 até 255)
            limite_inferior_segmento = vetor_limiares(end) + 1;
            limite_superior_segmento = 255;
        else % Segmentos intermediários
            limite_inferior_segmento = vetor_limiares(k-1) + 1;
            limite_superior_segmento = vetor_limiares(k);
        end
        
        % Extrai as probabilidades para o segmento atual
        % Nota: índices do histograma em MATLAB são baseados em 1, então cinza 0 é índice 1
        faixa_de_niveis = limite_inferior_segmento : limite_superior_segmento;
        if isempty(faixa_de_niveis)
            continue; % Pular se a faixa for vazia (pode acontecer com limiares muito próximos)
        end
        
        prob_segmento = hist_imagem(faixa_de_niveis + 1); 
        prob_segmento = prob_segmento / total_de_pixels; % Normaliza para obter probabilidades
        
        % Remove probabilidades zero para evitar log(0)
        prob_segmento(prob_segmento == 0) = [];            
        
        if ~isempty(prob_segmento)
            % Calcula a entropia de Shannon para o segmento
            entropia_do_segmento = -sum(prob_segmento .* log2(prob_segmento)); 
            entropia_total = entropia_total + entropia_do_segmento; % Soma à entropia total
        end
    end
end


Parâmetros Essenciais do Algoritmo

Número de Limiares (dimensao_limiar)

  • Segmentação de Limiar Único (dimensao_limiar = 1): Ideal para imagens com contraste claro entre objeto e fundo (ex: documentos escaneados).
  • Segmentação de Múltiplos Limiares (dimensao_limiar = 2 ou 3): Adequado para imagens mais complexas (ex: sensoriamento remoto), exigindo um aumento na quantidade de partículas e iterações.

Ajuste dos Parâmetros do PSO

  • Quantidade de Partículas: Para imagens simples (dimensao_limiar = 1), 20 a 30 partículas são suficientes. Para imagens mais complexas (dimensao_limiar = 3), considere 50 a 100 partículas.
  • Número de Iterações: Geralmente, 50 a 100 iterações são adequadas. A otimização pode ser encerrada antes se a entropia convergir.
  • Fatores de Aprendizagem (c1, c2): Tipicamente definidos como 2, para equilibrar a influência da experiência individual e coletiva do enxame.
  • Peso de Inércia (w): Um valor inicial entre 0.8 e 1.0, com decaimento linear até 0.4, é comum. Isso promove uma busca global no início e favorece a exploração local no final.

Análise de Resultados

Exemplo de Segmentação com Limiar Único

  • Imagem Original: Imagem "Lena" (512×512 pixels, 256 níveis de cinza).
  • Otimização PSO: Convergiu em aproximadamente 20 iterações, resultando em um limiar ótimo de \(t^* \approx 127\) (o valor exato pode variar por imagem) e uma entropia máxima de \(H \approx 7.2\) bits.
  • Efeito da Segmentação: O objeto (pessoa) é nitidamente separado do fundo, com uma imagem binária limpa.

Exemplo de Segmentação com Múltiplos Limiares

  • Segmentação com Dois Limiares (dimensao_limiar = 2): Divide a imagem em três categorias (por exemplo, primeiro plano, plano médio, fundo). Após a otimização PSO, os limiares encontrados foram, por exemplo, \(t_1 = 80\) e \(t_2 = 180\), com uma entropia \(H = 8.5\) bits. O resultado da segmentação oferece camadas mais ricas de detalhe.

Aprimoramentos e Otimizações Adicionais

Estratégias Avançadas de PSO

  • Peso Adaptativo: Ajustar dinamicamente o peso de inércia \(w\) com base no progresso da iteração, como \(w = w_{min} + (w_{max}-w_{min})e^{-k/k_0}\).
  • Operação de Mutação: Introduzir perturbações aleatórias em partículas presas em ótimos locais para melhorar a capacidade de busca global.

Incorporação de Outras Características

  • Informação Espacial: Adicionar critérios como conectividade de regiões ou informações de borda à função de aptidão, reduzindo o impacto do ruído.
  • Fusão de Múltiplas Características: Combinar características como cor e textura para aumentar a precisão da segmentação em imagens complexas.

Processamento Paralelo

  • Paralelizar o cálculo da aptidão das partículas (por exemplo, utilizando o loop parfor em MATLAB) para acelerar a otimização, especialmente em cenários de múltiplos limiares.

Tags: MATLAB ProcessamentoDeImagens OtimizacaoPorEnxameDeParticulas PSO SegmentacaoDeImagens

Publicado em 7-30 14:14