Relatório 03 - Espaço de Cores
Introdução
Na teoria das cores, o conceito de espaço de cores é fundamental para representar e manipular informações visuais em diversas aplicações, como segmentação de imagem e detecção de objetos. Um espaço de cores organiza as cores de acordo com modelos matemáticos que interpretam as diferentes percepções visuais, como intensidade, matiz e saturação, refletindo características da visão humana. Por exemplo, o espaço de cores RGB representa as cores como combinações de vermelho, verde e azul, enquanto o HSV separa os atributos de matiz (cor), saturação (vivacidade) e valor (brilho), tornando-o ideal para operações de processamento que dependem de variações de intensidade e cor.
No OpenCV, a função inRange permite identificar faixas específicas de cores em uma imagem, aplicando limites predefinidos para cada canal de cor. Isso possibilita que apenas regiões com valores dentro dessas faixas sejam destacadas, simplificando a segmentação e o reconhecimento de padrões. Essa abordagem é crucial em tarefas de visão computacional, onde a precisão na distinção de cores e a adequação do espaço escolhido determinam a eficácia na análise visual.
Programa de transformação de RGB para HSV
Este programa, desenvolvido em C++ com a biblioteca OpenCV, implementa um sistema de captura e detecção de cores em tempo real a partir de um dispositivo de vídeo (webcam). Ele processa os frames da câmera e permite a detecção de um objeto específico com base em seu intervalo de valores HSV (matiz, saturação e valor).
Arquivo: Gaussian_Threshold_inRange.cpp
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include
using namespace cv;
const int max_value_H = 360 / 2;
const int max_value = 255;
const String window_capture_name = "Video Capture";
const String window_detection_name = "Object Detection";
const String window_combined_name = "Combined View"; // Nova janela para imagens lado a lado
int low_H = 0, low_S = 0, low_V = 0;
int high_H = max_value_H, high_S = max_value, high_V = max_value;
static void on_low_H_thresh_trackbar(int, void *)
{
low_H = min(high_H - 1, low_H);
setTrackbarPos("Low H", window_detection_name, low_H);
}
static void on_high_H_thresh_trackbar(int, void *)
{
high_H = max(high_H, low_H + 1);
setTrackbarPos("High H", window_detection_name, high_H);
}
static void on_low_S_thresh_trackbar(int, void *)
{
low_S = min(high_S - 1, low_S);
setTrackbarPos("Low S", window_detection_name, low_S);
}
static void on_high_S_thresh_trackbar(int, void *)
{
high_S = max(high_S, low_S + 1);
setTrackbarPos("High S", window_detection_name, high_S);
}
static void on_low_V_thresh_trackbar(int, void *)
{
low_V = min(high_V - 1, low_V);
setTrackbarPos("Low V", window_detection_name, low_V);
}
static void on_high_V_thresh_trackbar(int, void *)
{
high_V = max(high_V, low_V + 1);
setTrackbarPos("High V", window_detection_name, high_V);
}
int main(int argc, char* argv[])
{
VideoCapture cap(argc > 1 ? atoi(argv[1]) : 0);
namedWindow(window_capture_name);
namedWindow(window_detection_name);
namedWindow(window_combined_name); // Criação da nova janela
// Trackbars para definir os limites dos valores HSV
createTrackbar("Low H", window_detection_name, &low_H, max_value_H, on_low_H_thresh_trackbar);
createTrackbar("High H", window_detection_name, &high_H, max_value_H, on_high_H_thresh_trackbar);
createTrackbar("Low S", window_detection_name, &low_S, max_value, on_low_S_thresh_trackbar);
createTrackbar("High S", window_detection_name, &high_S, max_value, on_high_S_thresh_trackbar);
createTrackbar("Low V", window_detection_name, &low_V, max_value, on_low_V_thresh_trackbar);
createTrackbar("High V", window_detection_name, &high_V, max_value, on_high_V_thresh_trackbar);
Mat frame, frame_HSV, frame_threshold, frame_filtered;
while (true) {
cap >> frame;
if (frame.empty())
{
break;
}
// Aplicar filtro gaussiano
GaussianBlur(frame, frame_filtered, Size(15, 15), 0);
// Converter de BGR para o espaço de cores HSV
cvtColor(frame_filtered, frame_HSV, COLOR_BGR2HSV);
// Detectar o objeto com base nos valores de intervalo HSV
inRange(frame_HSV, Scalar(low_H, low_S, low_V), Scalar(high_H, high_S, high_V), frame_threshold);
// Criar imagem combinada lado a lado
Mat combined;
hconcat(frame, frame_filtered, combined); // Combina as imagens
// Mostrar os quadros
imshow(window_capture_name, frame);
imshow(window_detection_name, frame_threshold);
imshow(window_combined_name, combined); // Exibir imagem combinada
char key = (char) waitKey(30);
if (key == 'q' || key == 27)
{
break;
}
}
return 0;
}
}
Detector Canny
O detector de bordas de Canny é uma técnica de detecção de bordas desenvolvida para identificar mudanças de intensidade em imagens, destacando contornos de objetos. Ele trabalha em quatro etapas: suavização, cálculo de gradiente, supressão de não-máximos e limiarização dupla com rastreamento de bordas.
Primeiro, a imagem é suavizada para reduzir ruídos, depois os gradientes são calculados para detectar mudanças de intensidade. Com a supressão de não-máximos, retêm-se apenas os pontos com maior intensidade de borda, e, na última etapa, aplica-se a limiarização dupla para realçar bordas com intensidade forte e conectar as fracas adjacentes.
No código abaixo, foi adicionada a aplicação do detector de bordas de Canny para destacar os contornos de objetos no vídeo.
Arquivo: Canny_Gaussian_Threshold_inRange.cpp
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include
using namespace cv;
Mat frame, frame_gray;
Mat dst, detected_edges;
Mat filtered_image;
int lowThreshold = 0;
const int max_lowThreshold = 100;
const int ratio = 3;
const int kernel_size = 3;
const char* window_name = "Canny Edge Map";
const char* window_filtered_name = "Filtered Image";
// Função para aplicar o detector Canny
static void CannyThreshold(int, void*)
{
blur(frame_gray, detected_edges, Size(3, 3));
Canny(detected_edges, detected_edges, lowThreshold, lowThreshold * ratio, kernel_size);
dst = Scalar::all(0);
frame.copyTo(dst, detected_edges);
imshow(window_name, dst);
}
int main(int argc, char** argv)
{
VideoCapture cap(0); // Captura de vídeo da webcam
if (!cap.isOpened())
{
std::cerr << "Error: Cannot open the webcam!" << std::endl;
return -1;
}
namedWindow(window_name, WINDOW_AUTOSIZE);
namedWindow(window_filtered_name, WINDOW_AUTOSIZE);
// Criar trackbar para ajustar o limiar
createTrackbar("Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold);
while (true)
{
cap >> frame; // Captura um frame da webcam
if (frame.empty())
break;
// Converter a imagem para escala de cinza
cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
// Exemplo de filtragem: aplicar um desfoque gaussiano
GaussianBlur(frame, filtered_image, Size(15, 15), 0);
// Chamar a função Canny pela primeira vez
CannyThreshold(0, 0);
// Exibir a imagem filtrada
imshow(window_filtered_name, filtered_image);
// Mostrar a imagem original (opcional)
imshow("Original", frame);
// Esperar por uma tecla
char key = (char)waitKey(30);
if (key == 'q' || key == 27) // Sair se 'q' ou 'Esc' for pressionado
break;
}
cap.release(); // Liberar a captura de vídeo
destroyAllWindows(); // Fechar todas as janelas
return 0;
}
Imagens e Videos
programa permite salvar uma imagem processada ao pressionar 's' e gravar um vídeo dos frames processados ao pressionar 'k' para iniciar e 'h' para parar a gravação.
Arquivo: R_Canny_Gaussian_Threshold_inRange.cpp
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include
using namespace cv;
Mat frame, frame_gray;
Mat dst, detected_edges;
int lowThreshold = 0;
const int max_lowThreshold = 100;
const int ratio = 3;
const int kernel_size = 3;
const char* window_name = "Canny Edge Map";
VideoWriter videoWriter; // Para gravar o vídeo
bool isRecording = false; // Flag para controle de gravação
// Função para aplicar o detector Canny
static void CannyThreshold(int, void*)
{
// Converter a imagem para escala de cinza
cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
blur(frame_gray, detected_edges, Size(3, 3));
Canny(detected_edges, detected_edges, lowThreshold, lowThreshold * ratio, kernel_size);
dst = Scalar::all(0);
frame.copyTo(dst, detected_edges);
imshow(window_name, dst);
}
int main(int argc, char** argv)
{
VideoCapture cap(0); // Captura de vídeo da webcam
if (!cap.isOpened())
{
std::cerr << "Error: Cannot open the webcam!" << std::endl;
return -1;
}
namedWindow(window_name, WINDOW_AUTOSIZE);
// Criar trackbar para ajustar o limiar
createTrackbar("Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold);
while (true)
{
cap >> frame; // Captura um frame da webcam
if (frame.empty())
break;
// Chamar a função Canny para processar a imagem
CannyThreshold(0, 0);
// Exibir a imagem com bordas detectadas
imshow("Original", frame);
imshow(window_name, dst);
// Salvar a imagem ao pressionar 's'
char key = (char)waitKey(30);
if (key == 's') // Salvar imagem
{
imwrite("canny_image.png", dst); // Salvar a imagem processada pelo Canny
std::cout << "Image saved as 'canny_image.png'" << std::endl;
}
else if (key == 'k') // Iniciar gravação de vídeo
{
if (!isRecording)
{
videoWriter.open("output_canny.avi", VideoWriter::fourcc('M','J','P','G'), 10, frame.size());
if (!videoWriter.isOpened())
{
std::cerr << "Error: Could not open the video writer!" << std::endl;
return -1;
}
isRecording = true;
std::cout << "Recording started..." << std::endl;
}
}
else if (key == 'h') // Parar gravação de vídeo
{
if (isRecording)
{
videoWriter.release();
isRecording = false;
std::cout << "Recording stopped." << std::endl;
}
}
// Gravar o frame se estiver gravando
if (isRecording)
{
videoWriter.write(dst); // Gravar a imagem processada pelo Canny
}
}
cap.release(); // Liberar a captura de vídeo
videoWriter.release(); // Liberar o gravador de vídeo se estiver aberto
destroyAllWindows(); // Fechar todas as janelas
return 0;
}
Imagem do detector Canny
Video do detector Canny