Programas/atividades desenvolvidas para a disciplina DCA0445 - Processamento Digital de Imagens, do curso de Engenharia de Computação da Universidade Federal do Rio grande do Norte UFRN
Prefácio
C++
utilizando-se da biblioteca OpenCV
e em ambiente Linux. Para compilar qualquer programa presente neste documento, pode-se fazer uso deste Makefile,
coloca o Makefile na mesma pasta do código fonte, extensão .cpp, e execute via terminal o comando
make <nome_do_programa>
. Todos os códigos encontram-se no Repositório do github.
1. Programa Region
Este programa consiste em negativar uma certa região dentro de uma imagem, delimitada por um retângulo informado pelo usuário. o programa varre a área correspondente na imagem e troca os valores dos pixels para seus inversos, ou seja 255 - valor_atual.
Compilando e Executando.
$ make region $ ./region <caminho_para_a_imagem>
O código fonte completo se encontra aqui region.cpp.
void region(Mat &img, CvPoint *p)
{
for(unsigned int i = p[0].x; i < p[1].x; i++)
for(unsigned int j = p[0].y; j < p[1].y; j++)
img.at<uint8_t>(i,j) = 255 - img.at<uint8_t>(i,j);
}
2. Troca Regiões
O usuário deve passar uma imagem qualquer, e o programa passara para escala de cinza e particionara a imagem em 4(quatro) partes simétricas e realizara a troca na diagonal dessas quatro subimagens.
Para este programa uma imagem foi pensada sendo composta por 4 regiões da seguinte forma:
A |
B |
C |
D |
Compilando e Executando.
$ make trocaregioes $ ./trocaregioes <caminho_para_a_imagem>
Código completo em trocaregioes.cpp
int main(int argc, char** argv){
Mat img;
Mat result;
int w, h;
img = imread(argv[1],CV_LOAD_IMAGE_GRAYSCALE);
//if fail to read the image
if ( img.empty() )
{
cout << "Error loading the image" << endl;
return -1;
}
w = img.size().width;
h = img.size().height;
result = img.clone();
img(cv::Rect(0,0, w/2, h/2)).copyTo(result(cv::Rect((w-1)/2, (h-1)/2, w/2, h/2))); (1)
img(cv::Rect((w-1)/2, 0, w/2, h/2)).copyTo(result(cv::Rect(0, (h-1)/2, w/2, h/2))); (2)
img(cv::Rect(0, (h-1)/2, w/2, h/2)).copyTo(result(cv::Rect((w-1)/2, 0, w/2, h/2))); (3)
img(cv::Rect((w-1)/2, (h-1)/2, w/2, h/2)).copyTo(result(cv::Rect(0, 0, w/2, h/2))); (4)
imshow("Original", img);
imshow("Resultado", result);
waitKey();
imwrite("resultados/trocaRegiao_resultado.png", result);
return 0;
}
1 | Sobrepoe A da img original em D de result |
2 | Sobrepoe B da img original em C de result |
3 | Sobrepoe C da img original em B de result |
4 | Sobrepoe D da img original em A de result |
Resultado
D |
C |
B |
A |
3. Conta Bolhas
Este programa consiste em contar o número de regiões brancas puras, com e sem "buracos", o fundo da imagem deve ser puramente preto e os objetos puramente brancos, o programa foi testado utilizando a imagem bolhas.png. Mas o mesmo deve funcionar para qualquer imagem que siga o padrão especificado a cima.
O algoritmo consiste em 4 passos bem definidos. O código completo se encontra neste link: contaregioes.cpp.
-
Passo 1- Remover objetos das bordas
//remove da borda superior e inferior
for(int i = 0; i < width; i++){
if(image.at<uint8_t>(0, i) == OBJ_COLOR)
floodFill(image, CvPoint(i, 0), BACK_COLOR);
if(image.at<uint8_t>(height-1,i) == OBJ_COLOR)
floodFill(image, CvPoint(i, height-1), BACK_COLOR);
}
//remove das laterais
for(int i = 0; i < height; i++){
//lateral esquerda
if(image.at<uint8_t>(i, 0) == OBJ_COLOR)
floodFill(image, CvPoint(0, i), BACK_COLOR);
//lateral direita
if(image.at<uint8_t>(i, width-1) == OBJ_COLOR)
floodFill(image, CvPoint(width-1, i), BACK_COLOR);
}
-
Passo 2- Contar bolhas com buraco
//troca o background, para facilitar a identificar os buracos das bolhas
floodFill(image, CvPoint(0,0), NEW_BACK_COLOR);
for(int i = 0; i < height; i++)
for(int j = 0; j < width; j++)
{
//identifica uma bolha com buraco
if(image.at<uint8_t>(i,j) == BACK_COLOR && image.at<uint8_t>(i,j-1) == OBJ_COLOR){
//soma um no numero de bolhas e "apaga" a bolha encontrada
nbolhas_com_buracos++;
floodFill(image, CvPoint(j-1, i), NEW_BACK_COLOR);
}
}
-
Passo 3- Contar bolhas sem buracos
//conta bolhas sem buracos
for(int i = 0; i < height; i++)
for(int j = 0; j < width; j++)
{
//identifica uma bola
if(image.at<uint8_t>(i,j) == OBJ_COLOR){
//soma um no numero de bolhas e "apaga" a bolha encontrada
nbolhas_sem_buracos++;
floodFill(image, CvPoint(j, i), NEW_BACK_COLOR);
}
}
Resultado
4. Histograma
Breve descrição do que seja um histograma…
4.1. Equalização de Histograma
Implementação de um Equalizador de Histograma para imagens em tons de cinza.
Algoritmo de equalização, para imagens em tons de cinza:
-
Calcular Histograma: \(h(r_k), k \in [0,255\)];
-
Calcular Histograma Acumulado: \(ha(r_k) = \sum{h(r_j)}, j \in [0,255\)];
-
Normalizar o Histograma Acumulado, na faixa de [0, 255]: \(ha(r_k) = ha(r_k)/ha(r_255)\);
-
Transformar a imagem: \(f(x,y) = ha(f(x,y))\).
Antes e Depois da equalização do histograma.
Download do código completo: equalize.cpp
Clique aqui pra ver o código completo
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv){
Mat frame;
Mat hist;
VideoCapture cap;
uint8_t histEq[256];
int histsize = 256;
int sum;
float range[] = {0, 256};
const float *histrange = { range };
cap.open(0);
if(!cap.isOpened()){
cout << "cameras indisponiveis\n";
return -1;
}
std::cout << "Pressione qualquer tecla para encerrar o programa." << '\n';
while(1){
cap >> frame;
cvtColor(frame, frame, CV_BGR2GRAY);
imshow("Original", frame);
//Calculo do histograma
calcHist(&frame, 1, 0, Mat(), hist, 1, &histsize, &histrange);
/*calculo do histograma acumulado */
/*e normalizacao do histograma acumulado*/
/**
* Calcula o vetor que ira realizar a transformacao nos valores dos pixels
*/
sum = 0;
for(int i = 0; i < histsize; i++)
{
sum+= hist.at<float>(i);
histEq[i] = sum*255.0/frame.total();
}
//substituicao dos valores dos pixels
for(int i = 0; i < frame.size().height; i++)
for(int j = 0; j < frame.size().width; j++)
frame.at<uint8_t>(i,j) = histEq[frame.at<uint8_t>(i,j)];
imshow("Equalizado", frame);
if(waitKey(10) != 255)break;
}
return 0;
}
4.2. Detector de Movimento
Utilizando comparação de histogramas entre frames consecutivos, comparando-o por calculo da correlação(usando função do OpenCV, compareHist), para identificar ocorrência de movimento, para isso foi estabelecido, de forma empírica, um limiar para a correlação, ao se identificar um valor de correlação abaixo do limiar, um circulo verde é desenhado no canto superior direito da imagem, indicando uma detecção de movimento.
Makefile utilizado para compilar o programa motiondetector, é diferente pois inclui a capacidade de gerar gifs.