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);
//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);
//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);
waitKey(0);
}
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.
fuente