Cela peut être accompli avec une convolution de la transformée de distance.
Utilisez une transformation de distance sur le bord du masque. Limitez ensuite cette transformation de distance pour supprimer les valeurs au-delà d'une certaine distance. Je pense que le secret pour obtenir l'ombrage est de convoluer le résultat de la transformation de distance avec un noyau qui ressemble à ceci:
[ -1.0 -1.0 -1.0
-1.0 0.0 0.0
-1.0 0.0 1.0 ]
Cela devrait vous aider à démarrer dans la bonne direction:
#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);
}
Le biseau et l'embossage de Photoshop fonctionnent de manière prévisible:
1) Calculer une transformation de distance dans une image à canal unique 8 bits temporaire
Chisel utilise la transformation de distance euclidienne avec une métrique de chanfrein (3x3, 5x5 ou 7x7 selon la taille). Vous pouvez utiliser une transformation de distance euclidienne exacte si vous le souhaitez, je préfère celle de Meijster car elle peut être rendue anti-aliasée ("Un algorithme général pour calculer les transformations de distance en temps linéaire", MEIJSTER).
Smooth Bevel utilise une transformation de distance Chanfrein 5-7-11 suivie de deux applications d'un flou de boîte, pour produire la carte de relief.
2) Appliquer le mappage de relief à l'image de transformation de distance intermédiaire. La technique originale de Blinn convient.
3) Pour l'adoucissement, vous pouvez effectuer une convolution sur les normales de surface ou vous pouvez les filtrer à l'aide d'un noyau.
4) En utilisant la carte de relief, les normales de surface sont combinées avec la source de lumière globale pour calculer l'intensité d'éclairage en tant que valeur de -1 à 1 où les valeurs négatives sont des ombres, les valeurs positives sont des reflets et la valeur absolue est la magnitude de la lumière la source.
5) Deux images temporaires à canal unique de 8 bits sont calculées, l'une à partir des intensités de surbrillance et l'autre à partir des ombres. À partir de là, il est trivial d'utiliser chaque masque pour teinter le calque en utilisant une couleur, un mode de fusion et une opacité - un masque pour les reflets et l'autre pour les ombres.
Le code source Visual Basic pour implémenter une partie de ceci peut être trouvé ici:
http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=51640&lngWId=1
Veuillez visiter mon projet open source LayerEffects pour en savoir plus:
https://github.com/vinniefalco/LayerEffects.git
J'espère que ça aidera quelqu'un.
la source