Correção de imagem amarelada

Imagens amareladas podem ser vistas em fotografias antigas ou imagens “all sky” com problemas de aquisição ou em horários de nascer/por do sol. Veja um exemplo de códigos em python que usam histogramas e os espaços de cores HSV e LAB – o post Modelos de cores HSV e LAB (LINKAR) falam mais da parte teórica e sua implementação no OpenCV.

Ajuste via HSV

A faixa de valores de matiz de 20 a 30 (ou até mesmo um pouco mais) no espaço de cores HSV é frequentemente associada a tons de amarelo. A faixa de saturação de 100 a 255 representa cores fortemente saturadas, podendo ser aplicada também. No entanto, os valores específicos podem variar dependendo da tonalidade e da iluminação da cor amarela na imagem.

Um primeiro passo é identificar se a imagem está amarelada ou não, considerando um limite. Uma forma de estimar esse limite é através de um histograma, em que o número de pixels com cada valor é contabilizado, para cada canal. O valor exato do limite pode variar dependendo de vários fatores, como a resolução das imagens (número total de pixels), a qualidade da câmera usada para capturá-las, as condições de iluminação, o conteúdo das imagens e o grau de amarelamento que você considera relevante. Para uma análise mais precisa, pode-se coletar um conjunto de imagens de referência que estão amareladas e outro em que não estão amareladas para calcular o valor médio (ou a distribuição) da quantidade de pixels amarelos nas imagens de referência.

O segundo passo é o ajuste do matiz, que deverá corrigir o amarelamento. Para isso, é adicionado um valor fixo ao canal de matiz, que depende da intensidade do amarelo na imagem mas um chute inicial pode ser o suficiente para mudar em 180° no disco de valores de matiz para chegar no azul.

# Ler arquivo com imagem
img = cv2.imread(file_in)
# Converter a imagem para o espaço de cores HSV
hsv_image = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Calcular o histograma HSV
h, s, v = hsv_image[:,:,0], hsv_image[:,:,1], hsv_image[:,:,2]
hist_h = cv2.calcHist([h],[0],mask,[256],[0,256])
hist_s = cv2.calcHist([s],[0],mask,[256],[0,256])
hist_v = cv2.calcHist([v],[0],mask,[256],[0,256])

# Definir um limite percentual para a quantidade de pixels amarelos
yellow_limit = 10
# Contar pixels amarelados
n_yellow = int(np.sum(hist_h[20:31]))
# Comparar com o limite
n_total = int(np.sum(hist_h))
p_yellow = int(round((n_yellow*100)/n_total,0))
if p_yellow > yellow_limit:
    print('Imagem amarelada')
else:
    print('Imagem normal')

# Montar imagem com máscara para plot
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_rgb_masked = cv2.bitwise_and(img_rgb, img_rgb, mask=mask)

# Definir a faixa de cor amarela no espaço HSV
lower_yellow = np.array([20, 0, 0])  # Valores mínimos de H, S e V
upper_yellow = np.array([31, 256, 256])  # Valores máximos de H, S e V
# Criar uma máscara para a cor amarela
yellow_mask = cv2.inRange(hsv_image, lower_yellow, upper_yellow)
# Aplicar a máscara à imagem original para destacar a cor amarela
yellow_result = cv2.bitwise_and(img_rgb_masked, img_rgb_masked, mask=yellow_mask)

# Iniciar plot
plt.subplot(1, 2, 1)
# Plotar a imagem original
plt.imshow(img_rgb_masked)
plt.title(f'Imagem mascarada')
# Plotar o histograma HSV
plt.subplot(1, 2, 2)
plt.plot(hist_h, color='c', label='H')
plt.plot(hist_s, color='m', label='S')
plt.plot(hist_v, color='y', label='V')
plt.xlim([0, 256])
plt.xlabel('Valor do Pixel')
plt.ylabel('Frequência')
plt.title('Histograma HSV')
plt.legend()
plt.tight_layout()
plt.savefig('imagem_histograma.png')
plt.close()

# CORRIGIR IMAGEM AMARELADA
# Converter a imagem para o espaço de cores HSV
hsv_image = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Ajuste do matiz para mover o amarelo em direção ao azul
factor = (240-60)/2 # 240=azul,60-amarelo,/2=HSV_opencv
hsv_adjusted = hsv_image.copy()
hsv_adjusted[:, :, 0] = (hsv_adjusted[:, :, 0] + factor) % 180
# Converter imagem ajustada para BGR
image_adjusted = cv2.cvtColor(hsv_adjusted, cv2.COLOR_HSV2BGR)

# Iniciar plot: imagem original com máscara e histograma HSV
plt.subplot(1, 2, 1)
# Plotar a imagem corrigida
plt.imshow(image_adjusted)
plt.title('Imagem ajustada')

# Plotar imagem binária com regiões amareladas
plt.subplot(1, 2, 2)
plt.imshow(yellow_result)
plt.title(f'Pixels amarelados: {p_yellow}%')
plt.tight_layout()
plt.savefig('imagem_ajustada.png')
plt.close()

Finalmente, realiza-se a conversão de volta para o espaço de cores original e exibir/salvar a imagem corrigida, que deve ter uma distribuição de cores mais equilibrada.

Imagem original com máscara e histograma
Imagem original com máscara e histograma
Imagem com ajuste de cores via HSV e pixels considerados amarelados
Imagem com ajuste de cores via HSV e pixels considerados amarelados

Este é um método simples e pode não ser perfeito em todos os casos, especialmente se a imagem tiver variações complexas de cor. Em casos mais avançados, você pode considerar o uso de técnicas de processamento de imagem mais sofisticadas, como a correção de cores baseada em histograma.

Já a correção de cores baseada em histograma é uma técnica mais avançada que envolve a manipulação dos histogramas de cores de uma imagem para ajustar seu equilíbrio de cores e corrigir distorções de cor. Essa técnica é útil quando a imagem possui problemas de equilíbrio de cores, como dominância excessiva de uma determinada cor (por exemplo, uma imagem que parece excessivamente amarela) ou quando as cores não estão representadas de forma equilibrada.

Nessa técnica, também deve-se converter o espaço de cores (para HSV, por exemplo) e calcular os histogramas dos canais. A análise dos histogramas pode ser feita visualmente ou usando métricas específicas, como a média e o desvio padrão das componentes de cor. O passo seguinte é o de ajuste dos histogramas para corrigir os desequilíbrios de cores. Isso pode ser feito através de:

  • Equalização de Histograma – para esticar o intervalo de cores de forma que a distribuição de cores seja mais uniforme (pode ajudar a corrigir problemas de contraste de cor);
  • Equalização Adaptativa de Histograma – divide a imagem em regiões menores e aplica a equalização de histograma a cada região, levando em consideração o contexto local;
  • Ajuste manual – necessário para corrigir problemas de cores específicos, o que pode envolver a redução ou aumento de intensidades de cores específicas.

A correção de cores baseada em histograma pode ser uma técnica poderosa para resolver problemas de equilíbrio de cores em imagens, mas requer alguma experiência em processamento de imagem e ajuste fino para obter resultados precisos. É importante lembrar que nem todos os problemas de cor podem ser corrigidos facilmente, e em alguns casos, a intervenção manual pode ser necessária para obter os resultados desejados.

Ajuste via LAB

A primeira parte do script a seguir classifica e contabiliza os pixels amarelados com relação ao total de pixels que a máscara considera como válidos (“NonZero”). Os intervalos considerados de cada canal foram estimados de modo a permitir que o limite para considerar uma imagem amarelada ou não (“yellow_limit”) fosse igual a 10%, mas considerando uma restrição para amarelo no canal b*, sem restrição no canal a* e uma restrição de pixels mais claros no canal L.

A segunda parte do script converte a imagem para o modelo de cores LAB, onde o canal b* usa valores positivos para tons de amarelo (cores de temperaturas quentes) e valores negativos para tons azuis (cores frias). Para a correção, é adicionada uma constante (definida empiricamente) para todos os pixels da imagem nesse canal. Por fim, ela é convertida de volta pra RGB e salva em um arquivo PNG, ao lado da imagem original.

# Ler arquivo com imagem
img = cv2.imread(file_in)
# Converter a imagem para o modelo de cores LAB
imagem_lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)

# Definir um limite percentual para a quantidade de pixels amarelos
yellow_limit = 10
# Contabilizar número total de pixels considerados na máscara (NonZero)
n_total = cv2.countNonZero(mask)
# Aplicar a máscara à imagem LAB
imagem_lab_mask = cv2.bitwise_and(imagem_lab, imagem_lab, mask=mask)
# Definir o intervalo de cor para amarelo no espaço LAB
lower_yellow = np.array([150, 0, 140], dtype=np.uint8)
upper_yellow = np.array([255, 255, 255], dtype=np.uint8)
# Encontrar pixels amarelados na imagem
mascara_amarela = cv2.inRange(imagem_lab_mask, lower_yellow, upper_yellow)
n_yellow = cv2.countNonZero(mascara_amarela)
p_yellow = int(round((n_yellow*100)/n_total,0))
if p_yellow > yellow_limit:
    print('Imagem amarelada')
else:
    print('Imagem normal')

# Constante da temperatura (negativo para tornar mais azul/frio)
constante = -20
# Separar os canais LAB
l, a, b = cv2.split(lab_imagem)
# Ajuste da temperatura de cor no canal b*
b = b + constante
# Limitar os valores de b* para estar no intervalo de 0 a 255
b = np.clip(b, 0, 255)
# Juntar os canais novamente
nova_imagem_lab = cv2.merge((l, a, b))
# Converter a nova imagem de LAB para BGR
nova_imagem = cv2.cvtColor(nova_imagem_lab, cv2.COLOR_LAB2BGR)

# Plotar imagem
fig, axs = plt.subplots(1, 2, figsize=(12, 6))
axs[0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axs[0].set_title('Original')
axs[0].axis('off')
axs[1].imshow(cv2.cvtColor(nova_imagem, cv2.COLOR_BGR2RGB))
axs[1].set_title('Ajustada')
axs[1].axis('off')

# Salva a figura como um arquivo PNG
output_path = 'temperatura_ajustada.png'
plt.savefig(output_path, bbox_inches='tight', pad_inches=0.1)
plt.close()
Imagem original e imagem ajustada via LAB
Imagem original e imagem ajustada via LAB

Neste script, os valores no canal b* são ajustados para tornar a imagem mais azulada. Você pode ajustar o valor da temperatura para controlar o quanto você deseja alterar a temperatura de cor da imagem. Valores negativos tornarão a imagem mais fria (mais azulada), enquanto valores positivos tornarão a imagem mais quente (mais amarelada).

Leave a Reply

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

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.