Histogramas

Un histograma es una representación gráfica de la distribución de los niveles de grises en una imagen, utilizando el método de Ecualización de Histogramas podemos obtener una distribución uniforme del histograma de la imagen, este método mejora el contraste y brillo de una imagen que sea demasiado oscura o brillante, obteniendo un balance óptimo de los pixeles blancos y negros.

histogram_sample

Ecualización de Histogramas


Aplicar ecualización de histogramas con OpenCV es muy fácil, contamos con la función: cv::equalizeHist(InputArray src, OutputArray dst), debemos indicar el cv::Mat fuente y el destino, la imagen fuente debe estar en escala de grises.

int main(int, char** argv)
{
    cv::Mat src, dst;

    std::string original = "Imagen Original";
    std::string equalized = "Imagen Equalizeda";

    // leer la imagen
    src = cv::imread("lena.png", 1);

    // convertir en escala de grises y ecualizar histograma
    cv::cvtColor(src, src, cv::COLOR_BGR2GRAY);
    cv::equalizeHist(src, dst);

    // mostrar la imagen original y ecualizada
    cv::imshow(original, src);
    cv::imshow(equalized, dst);
    
    cv::waitKey(0);
    return 0;
}

A la izquierda veremos la imagen original, lena.jpg que ha sido modificada para apreciar mejor el efecto de la ecualización de histogramas, a la derecha vemos el resultado.

ecualización de histogramas OpenCV

Ecualizar Histograma de Imagen a Color


Si deseamos mejorar el brillo y contraste de una imagen a color debemos primero separar la información de luminosidad de la imagen, para ello convertimos el formato de color de BRG a YCrCb de esta manera es más fácil extraer esta información, la cual se encuentra en el primer canal (Y), luego aplicamos la ecualización de histogramas para este canal y finalmente volvemos a unir todos los canales.

// Convertir BGR image a YCrCb
Mat ycrcb;
cvtColor(img, ycrcb, COLOR_BGR2YCrCb);

// Extarer cada uno de los canales
vector<Mat> channels;
split(ycrcb, channels);

// Ecualizar histograma del canal Y (luminosidad)
equalizeHist(channels[0], channels[0]);

// Unir los canales nuevamente
merge(channels, ycrcb);

// Convertir color YCrCb a BGR
cvtColor(ycrcb, result, COLOR_YCrCb2BGR);

El resultado es el siguiente, a la derecha la imagen ecualizada.

OpenCV histogramas

Gráfica de Histogramas


Para dibujar la gráfica de histogramas de cada uno de los canales BGR primero los separamos para luego usar la función calcHist() para calcular el histograma del canal indicado, debemos indicar el rango de valores que usaremos, de 0 a 255 para cada uno de los canales.

// Dividir los canales BRG
vector<Mat> bgr;
split(img, bgr);

// Crear un histograma con 256 bin (numero de subdivisiones) uno por pixel [0..256]
int numbins = 256;

// Establecer rango para los canales (B, G, R)
float range[] = { 0, 256 };
const float* histRange = { range };

Mat b_hist, g_hist, r_hist;

// Calcular el histograma para cada canal
calcHist(&bgr[0], 1, 0, Mat(), b_hist, 1, &numbins, &histRange);
calcHist(&bgr[1], 1, 0, Mat(), g_hist, 1, &numbins, &histRange);
calcHist(&bgr[2], 1, 0, Mat(), r_hist, 1, &numbins, &histRange);

Antes de dibujar primero normalizamos los histogramas obtenidos para que se ubiquen en el rango de valores deseados, en nuestro caso la altura de la imagen, usamos la función normalize(), la función drawLine() dibuja la línea correspondiente.

// Tamaño del histograma
int h_width = 512;
int h_height = 400;

// Crear una imagen para dibujar en ella
Mat histImage(h_height, h_width, CV_8UC3, Scalar(20, 20, 20));

// Normalizar los histogramas 
normalize(b_hist, b_hist, 0, h_height, NORM_MINMAX);
normalize(g_hist, g_hist, 0, h_height, NORM_MINMAX);
normalize(r_hist, r_hist, 0, h_height, NORM_MINMAX);

int bin_width = cvRound((float)h_width / (float)numbins);

// Dibujar cada una de las lineas
for (int i = 1; i < numbins; i++)
{
    drawLine(histImage, bin_width, i, h_height, b_hist, Scalar(255, 0, 0));
    drawLine(histImage, bin_width, i, h_height, g_hist, Scalar(0, 255, 0));
    drawLine(histImage, bin_width, i, h_height, r_hist, Scalar(0, 0, 255));
}

Gráfica de Histograma para los canales BGR.

grafica de histograma
GitHub: Histogramas con OpenCV

Comentarios

Temas relacionados

Entradas populares de este blog

tkinter Grid

tkinter Canvas

Histogramas OpenCV Python

Python Binance API