Efecto Pixelado con OpenCV

Continuando con la serie de tutoriales OpenCV esta vez aprenderemos a aplicar el efecto de pixelado a una imagen, lo utilizaremos en conjunto con un detector en cascada para localizar una región u ocultarla, por ejemplo, detectar un rostro y ocultar el área que lo contiene para proteger la identidad de la persona.

El tutorial de detección de rostros lo puedes ver en las publicaciones anteriores, en este post nos centraremos en el efecto pixelado, ya sea para una imagen completa o una región definida de la misma.

for (int r = 0; r < src.rows; r += pixel_size)
{
    for (int c = 0; c < src.cols; c += pixel_size)
    {
        rect.x = c;
        rect.y = r;
        rect.width = c + pixel_size < src.cols ? pixel_size : src.cols - c;
        rect.height = r + pixel_size < src.rows ? pixel_size : src.rows - r;

        Scalar color = mean(Mat(src, rect));
        rectangle(dst, rect, color, CV_FILLED);
    }
}

Lo que haremos será obtener un rectángulo de tamaño indicado por el usuario, este será el tamaño de píxel, si indicamos por ejemplo 4 la imagen será dividida en cuadrados de tamaño 4x4 px, para cada uno de ellos calculamos el color promedio y pintamos todo el cuadrado con ese color.

Usamos la función cv::mean() para calcular el color promedio de la región definida por rect, nos apoyamos también en la función cv::rectangle() para dibujar en cuadrado, CV_FILLED indica que el rectángulo debe rellenarse con el color indicado.

Para finalizar esta aplicación creamos un trackbar que nos permitirá cambiar el tamaño de píxel, usamos la función cv::createTrackbar() para crear este control, como último parámetro indicamos la dirección de memoria del cv::Mat que pixelaremos, esta es una manera de pasar datos a la función callback del trackbar sin tener que usar variables globales.

Mat image = imread("image/lena.jpg", CV_LOAD_IMAGE_COLOR);

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

int pixel_size = 8;

namedWindow("Pixelate Effect", WINDOW_AUTOSIZE);
createTrackbar("Pixel Size", "Pixelate Effect", &pixel_size, 50, ontrack, &image);
ontrack(pixel_size, &image);

waitKey(0);
destroyAllWindows();

En la función ontrack() debemos obtener el cv::Mat a partir del puntero void*, hacemos la conversión correspondiente.

void ontrack(int value, void* data) {
    if (value <= 0 || data == nullptr) return;

    Mat dst;
    pixelate(*((Mat*)data), dst, value);
    imshow("Pixelate Effect", dst);
}

Aplicando este pequeño programa sobre una imagen obtenemos:

opencv efecto pixelado
Para finalizar agregamos una pequeña restricción a la hora de aplicar el efecto de pixelado, solo lo aplicaremos a la región indicada, lo que se encuentre fuera permanecerá igual.

// verificar si se encuentra dentro del ROI
if (roi.contains(Point(c, r)) && roi.contains(Point(c + rect.width, r + rect.height))) {
    Scalar color = mean(Mat(src, rect));
    rectangle(dst, rect, color, CV_FILLED);
}
else {
    // copiar sin modificar
    Mat(src, rect).copyTo(Mat(dst, rect));
}

El resultado ahora se ve como sigue, he indicado manualmente la región, pero podemos utilizar el detector de rostros para obtener la región y aplicarle el efecto.

pixelar region
Encontrarás en código de la aplicación sin el detector de rostros en:

GitHub: Efecto Pixelado con OpenCV

Comentarios

Temas relacionados

Entradas populares de este blog

tkinter Grid

Conectar SQL Server con Java

Controles y Contenedores JavaFX 8 - I

tkinter Canvas