Można to osiągnąć za pomocą splotu transformacji odległości.
Użyj transformacji odległościowej na krawędzi maski. Następnie ustaw wartość progową tej transformacji odległości, aby usunąć wartości poza pewną odległością. Myślę, że sekretem uzyskania cieniowania jest splot wyniku transformacji odległości za pomocą jądra, które wygląda mniej więcej tak:
[ -1.0 -1.0 -1.0
-1.0 0.0 0.0
-1.0 0.0 1.0 ]
To powinno pomóc Ci zacząć we właściwym kierunku:
#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);
}
Funkcje Bevel i Emboss programu Photoshop działają przewidywalnie:
1) Oblicz transformację odległości w tymczasowym 8-bitowym obrazie jednokanałowym
Dłuto korzysta z euklidesowej transformacji odległości z pomiarem fazowania (3x3, 5x5 lub 7x7 w zależności od rozmiaru). Możesz użyć dokładnej euklidesowej transformacji odległości, jeśli chcesz, wolę tę od Meijster, ponieważ można ją wygładzić („Ogólny algorytm obliczania transformacji odległości w czasie liniowym”, MEIJSTER).
Smooth Bevel wykorzystuje transformację odległości Fazowanie 5-7-11, a następnie dwie aplikacje rozmycia ramki, aby utworzyć mapę wypukłości.
2) Zastosuj mapowanie wypukłości do obrazu transformacji odległości pośredniej. Odpowiednia jest oryginalna technika Blinna.
3) W celu zmiękczenia można wykonać splot normalnych powierzchni lub przefiltrować je za pomocą jądra.
4) Za pomocą mapy wypukłości normalne powierzchni są łączone z globalnym źródłem światła w celu obliczenia intensywności oświetlenia jako wartości od -1 do 1, gdzie wartości ujemne to cienie, wartości dodatnie są podświetlone, a wartość bezwzględna to jasność światła źródło.
5) Obliczane są dwa 8-bitowe tymczasowe obrazy jednokanałowe, jeden z intensywności podświetlenia, a drugi z cieni. Z tego miejsca kwestią trywialną jest użycie każdej maski do barwienia warstwy za pomocą koloru, trybu mieszania i krycia - jedna maska dla świateł, a druga dla cieni.
Kod źródłowy Visual Basic do implementacji niektórych z nich można znaleźć tutaj:
http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=51640&lngWId=1
Proszę odwiedzić mój projekt LayerEffects open source, aby dowiedzieć się więcej:
https://github.com/vinniefalco/LayerEffects.git
Mam nadzieję, że to komuś pomoże.
źródło