Isso pode ser realizado com uma convolução da transformação de distância.
Use uma transformação de distância na borda da máscara. Em seguida, limpe essa transformação de distância para remover valores além de alguma distância. Eu acho que o segredo para obter o sombreamento é envolver o resultado da transformação de distância com um kernel que se parece com isso:
[ -1.0 -1.0 -1.0
-1.0 0.0 0.0
-1.0 0.0 1.0 ]
Isso deve ajudá-lo a começar na direção certa:
#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);
}
O Bevel and Emboss do Photoshop funciona previsivelmente:
1) Calcule uma transformação de distância em uma imagem temporária de canal único de 8 bits
O cinzel usa a transformação de distância euclidiana com uma métrica de chanfro (3x3, 5x5 ou 7x7, dependendo do tamanho). Você pode usar uma transformação de distância euclidiana exata, se preferir, a de Meijster, pois ela pode ser feita com anti-alias ("Algoritmo geral para calcular transformações de distância em tempo linear", MEIJSTER).
O chanfro suave usa uma transformação de distância de chanfro 5-7-11 seguida de duas aplicações de um desfoque de caixa, para produzir o mapa de relevo.
2) Aplique o mapeamento de relevo à imagem de transformação de distância intermediária. A técnica original de Blinn é adequada.
3) Para amolecer, você pode realizar uma convolução nas normais da superfície ou filtrá-las usando um kernel.
4) Usando o mapa de relevo, as normais da superfície são combinadas com a fonte de luz global para calcular a intensidade da iluminação como um valor de -1 a 1, onde valores negativos são sombras, valores positivos são realces e o valor absoluto é a magnitude da luz. fonte.
5) Duas imagens temporárias de canal único de 8 bits são calculadas, uma das intensidades de destaque e a outra das sombras. A partir daí, é trivial usar cada máscara para colorir a camada usando uma cor, modo de mesclagem e opacidade - uma máscara para os realces e a outra para as sombras.
O código fonte do Visual Basic para implementar parte disso pode ser encontrado aqui:
http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=51640&lngWId=1
Visite meu projeto de código aberto LayerEffects para saber mais:
https://github.com/vinniefalco/LayerEffects.git
Espero que isso ajude alguém.
fonte