Tutorial OpenCV (Filtro Twirl)

Aplicar filtro twirl a una imagen con OpenCV, twirl es una transformación 2D aplicada a la imagen que busca rotar los pixeles sobre un punto determinado, en nuestro caso el centro de la imagen, cuanto más alejado estén los pixeles del punto central mayor será el ángulo de rotación.

twirl filtro opencv

La operación es simple, primero desplazamos el origen al centro y obtenemos el ángulo y radio para realizar la deformación en coordenadas polares.

float x = (j / height) - 0.5f;
float y = (i / width) - 0.5f;

float angle = atan2f(y, x);
float radius = sqrtf((x * x) + (y * y));

Luego incrementamos el ángulo y obtenemos la posición en coordenadas cartesianas (X, Y), terminamos ubicando el pixel actual en la nueva posición.

angle += radius * (value / 10.0f);

float xr = ((radius * sinf(angle)) + 0.5f) * width;
float yr = ((radius * cosf(angle)) + 0.5f) * height;

int k = (int)std::min(width - 1, std::max(0.0f, xr));
int m = (int)std::min(height - 1, std::max(0.0f, yr));

Usaremos un trackbar que nos permitirá cambiar el nivel de deformación que deseamos aplicar a este filtro.

const cv::String name_window = "Twirl Image";
const cv::String name_trackbar = "Twirl";

namedWindow(name_window);
createTrackbar(name_trackbar, name_window, NULL, 200, trackbar_callback, &image);
setTrackbarPos(name_trackbar, name_window, 80);
imshow(name_window, image);

La función createTrackbar() crea el trackbar, lo hemos visto en tutoriales anteriores, mientras que la función setTrackbarPos() establece el valor de este control.

Código fuente C++

#include <iostream>
#include <cmath>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

void trackbar_callback(int value, void* userdata)
{
    Mat* image = (Mat*)userdata;

    const float width = (float)image->rows;
    const float height = (float)image->cols;

    Mat result(image->rows, image->cols, image->type());

    for (int i = 0; i < image->rows; i++) {
        for (int j = 0; j < image->cols; j++) {

            float x = (j / height) - 0.5f;
            float y = (i / width) - 0.5f;

            float angle = atan2f(y, x);
            float radius = sqrtf((x * x) + (y * y));

            angle += radius * (value / 10.0f);

            float xr = ((radius * sinf(angle)) + 0.5f) * width;
            float yr = ((radius * cosf(angle)) + 0.5f) * height;
      
            int k = (int)std::min(width - 1, std::max(0.0f, xr));
            int m = (int)std::min(height - 1, std::max(0.0f, yr));

            uchar* src = image->ptr<uchar>(k, m);
            uchar* out = result.ptr<uchar>(i, j);

            out[0] = src[0];
            out[1] = src[1];
            out[2] = src[2];
        }
    }

    imshow("Result Image", result);
}

int main(int argc, char** argv)
{
    Mat image = imread("data/lena.jpg", CV_LOAD_IMAGE_COLOR);

    if (image.empty())
    {
        printf("No image data \n");
        return -1;
    }

    try
    {
        const cv::String name_window = "Twirl Image";
        const cv::String name_trackbar = "Twirl";

        namedWindow(name_window);
        createTrackbar(name_trackbar, name_window, NULL, 200, trackbar_callback, &image);
        setTrackbarPos(name_trackbar, name_window, 80);
        imshow(name_window, image);

        waitKey(0);
        destroyAllWindows();
    }
    catch (cv::Exception& e)
    {
        const char* err_msg = e.what();
        std::cout << "exception caught: " << err_msg << std::endl;
    }

    return 0;
}

Comentarios

Entradas populares de este blog

Conectar SQL Server con Java

Conociendo la clase cv::Mat de OpenCV

Entrenar OpenCV en Detección de Objetos

Procesamiento de imágenes en OpenCV

Acceso a la webcam con OpenCV