Mostrar Varios cv::Mat en una Ventana

En el siguiente tutorial OpenCV veremos cómo podemos mostrar una, dos o más Imágenes en la misma ventana, la biblioteca OpenCV no tiene una función definida para esto pero hacerlo es muy fácil, lo que haremos será crear una imagen de gran tamaño que contendrá a las demás imágenes que deseamos mostrar ubicando cada una de ellas en su correspondiente ubicación.

Vamos a crear una función a la cual le pasaremos un conjunto de imágenes que deseamos mostrar, indicaremos el número de columnas y filas que crearemos, en cada cuadrante se ubicara una imagen dependiendo del orden en que sean agregadas, podemos cambiar el tamaño de cada cuadrante y la distancia entre uno y otro.

multiple image window

void showImages(const String& window_name, int rows, int cols, int size, std::initializer_list<const Mat*> images, int pad = 1)
{
    if (pad <= 0) pad = 0;

    int width = size * cols + ((cols + 1) * pad);
    int height = size * rows + ((rows + 1) * pad);

    Mat dst = Mat(height, width, CV_8UC3, Scalar::all(255));

    int x = 0, y = 0, cols_counter = 0, img_counter = 0;

    for (auto& img : images) {
        Mat roi = dst(Rect(x + pad, y + pad, size, size));

        getSquareImage(*img, roi, size);

        x += roi.cols + pad;

        if (++cols_counter == cols) {
            cols_counter = x = 0;
            y += roi.rows + pad;
        }

        if (++img_counter >= rows * cols) break;
    }

    imshow(window_name, dst);
}

Esta es la función encargada de ubicar cada una de las imágenes, primero crea la imagen destino con el ancho y alto calculado según el número de filas, columnas, tamaño de cuadrante indicado, lo siguiente es recorrer cada una de las imágenes pasadas a través del inicializador de listas y ubicar cada imagen en su posición correspondiente.

Mat roi = dst(Rect(x + pad, y + pad, size, size));
getSquareImage(*img, roi, size);

La primeria línea de este fragmento de código toma la región o cuadrante correspondiente a la imagen que se está procesando en el bucle, la llamado a la función getSquareImage() es para obtener una imagen redimensionada al tamaño indicado respetando la relación ancho/alto.

Redimensionar Imagen Manteniendo la Relación Ancho/Alto.

void getSquareImage(cv::InputArray img, cv::OutputArray dst, int size)
{
    if (size < 2) size = 2;
    int width = img.cols(), height = img.rows();

    cv::Mat square = dst.getMat();

    if (width == height) {
        cv::resize(img, square, Size(size, size));
        return;
    }

    square.setTo(Scalar::all(0));

    int max_dim = (width >= height) ? width : height;
    float scale = ((float)size) / max_dim;
    
    cv::Rect roi;

    if (width >= height)
    {
        roi.width = size;
        roi.x = 0;
        roi.height = (int)(height * scale);
        roi.y = (size - roi.height) / 2;
    }
    else
    {
        roi.y = 0;
        roi.height = size;
        roi.width = (int)(width * scale);
        roi.x = (size - roi.width) / 2;
    }

    cv::resize(img, square(roi), roi.size());
}

Esta es la función encargada de redimensionar la imagen al tamaño indicado manteniendo el “aspect ratio” la idea es calcular la región centrada donde se ubicara la imagen de tamaño redimensionado, si la imagen es cuadrada solo redimensionamos y la ubicamos usando el cuadrante completo.

Mat image0 = imread("image/lena.jpg", CV_LOAD_IMAGE_COLOR);
Mat image1 = imread("image/baboon.jpg", CV_LOAD_IMAGE_COLOR);
Mat image2 = imread("image/butterfly.jpg", CV_LOAD_IMAGE_COLOR);

Mat image4;
cvtColor(image0, image4, CV_BGR2GRAY);
cvtColor(image4, image4, CV_GRAY2BGR);

Mat image5;
filter2D(image1, image5, image5.depth(), Mat::eye(2, 2, CV_8UC1));

Mat image6;
Sobel(image2, image6, -1, 1, 1);

Para nuestro tutorial cargamos tres imágenes y les aplicamos algunos filtros, notemos que para mostrar imágenes a escala de grises debemos a BGR antes de pasar la imagen.

if (!image0.empty() || !image1.empty() || !image2.empty())
{
    namedWindow("Display Multiple Image", WINDOW_AUTOSIZE);
    showImages("Display Multiple Image", 2, 3, 240, { &image0, &image1, &image2, &image4, &image5, &image6 }, 5);
}

Llamamos a la función showImages() indicando el nombre de la ventana, el número de filas y columnas, el tamaño de cuadrante que no puede ser menor que 2, la lista de imágenes y la distancia entre cuadrantes, este último es opcional, por defecto su valor e 1.

varios mat en ventana
Puedes descargar el proyecto en el siguiente repositorio:

GitHut: Mostrar Múltiples Imágenes

Comentarios

Entradas populares de este blog

Conectar SQL Server con Java

Entrenar OpenCV en Detección de Objetos

Detección de figuras geométricas