Sigmoidal
  • Home
  • Pós-Graduação
  • Blog
  • Sobre Mim
  • Contato
Sem Resultado
Ver Todos Resultados
  • English
  • Home
  • Pós-Graduação
  • Blog
  • Sobre Mim
  • Contato
Sem Resultado
Ver Todos Resultados
Sigmoidal
Sem Resultado
Ver Todos Resultados

Equalização de Histograma com OpenCV e Python

Carlos Melo por Carlos Melo
julho 16, 2024
em Python, Tutoriais, Visão Computacional
0
151
COMPARTILHAMENTOS
5k
VIEWS
Publicar no LinkedInCompartilhar no FacebookCompartilhar no Whatsapp

Histograma é um conceito que está presente direta ou indiretamente em praticamente todas as aplicações de visão computacional.

Afinal, ao ajustar a distribuição dos valores de pixel, conseguimos realçar os detalhes e revelar características até então ocultas na imagem original.

Na equalização do histograma, queremos o espectro completo de intensidades, distribuindo os valores de pixel mais uniformemente ao longo do eixo x.

Por isso, entender o conceito e aprender como aplicar a técnica, é fundamental para trabalhar em problemas de processamento digital de imagem.

Neste tutorial, você vai aprender a teoria, e como equalizar histogramas em imagens digitais usando OpenCV e Python.

💻

Código do Artigo

Acesse o código-fonte deste artigo gratuitamente.

Informe seu email para acessar o código:

✓ Seu código está pronto!

Abrir no Google Colab →

O que é um Histograma de Imagem

Um histograma de imagem é um tipo de representação gráfica que representa como as intensidades dos pixels de uma determinada imagem digital estão distribuídos.

Em termos simples, é o histograma que vai te dizer se uma imagem está corretamente exposta, se a iluminação está adequada e se o contraste permite ressaltar algumas características desejáveis.

Um histograma é uma representação gráfica de como a intensidade de valores de pixels é distribuída na sua imagem.
Um histograma é uma representação gráfica de como a intensidade de valores de *pixels* é distribuída na sua imagem (fonte).

Nós usamos histogramas para identificar assinaturas espectrais em imagens hiperspectrais de satélites – como distinguir entre plantações transgênicas e orgânicas.

Nós usamos histogramas para segmentar peças em uma esteira de fábrica – aplicando thresholding para isolar os objetos.

E olhando para diversos algoritmos como SIFT e HOG, o uso de histogramas de gradiente de imagem é fundamental para a detecção e descrição de características locais robustas.

Exemplos de pixels e seus valores de intensidade distribuídos no histograma (fonte).

Esta técnica é fundamental no processamento de imagens digitais e amplamente utilizada em diversos campos, incluindo a área médica, como em exames de raios X e tomografias computadorizadas (CT scans).

Além de ser uma ferramenta fundamental, uma vez que é muito simples de calcular, é uma alternativa bastante popular para aplicações que necessitam de processamento em tempo real.

Definição Formal

Um histograma de uma imagem digital f(x, y) cujas intensidades variam no intervalo [0, L - 1] é uma função discreta

    \[h(r_{k}) = n_{k},\]

onde r_k é o valor de intensidade k-ésimo e n_k é o número total de pixels em f com intensidade r_k. De forma semelhante, o histograma normalizado de uma imagem digital f(x, y) é

    \[p(r_{k}) = \frac{h(r_{k})}{MN} = \frac{n_k}{MN},\]

onde M e N são as dimensões da imagem (linhas e colunas, respectivamente). É uma prática comum dividir cada componente de um histograma pelo número total de pixels para normalizá-lo.

Uma vez que p(r_k) é a probabilidade de ocorrência de um dado nível de intensidade r_k em uma imagem, a soma de todos os componentes é igual a 1.

Como calcular um histograma

Calcular manualmente um histograma de imagens é um processo direto que envolve a contagem da frequência de cada valor de intensidade de pixel em uma imagem.

Apenas para fins didáticos, providenciei um pseudo-código e uma implementação usando o numpy para demonstrar como fazer isso.

Pseudo-código para calcular histogramas.

Primeiramente, inicializamos um vetor para armazenar o histograma com zeros. No caso, estou considerando uma imagem grayscale de 8 bits (2^8 = 256) valores possíveis para cada intensidade de pixel.

Em seguida, capturamos os atributos de altura e largura da imagem. Caso fosse necessário, poderíamos incluir ainda o atributo canais.

Então, percorremos cada pixel da imagem, incrementando a posição correspondente no vetor do histograma com base no valor de intensidade de cada pixel. Dessa forma, ao final do processo, o vetor de histograma conterá a contagem de ocorrências de cada nível de cinza na imagem, proporcionando uma representação clara da distribuição de intensidades na imagem.

Cálculo de Histograma no NumPy

A biblioteca NumPy possui a função np.histogram(), que permite calcular histogramas de dados de entrada. Esta função é bastante flexível e pode lidar com diferentes configurações de bins e intervalos.

numpy.histogram(
    a: np.ndarray,
    bins: Union[int, np.ndarray, str] = 10,
    range: Optional[Tuple[float, float]] = None,
    density: Optional[bool] = None,
    weights: Optional[np.ndarray] = None
) -> Tuple[np.ndarray, np.ndarray]

Veja o exemplo de utilização no código abaixo e perceba que quando usamos o np.histogram() para calcular o histograma de uma imagem grayscale, definimos o número de bins como 256 para cobrir todos os valores de intensidade de pixel de 0 a 255.

No entanto, antes é preciso entender como a biblioteca calcula os bins. O NumPy os calcula em intervalos como 0-0.99, 1-1.99, até 255-255.99. Na prática, isso significa que haverá 257 elementos no array de bins (pois passamos o argumento 256 na função).

Como não precisamos desse valor extra, afinal os valores de intensidade do pixel variam entre 0-255, podemos ignorá-lo.

import cv2
import numpy as np
import matplotlib.pyplot as plt

# Carrega uma foto em grayscale
image_path = "carlos_hist.jpg"
image = cv2.imread(image_path, 0)

# Calcule o histograma
hist, bins = np.histogram(image.flatten(), 256, [0, 256])

# Compute a função de distribuição acumulada
cdf = hist.cumsum()
cdf_normalized = cdf * hist.max() / cdf.max()

Inicialmente, nós carregamos e imagem carlos_hist.jpg em grayscale usando a flag 0 em cv2.imread(image_path, 0). Com a imagem carregada, nosso próximo passo é calcular o histograma. Utilizamos a função np.histogram() do NumPy para isso. Esta função conta a frequência de ocorrência de cada valor de intensidade de pixel.

Para entender melhor a distribuição das intensidades, também vamos calcular a função de distribuição acumulada (CDF). A CDF é essencial para técnicas como equalização de histograma.

# Plotar histograma e C.D.F.
fig, axs = plt.subplots(1, 2, figsize=(10, 5))

# Mostrar a imagem em grayscale
axs[0].imshow(image, cmap="gray", vmin=0, vmax=255)
axs[0].axis("off")

# Plotar o histograma e a CDF
axs[1].plot(cdf_normalized, color="black", linestyle="--", linewidth=1)
axs[1].hist(image.flatten(), 256, [0, 256], color="r", alpha=0.5)
axs[1].set_xlim([0, 256])
axs[1].legend(("CDF", "Histograma"), loc="upper left")

plt.show()

Agora, vamos visualizar o histograma e a CDF lado a lado usando Matplotlib e configurando a nossa figura com os subplots.

Visualmente, apenas olhando para a imagem, percebemos que a mesma parece “flat“, com pouco contraste. E isso de fato é corroborado pelo histograma à direita.

Como maioria dos valores de intensidade de pixel está concentrada em torno de 150, a imagem possui predominância de tons médios a claros, resultando em uma aparência menos vibrante e com pouca variação de contraste.

Equalização de Histograma para Imagens em Tons de Cinza

Como mencionamos no início do artigo, a equalização de histograma é uma técnica para ajustar o contraste de uma imagem, distribuindo os valores dos pixels de forma mais uniforme por toda a faixa de intensidade.

Existem várias técnicas possíveis, dependendo do contexto, quantidade de canais e aplicação. Nesta seção eu irei te mostrar como usar a função cv.equalizeHist() para realizar esse processo em imagens em tons de cinza.

cv2.equalizeHist(
    src: np.ndarray
) -> np.ndarray:

A função cv2.equalizeHist equaliza o histograma da imagem de entrada usando o seguinte algoritmo:

  1. Calcule o histograma ( H ) para src.
  2. Normalize o histograma de forma que a soma dos bins do histograma seja 255.
  3. Calcule o somatório do histograma:

        \[H'_i = \sum_{0 \leq j < i} H(j)\]

  4. Transforme a imagem usando ( H’ ) como uma tabela de consulta (look-up table):

        \[\text{dst}(x,y) = H'(\text{src}(x,y))\]

Para ver como essa função age para normalizar o brilho e aumentar o contraste da imagem original, vamos rodar o código abaixo.

# Aplica a equalização de histograma
equalized = cv2.equalizeHist(image)

# Cria uma figura com subplots para comparar as imagens
plt.figure(figsize=(30, 10))

# Mostrar imagem equalizada
plt.subplot(1, 3, 1)
plt.imshow(equalized, cmap='gray', vmin=0, vmax=255)
plt.title('Imagem Equalizada')

# Comparar histogramas original e equalizado
plt.subplot(1, 3, 2)
plt.hist(image.flatten(), 256, [0, 256])
plt.title('Histograma Original')
plt.subplot(1, 3, 3)
plt.hist(equalized.flatten(), 256, [0, 256])
plt.title('Histograma Equalizado')
plt.show()

Primeiro, aplicamos a equalização de histograma na imagem carregada usando a função cv2.equalizeHist. Em seguida, criamos uma figura com subplots para analisar o resultado final.

O primeiro subplot exibe a imagem equalizada, enquanto os dois subplots seguintes comparam os histogramas da imagem original e da imagem processada, usando plt.hist para plotá-los diretamente. Repare como a alteração da distribuição tornou a imagem mais agradável.

Equalização de Histograma para Imagens Coloridas

Se tentarmos realizar a equalização de histograma em imagens coloridas tratando cada um dos três canais separadamente, teremos um resultado ruim e inesperado.

O motivo é que, quando cada canal de cor é transformado de maneira não linear e independente, podem ser geradas cores completamente novas que não estão relacionadas de nenhuma maneira.

A maneira correta de realizar a equalização de histograma em imagens coloridas envolve uma etapa anterior, que é a conversão para um espaço de cor como o HSV, onde a intensidade está separada:

  1. Transforme a imagem para o espaço de cores HSV.
  2. Realize a equalização de histograma apenas no canal V (Valor).
  3. Transforme a imagem de volta para o espaço de cores RGB.
# Ler a astrofotografia
astrofoto = cv2.imread('astrofoto.jpg')

# Converter para o espaço de cores HSV
hsv_astrofoto = cv2.cvtColor(astrofoto, cv2.COLOR_BGR2HSV)

# Dividir os canais HSV
h, s, v = cv2.split(hsv_astrofoto)

Primeiro, carregamos uma nova imagem colorida usando cv2.imread. Então, convertemos a imagem carregada originalmente no formato BGR para o espaço de cores HSV com cv2.cvtColor e separamos as informações de cor (Hue e Saturation) da intensidade (Value) usando cv2.split(hsv_astrofoto).

# Equalizar o canal V (valor)
v_equalized = cv2.equalizeHist(v)

# Mesclar os canais HSV de volta, com o canal V equalizado
hsv_astrofoto = cv2.merge([h, s, v_equalized])

# Converter de volta para o espaço de cores RGB
astrofoto_equalized = cv2.cvtColor(hsv_astrofoto, cv2.COLOR_HSV2RGB)

Após aplicamos a equalização de histograma apenas ao canal V, mesclamos os canais HSV de volta, mas substituindo o canal V pelo canal equalizado.

A redistribuição de valores de intensidade no canal V melhorou significativamente o contraste da imagem, destacando detalhes que podiam estar obscurecidos.

No entanto, a equalização de histograma que acabamos de ver pode não ser a melhor abordagem em muitos casos, por considerar o contraste global da imagem. Em situações onde há grandes variações de intensidade, com pixels muito claros e muito escuros presentes, ou onde desejaríamos melhorar apenas uma região da imagem, esse método pode fazer com que percamos muitas informações.

Para lidar com esses problemas, vamos conhecer uma técnica mais avançada chamada Contrast Limited Adaptive Histogram Equalization (CLAHE).

Contrast Limited Adaptive Histogram Equalization (CLAHE)

Contrast Limited Adaptive Histogram Equalization (CLAHE) é uma técnica que divide a imagem em pequenas regiões chamadas “tiles“ e aplica a equalização de histograma em cada uma dessas regiões de forma independente.

Isso permite que o contraste seja melhorado localmente, preservando detalhes e reduzindo o ruído. Além disso, o método CLAHE tem a capacidade de limitar o aumento do contraste (daí o termo “Contrast Limited”), impedindo a amplificação do ruído que pode ocorrer na técnica regular.

cv2.createCLAHE(
    clipLimit: float = 40.0,
    tileGridSize: Optional[Tuple[int, int]] = (8, 8)
) -> cv2.CLAHE:

A implementação do CLAHE no OpenCV é feita usando a função createCLAHE(). Primeiro, um objeto CLAHE é criado com dois argumentos opcionais: clipLimit e tileGridSize.

Neste último exemplo, vamos usar uma foto que eu tirei com a minha esposa no Parque Nacional da Chapada dos Veadeiros, no estado de Goiás.

# Ler a imagem da chapada
chapada = cv2.imread('chapada.png')

# Converter para o espaço de cores HSV
chapada_hsv = chapada.copy()
chapada_hsv = cv2.cvtColor(chapada, cv2.COLOR_BGR2HSV)

# Criar um objeto CLAHE
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
chapada_hsv[:, :, 2] = clahe.apply(chapada_hsv[:, :, 2])

# Converter de volta para o espaço de cores RGB
chapada_equalized = cv2.cvtColor(chapada_hsv, cv2.COLOR_HSV2BGR)

Após carregar a imagem chapada.png, vamos converter para o espaço de cor HSV a fim de manter a consistência. Depois, aplicamos o CLAHE ao canal V usando a função cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)). Finalmente, convertemos a imagem de volta para o espaço de cores RGB para visualizar o resultado.


Na imagem original, havia uma região bem iluminada (cerca, árvore, e eu e minha esposa). Se tivéssemos optado pela equalização de histograma global, toda a imagem teria sido ajustada uniformemente, potencialmente levando à perda de detalhes em áreas muito claras ou muito escuras.

No entanto, ao usar o CLAHE, o algoritmo utilizou o contexto local, adaptando a quantidade de tiles para ajustar o contraste de cada pequena região da imagem individualmente. Isso preservou os detalhes tanto nas áreas claras quanto nas escuras, resultando em uma imagem final com contraste aprimorado e cores mais naturais.

Takeaways

  • Histograma de Imagem: Um histograma de imagem representa graficamente a distribuição das intensidades dos pixels, indicando se uma imagem está corretamente exposta e ajudando a realçar detalhes ocultos.
  • Utilização de Histogramas: Histogramas são usados para várias aplicações, incluindo a segmentação de peças em esteiras de fábrica, identificação de assinaturas espectrais em imagens hiperspectrais e detecção de características locais robustas com algoritmos como SIFT e HOG.
  • Definição Formal: O histograma de uma imagem digital é uma função discreta que conta a frequência de cada valor de intensidade de pixel, podendo ser normalizado para representar a probabilidade de ocorrência de cada nível de intensidade.
  • Equalização de Histograma em Tons de Cinza: A função cv2.equalizeHist() do OpenCV ajusta o contraste de uma imagem grayscale distribuindo os valores dos pixels de forma mais uniforme ao longo da faixa de intensidade.
  • Limitações da Equalização Global: A equalização de histograma global pode não ser ideal em casos com grandes variações de intensidade, pois pode levar à perda de informações em áreas muito claras ou escuras da imagem.
  • Equalização de Histograma em Imagens Coloridas: Ao tratar imagens coloridas, a equalização de histograma deve ser aplicada no canal de intensidade (V) do espaço de cores HSV para evitar a geração de cores não naturais.
  • CLAHE – Equalização de Histograma Adaptativa: CLAHE divide a imagem em pequenas regiões e aplica a equalização de histograma localmente, preservando detalhes e evitando a amplificação de ruído. Esta técnica é eficaz para melhorar o contraste de imagens com grandes variações de iluminação.

Cite este Post de Citação

Use a entrada abaixo para citar este post em sua pesquisa:

Carlos Melo. “Histogram Equalization with OpenCV and Python”, Sigmoidal.ai, 2024, https://sigmoidal.ai/equalizacao-de-histograma-com-opencv-e-python/.

@incollection{CMelo_EqualizacaoHistograma,
    author = {Carlos Melo},
    title = {Histogram Equalization with OpenCV and Python},
    booktitle = {Sigmoidal.ai},
    year = {2024},
    url = {https://sigmoidal.ai/equalizacao-de-histograma-com-opencv-e-python/},
}

 

Compartilhar11Compartilhar60Enviar
Post Anterior

Amazon Go: Visão Computacional em uma Loja sem Caixas

Próximo Post

O que é Visão Computacional — Data Hackers Episódio #92

Carlos Melo

Carlos Melo

Engenheiro de Visão Computacional graduado em Ciências Aeronáuticas pela Academia da Força Aérea (AFA) e Mestre em Engenharia Aeroespacial pelo Instituto Tecnológico de Aeronáutica (ITA).

Relacionado Artigos

Deep Learning

Gaussian Splatting: Reconstrução 3D em Tempo Real com Python

por Carlos Melo
abril 5, 2026
Matemática da Visão Computacional: Rotação, Translação e Escala com Python
Python

Matemática da Visão Computacional: Rotação, Translação e Escala com Python

por Carlos Melo
abril 4, 2026
Deep Learning

Introdução ao PyTorch: Como Treinar sua Primeira CNN

por Carlos Melo
abril 1, 2026
Artigos

Quanto ganha um Engenheiro de Visão Computacional

por Carlos Melo
março 31, 2026
Artigos

Analisando uma Tomografia 3D com Python

por Carlos Melo
março 28, 2026
Próximo Post
O que é Visão Computacional - Podcast Data Hackers

O que é Visão Computacional — Data Hackers Episódio #92

Deixe um comentário Cancelar resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Pós em Visão Computacional Pós em Visão Computacional Pós em Visão Computacional

Mais Populares

  • ORB-SLAM 3: Tutorial Completo para Mapeamento 3D e Localização em Tempo Real

    460 compartilhamentos
    Compartilhar 184 Tweet 115
  • Vision Transformer (ViT): Implementação com Python

    7 compartilhamentos
    Compartilhar 3 Tweet 2
  • Introdução ao MediaPipe e Pose Estimation

    552 compartilhamentos
    Compartilhar 221 Tweet 138
  • O Que é Amostragem e Quantização no Processamento de Imagens

    49 compartilhamentos
    Compartilhar 20 Tweet 12
  • Processamento de Nuvens de Pontos com Open3D e Python

    78 compartilhamentos
    Compartilhar 31 Tweet 20
  • Em Alta
  • Comentários
  • Mais Recente
Como Tratar Dados Ausentes com Pandas

Como Tratar Dados Ausentes com Pandas

agosto 13, 2019
Como usar o DALL-E 2 para gerar imagens a partir de textos

Como usar o DALL-E 2 para gerar imagens a partir de textos

dezembro 25, 2022
Introdução ao MediaPipe e Pose Estimation

Introdução ao MediaPipe e Pose Estimation

julho 15, 2023

ORB-SLAM 3: Tutorial Completo para Mapeamento 3D e Localização em Tempo Real

abril 10, 2023
Como Analisar Ações da Bolsa com Python

Como Analisar Ações da Bolsa com Python

15
Setembro Amarelo: Análise do Suicídio no Brasil, com Data Science

Setembro Amarelo: Análise do Suicídio no Brasil, com Data Science

13
Como Aprender Data Science?

Como Aprender Data Science?

9
Qual o Cenário de Data Science no Brasil hoje?

Qual o Cenário de Data Science no Brasil hoje?

8
5 Livros de Machine Learning e Data Science para 2026

5 Livros de Machine Learning e Data Science para 2026

abril 7, 2026

Gaussian Splatting: Reconstrução 3D em Tempo Real com Python

abril 5, 2026
Matemática da Visão Computacional: Rotação, Translação e Escala com Python

Matemática da Visão Computacional: Rotação, Translação e Escala com Python

abril 4, 2026

Introdução ao PyTorch: Como Treinar sua Primeira CNN

abril 1, 2026
Instagram Youtube LinkedIn Twitter
Sigmoidal

O melhor conteúdo técnico de Data Science, com projetos práticos e exemplos do mundo real.

Seguir no Instagram

Categorias

  • Aeroespacial
  • Artigos
  • Blog
  • Carreira
  • Cursos
  • Data Science
  • Deep Learning
  • Destaques
  • Entrevistas
  • IA Generativa
  • Livros
  • Machine Learning
  • Notícias
  • Python
  • Teoria
  • Tutoriais
  • Visão Computacional
  • Youtube

Navegar por Tags

camera calibration carreira chatgpt cientista de dados cnn computer vision Cursos dados desbalanceados data science data science na prática decision tree deep learning deploy detecção de objetos gpt-3 IA generativa image formation inteligência artificial jupyter kaggle keras livros machine learning matplotlib mnist nft openai opencv pandas processamento de imagens profissão python pytorch redes neurais redes neurais convolucionais regressão linear regressão logística salário sklearn tensorflow tutorial visão computacional vídeo youtube árvore de decisão

© 2024 Sigmoidal - Aprenda Data Science, Visão Computacional e Python na prática.

Welcome Back!

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In

Add New Playlist

Sem Resultado
Ver Todos Resultados
  • Home
  • Pós-Graduação
  • Blog
  • Sobre Mim
  • Contato
  • English

© 2024 Sigmoidal - Aprenda Data Science, Visão Computacional e Python na prática.