¿Algoritmo de bisel alfa de mapa de bits?

14

Estoy buscando crear un algoritmo que agregue un efecto de bisel a un mapa de bits usando su alfa como un mapa de relieve.

¿Cómo iría haciendo algo como esto? He probado la iluminación especular pero solo obtengo el brillo y no la sombra.

Aquí está el efecto del que estoy hablando (hecho con Photoshop): ingrese la descripción de la imagen aquí

Todos estos se realizaron utilizando size: 30px(La profundidad del bisel del contorno del mapa de bits), angle 130, altitude 50.

De izquierda a derecha, de arriba a abajo:

  1. Cincel Bisel duro
  2. Bisel Suave Bisel
  3. Bisel liso
  4. Cincel duro con soften: 16px- ¿un bisel borroso?

Estoy tratando de crear cada uno de estos efectos, ¿cómo haría para crear el bisel básico? y qué necesito para llegar a cada uno de ellos desde ese bisel

Shedokan
fuente

Respuestas:

10

Esto se puede lograr con una convolución de la transformación de distancia.

Use una transformación de distancia en el borde de la máscara. Luego, umbral de esta transformación de distancia para eliminar valores más allá de cierta distancia. Creo que el secreto para obtener el sombreado es convolver el resultado de la transformación de distancia con un núcleo que se parece a esto:

[ -1.0  -1.0  -1.0
  -1.0   0.0   0.0
  -1.0   0.0   1.0 ]

Esto debería ayudarlo a comenzar en la dirección correcta:

#include "opencv/cv.h"
#include "opencv/highgui.h"

using namespace cv;
using namespace std;

int main() {
    Mat mask, dist, bevel;
    mask = Mat::zeros(200, 400, CV_8U);
    rectangle(mask, Point(30,30), Point(180,180), Scalar(255), -1);
    circle(mask, Point(30,30), 50, Scalar(0), -1);
    circle(mask, Point(180,180), 50, Scalar(0), -1);
    circle(mask, Point(300,100), 75, Scalar(255), -1);
    imshow("1",mask);

ingrese la descripción de la imagen aquí

    //find edges and invert image for distance transform
    Canny(mask, dist, 50, 150);
    dist = 255-dist;
    distanceTransform(dist, dist, CV_DIST_L2, CV_DIST_MASK_5);
    threshold(dist, dist, 20, 20, CV_THRESH_TRUNC);
    blur(dist, dist, Size(3,3));
    dist.convertTo(bevel, CV_8U);
    equalizeHist(bevel, bevel);
    imshow("2",bevel);

ingrese la descripción de la imagen aquí

    //convolve with secret sauce
    float d[] = {-1,-2,-3,
                 -2, 0, 0,
                 -3, 0, 1 };
    Mat kernel(3, 3, CV_32F, d);
    kernel = kernel - mean(kernel)[0];
    filter2D(dist, dist, CV_32F, kernel);

    //normalize filtering result to [-1, 1]
    double maxVal;
    minMaxLoc(dist, NULL, &maxVal);
    dist = 128 * dist / maxVal;

    //convert and display result
    dist.convertTo(bevel, CV_8U, 1, 128);
    bevel = bevel.mul(mask)/255;
    imshow("3", bevel);

ingrese la descripción de la imagen aquí

    waitKey(0);
}
Matt M.
fuente
¡Se ven increíbles! El que tiene suavizar parece borroso, pero ¿cómo voy a hacer el "bisel liso" a partir de ellos?
Shedokan
Creo que Smooth Bevel difumina la máscara de distancia antes de la convolución y Soften difumina el resultado después de la convolución.
Matt M.
4

Photoshop Bevel and Emboss funciona de manera predecible:

1) Calcular una transformación de distancia en una imagen temporal de un solo canal de 8 bits

  • Cincel utiliza la Transformación de distancia euclidiana con una métrica de chaflán (3x3, 5x5 o 7x7 según el tamaño). Puede usar una transformación de distancia euclidiana exacta si lo desea, prefiero la de Meijster, ya que puede hacerse sin alias ("Algoritmo general para calcular transformaciones de distancia en tiempo lineal", MEIJSTER).

  • Smooth Bevel usa una transformación de distancia Chamfer 5-7-11 seguida de dos aplicaciones de un cuadro borroso, para producir el mapa de relieve.

2) Aplicar mapeo de relieve a la imagen de transformación de distancia intermedia. La técnica original de Blinn es adecuada.

3) Para suavizar puede realizar una convolución en las superficies normales o puede filtrarlas usando un núcleo.

4) Usando el mapa de relieve, las normales de la superficie se combinan con la fuente de luz global para calcular la intensidad de la iluminación como un valor de -1 a 1, donde los valores negativos son sombras, los valores positivos son luces y el valor absoluto es la magnitud de la luz. fuente.

5) Se calculan dos imágenes temporales de un solo canal de 8 bits, una a partir de las intensidades de resaltado y la otra a partir de las sombras. A partir de ahí, es una cuestión trivial usar cada máscara para teñir la capa usando un color, modo de fusión y opacidad: una máscara para los reflejos y la otra para las sombras.

El código fuente de Visual Basic para implementar algo de esto se puede encontrar aquí:

http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=51640&lngWId=1

Visite mi proyecto LayerEffects de código abierto para obtener más información:

https://github.com/vinniefalco/LayerEffects.git

Espero que esto ayude a alguien.

Vinnie Falco
fuente
Gracias, estoy muy interesado en la transformación de distancia gaussiana que mencionó, ¿conoce algún código disponible? No puedo leer bien las fórmulas. :(
Shedokan
No he encontrado nada sobre el GDT, aparte de la información que ya he publicado.
Vinnie Falco
¿Qué quiere decir con "2) Aplicar mapeo de relieve a la imagen de transformación de distancia"? La transformación de distancia proporciona distancias (1 número para cada píxel), mientras que el mapeo de relieve requiere valores normales (2 números para cada píxel) ... ¿Está seguro de saber de qué está hablando?
Ivan Kuckir
@IvanKuckir Debería haber sido más claro: se puede calcular una superficie normal tratando la transformación de distancia como un mapa de altura y calculando dx / dy a partir de valores verticales y horizontales vecinos. Estos dos números proporcionan la normalidad requerida para el mapeo de relieve.
Vinnie Falco