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;
}      		

			
3x3

Imagem do detector Canny

Video do detector Canny