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
- Pré-processamento e Conversão para Tons de Cinza: Carrega-se uma imagem colorida, converte-a para tons de cinza e calcula seu histograma.
- 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.
- 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.
- 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 = 2ou3): 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
parforem MATLAB) para acelerar a otimização, especialmente em cenários de múltiplos limiares.