Saltar al contenido

¿Creando un filtro de viñeta en opencv?

Solución:

En primer lugar, Abid Rahman K describe la forma más sencilla de utilizar este filtro. Debería estudiar seriamente su respuesta con tiempo y atención. La versión de Wikipedia sobre Vignetting también es bastante esclarecedora para aquellos que nunca habían oído hablar de este filtro.

La implementación de Browny de este filtro es considerablemente más compleja. Sin embargo, porté su código a la API de C ++ y lo simplifiqué para que puedas seguir las instrucciones tú mismo.

#include <math.h>

#include <vector>

#include <cv.hpp>
#include <highgui/highgui.hpp>


// Helper function to calculate the distance between 2 points.
double dist(CvPoint a, CvPoint b)
{
    return sqrt(pow((double) (a.x - b.x), 2) + pow((double) (a.y - b.y), 2));
}

// Helper function that computes the longest distance from the edge to the center point.
double getMaxDisFromCorners(const cv::Size& imgSize, const cv::Point& center)
{
    // given a rect and a line
    // get which corner of rect is farthest from the line

    std::vector<cv::Point> corners(4);
    corners[0] = cv::Point(0, 0);
    corners[1] = cv::Point(imgSize.width, 0);
    corners[2] = cv::Point(0, imgSize.height);
    corners[3] = cv::Point(imgSize.width, imgSize.height);

    double maxDis = 0;
    for (int i = 0; i < 4; ++i)
    {
        double dis = dist(corners[i], center);
        if (maxDis < dis)
            maxDis = dis;
    }

    return maxDis;
}

// Helper function that creates a gradient image.   
// firstPt, radius and power, are variables that control the artistic effect of the filter.
void generateGradient(cv::Mat& mask)
{
    cv::Point firstPt = cv::Point(mask.size().width/2, mask.size().height/2);
    double radius = 1.0;
    double power = 0.8;

    double maxImageRad = radius * getMaxDisFromCorners(mask.size(), firstPt);

    mask.setTo(cv::Scalar(1));
    for (int i = 0; i < mask.rows; i++)
    {
        for (int j = 0; j < mask.cols; j++)
        {
            double temp = dist(firstPt, cv::Point(j, i)) / maxImageRad;
            temp = temp * power;
            double temp_s = pow(cos(temp), 4);
            mask.at<double>(i, j) = temp_s;
        }
    }
}

// This is where the fun starts!
int main()
{
    cv::Mat img = cv::imread("stack-exchange-chefs.jpg");
    if (img.empty())
    {
        std::cout << "!!! Failed imreadn";
        return -1;
    }

    /*
    cv::namedWindow("Original", cv::WINDOW_NORMAL);
    cv::resizeWindow("Original", img.size().width/2, img.size().height/2);
    cv::imshow("Original", img);
    */

Qué img parece:

    cv::Mat maskImg(img.size(), CV_64F);
    generateGradient(maskImg);

    /*
    cv::Mat gradient;
    cv::normalize(maskImg, gradient, 0, 255, CV_MINMAX);
    cv::imwrite("gradient.png", gradient);
    */

Qué maskImg parece:

    cv::Mat labImg(img.size(), CV_8UC3);
    cv::cvtColor(img, labImg, CV_BGR2Lab);

    for (int row = 0; row < labImg.size().height; row++)
    {
        for (int col = 0; col < labImg.size().width; col++)
        {
            cv::Vec3b value = labImg.at<cv::Vec3b>(row, col);
            value.val[0] *= maskImg.at<double>(row, col);
            labImg.at<cv::Vec3b>(row, col) =  value;
        }
    }

    cv::Mat output;
    cv::cvtColor(labImg, output, CV_Lab2BGR);
    //cv::imwrite("vignette.png", output);

    cv::namedWindow("Vignette", cv::WINDOW_NORMAL);
    cv::resizeWindow("Vignette", output.size().width/2, output.size().height/2);
    cv::imshow("Vignette", output);
    cv::waitKey();

    return 0;
}

Qué producción parece:

Como se indica en el código anterior, al cambiar los valores de firstPt, radius y power puede lograr efectos artísticos más fuertes / más débiles.

¡Buena suerte!

Puede realizar una implementación simple utilizando los núcleos gaussianos disponibles en OpenCV.

  1. Cargue la imagen, obtenga su número de filas y columnas
  2. Cree dos núcleos gaussianos de filas y columnas de tamaño, digamos A, B. Su variación depende de sus necesidades.
  3. C = transponer (A) * B, es decir, multiplicar un vector de columna con un vector de fila de modo que la matriz de resultados tenga el mismo tamaño que el de la imagen.
  4. D = C / C.max ()
  5. E = img * D

Vea la implementación a continuación (para una imagen en escala de grises):

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('temp.jpg',0)
row,cols = img.shape

a = cv2.getGaussianKernel(cols,300)
b = cv2.getGaussianKernel(rows,300)
c = b*a.T
d = c/c.max()
e = img*d

cv2.imwrite('vig2.png',e)

A continuación se muestra mi resultado:

ingrese la descripción de la imagen aquí

Del mismo modo para la imagen en color:

ingrese la descripción de la imagen aquí

NOTA: Por supuesto, está centrado. Deberá realizar modificaciones adicionales para mover el foco a otros lugares.

Similar a la respuesta de Abid. Pero el código es para la imagen coloreada.

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('turtle.jpg',1)
rows,cols = img.shape[:2]
zeros = np.copy(img)
zeros[:,:,:] = 0
a = cv2.getGaussianKernel(cols,900)
b = cv2.getGaussianKernel(rows,900)
c = b*a.T
d = c/c.max()
zeros[:,:,0] = img[:,:,0]*d
zeros[:,:,1] = img[:,:,1]*d
zeros[:,:,2] = img[:,:,2]*d

cv2.imwrite('vig2.png',zeros)

Imagen original (tomada de Pexels con licencia CC0)

Imagen original (tomada de Pexels con licencia CC0)

Después de aplicar Vignette con un sigma de 900 (es decir, `cv2.getGaussianKernel (cols, 900))

Después de aplicar una viñeta con un  sigma de 900 (tenga en cuenta que he comprimido la imagen con Facebook y, por lo tanto, la calidad es baja. De lo contrario, el filtro no tiene nada que ver con cambiar la calidad o la nitidez de la imagen)

Después de aplicar Vignette con un sigma de 300 (es decir, `cv2.getGaussianKernel (cols, 300))

ingrese la descripción de la imagen aquí

Además, puede enfocar el efecto de viñeta a las coordenadas de su deseo simplemente cambiando la media del gaussiano a su punto de enfoque de la siguiente manera.

import cv2
import numpy as np

img = cv2.imread('turtle.jpg',1)

fx,fy = 1465,180 # Add your Focus cordinates here
fx,fy = 145,1000 # Add your Focus cordinates here
sigma = 300 # Standard Deviation of the Gaussian
rows,cols = img.shape[:2]
fxn = fx - cols//2 # Normalised temperory vars
fyn = fy - rows//2

zeros = np.copy(img)
zeros[:,:,:] = 0

a = cv2.getGaussianKernel(2*cols ,sigma)[cols-fx:2*cols-fx]
b = cv2.getGaussianKernel(2*rows ,sigma)[rows-fy:2*rows-fy]
c = b*a.T
d = c/c.max()
zeros[:,:,0] = img[:,:,0]*d
zeros[:,:,1] = img[:,:,1]*d
zeros[:,:,2] = img[:,:,2]*d

zeros = add_alpha(zeros)
cv2.imwrite('vig4.png',zeros)

El tamaño de la imagen de la tortuga es 1980×1200 (WxH). El siguiente es un ejemplo que se centra en la cordinate 1465,180 (es decir fx,fy = 1465,180) (Tenga en cuenta que he reducido la varianza para ejemplificar el cambio de enfoque)

ingrese la descripción de la imagen aquí

El siguiente es un ejemplo que se centra en la cordinate 145,1000 (es decir fx,fy = 145,1000)

ingrese la descripción de la imagen aquí

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *