Introdução

O histograma é uma ferramenta muito importante usada para avaliar o comportamento de uma imagem. Quando precisamos identificar quantas ocorrencias - de pixels - existem em cada nível (de tom de cinza ou de cor - RBG). Podemos ver na seguite figura, o exemplo de um histograma:

512
Figura 1. Exemplo de um histograma

A partir do conhecimento do histograma de uma imagem, podemos analisar algumas características da imagem e, mais que isso, realizar alguns tipos de modificações que melhoram a qualidade da imagem. Dentre as modificações que podemos realizar, uma bastante comum é a equalização do histograma, que acarreta em efeitos que iremos analisar nessa atividade.

Desenvolvimento da atividade

A atividade propõe mostrar o processo de capturar imagens de uma webcam instalada no computador, calcular os histogramas em tons de cinza e desenhá-los no canto superior esquerdo da imagem capturada. Além disso, em outra janela de exibição, mostrar como cada imagem capturada ficaria com seu histograma equalizado.

Podemos ver o resultado esperado nas seguintes figuras, onde podemos observar as diferenças entre uma imagem e sua versão com o histograma equalizado. No canto superior esquerdo podemos ver o histograma de cada imagem.

512
Figura 2. Imagem capturada original
512
Figura 3. Imagem capturada equalizada

Código no OpenCV

O programa implementado apresenta o comportamento indicado pelo seguinte fluxograma:

640
Figura 4. Fluxograma seguido pelo programa

Para a realização de equalização, cálculo e normalização do histograma, foram utilizadas funções oferecidas pela biblioteca OpenCV. O código do programa pode ser visualizado a seguir:

Listagem 1. equalize.cpp
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, char** argv){
  	Mat image, saida;
  	int larg, alt;


  	//Variáveis necessárias para a construção do histograma
  	int 		 histSize 	= 64;								//Número de subdivisões horizontais
  	float 		 range[] 	= { 0, 256 };						//Limites inferior e superior do histograma
  	const float* histRange 	= { range };
  	Mat histograma, histograma2;								//Objeto onde o histograma será armazenado


  	//Variáveis para a 'plotagem' do histograma
  	int hist_w 	= histSize;										//Tamanho do histograma será 1 pixel por subdivisão horizontal
  	int hist_h 	= 32;											//Tamanho da altura do histograma (1 pixel por valor possível)
  	Mat histImage (hist_h, hist_w, CV_8UC1, Scalar(0));			//Inicializando as imagens que apresentarão os histogramas
  	Mat histImage2(hist_h, hist_w, CV_8UC1, Scalar(0));

    //Abertura da webcam
  	VideoCapture cap;
  	cap.open(0);

  	if(!cap.isOpened()){
    	cout << "Erro ao abrir a câmera.\n";
    	return -1;
    }

	while(1){

   		cap >> image;
   		flip(image,image,1);  									//espelhar a tela pra deixar a visualização mais fiel da realidade
        cvtColor(image,image,CV_BGR2GRAY); 						//Convertendo RGB para Escala de Cinza
   		equalizeHist(image, saida); 							//Função do opencv para equalizar o histograma

   		//Reinicializando as imagens dos histogramas
   		histImage.setTo( Scalar(0));
   		histImage2.setTo(Scalar(0));

   		//Calculando o histograma das imagens
   		calcHist(&image, 1, 0, Mat(), histograma , 1, &histSize, &histRange, true, false);
   		calcHist(&saida, 1, 0, Mat(), histograma2, 1, &histSize, &histRange, true, false);

   		//Normalizando o histograma das imagens
   		normalize(histograma , histograma , 0, histImage.rows , NORM_MINMAX, -1, Mat());
   		normalize(histograma2, histograma2, 0, histImage2.rows, NORM_MINMAX, -1, Mat());

   		//Plotagem do histograma
   		for(int i = 0; i < histSize; i++){
   			line( histImage, Point(i,hist_h) , Point(i,hist_h-cvRound(histograma.at<float>(i))) , Scalar( 255, 255, 255), 1, 8, 0);
   			line( histImage2,Point(i,hist_h) , Point(i,hist_h-cvRound(histograma2.at<float>(i))), Scalar( 255, 255, 255), 1, 8, 0);
   		}

   		//Copiando histograma para ser apresentado na saída
   		histImage.copyTo(image(Rect(0, 0, histSize, hist_h)));
   		histImage2.copyTo(saida(Rect(0, 0, histSize, hist_h)));

   		//Apresentação dos resultados
   		namedWindow("entrada", CV_WINDOW_KEEPRATIO);
   		namedWindow("saida", CV_WINDOW_KEEPRATIO);
   		imshow("entrada", image);
   		imshow("saida",saida);
		if(waitKey(30) >= 0) break;
	}

  	imwrite("saida.png",saida);
  	imwrite("entrada.png",image);
  	return 0;
}

Para a realização do processamento, primeiramente um quadro do vídeo é capturado, e após isso, a imagem é invertida, para que haja uma interação melhor com o usuário na apresentação do resultado. Nesse momento, a imagem é convertida para tons de cinza.

A equalização do histograma é realizada através da função equalizeHist(). Essa função recebe uma imagem e armazena o resultado da equalização em outra imagem. Quando o processo de equalização é realizado, os níveis do histograma tendem a se espalharem por todo os valores de tons de cinza. Com isso, há uma normalização no brilho da imagem, aumentando seu contraste.

Após a equalização da imagem, é então calculado o histograma da imagem original e da imagem equalizada. Esse cálculo é necessário para a apresentação do histograma resultante nas imagens. O cálculo é realizado pela função calcHist(). Nessa função, fornecemos alguns valores como a imagem a ser analisada, tamanho do histograma, etc, e o resultado do cáculo é armazendo em uma imagem. Para maior detalhamento, consultar a documentação da função fornecida no site do OpenCV. Os histogramas são então normalizados e copiados para suas respectivas imagens.

Resultados

Em desenvolvimento…​

Com a execução do código, a imagem capturada pela webcam passa a ser apresentada em uma janela, e o resultado da equalização é apresentada em outra janela. Podemos um exemplo da imagem resultante a seguir:

640
Figura 5. Imagem capturada pela webcam
640
Figura 6. Imagem com histograma equalizado

Com isso, podemos perceber que os efeitos da equalização foram obtidos com sucesso, sendo possível observar claramente a diferença entre o histograma da imagem original e da imagem processada.

Dependendo da iluminação do local, a equalização pode ser pouco perceptível, pois o histograma da imagem original já está bem distribuída ao longo de todos os tons de cinza. Podemos ver isso a seguir:

640
Figura 7. Imagem capturada pela webcam
640
Figura 8. Imagem com histograma equalizado