Это может быть достигнуто с помощью свертки преобразования расстояния.
Используйте преобразование расстояния по краю маски. Затем пороговое значение этого преобразования расстояния для удаления значений за пределами некоторого расстояния. Я думаю, секрет получения затенения заключается в том, чтобы свести результат преобразования расстояния с ядром, которое выглядит примерно так:
[ -1.0 -1.0 -1.0
-1.0 0.0 0.0
-1.0 0.0 1.0 ]
Это должно привести вас в правильном направлении:
#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);
}
Фотошоп Bevel and Emboss работает предсказуемо:
1) Вычислить преобразование расстояния во временном 8-битном одноканальном изображении
Долото использует евклидово преобразование расстояния с метрикой фаски (3x3, 5x5 или 7x7 в зависимости от размера). Вы можете использовать точное евклидово преобразование расстояния, если хотите, я предпочитаю одно из Meijster, так как его можно сделать сглаженным («Общий алгоритм вычисления расстояний в линейном времени», MEIJSTER).
Smooth Bevel использует преобразование расстояния Chamfer 5-7-11, за которым следуют два применения размытия рамки для создания карты рельефа.
2) Примените рельефное отображение к изображению с промежуточным преобразованием расстояния. Оригинальная техника Блинна подходит.
3) Для смягчения вы можете выполнить свертку на поверхности нормали или отфильтровать их с помощью ядра.
4) Используя карту рельефа, нормали поверхности объединяются с глобальным источником света, чтобы вычислить интенсивность освещения в виде значения от -1 до 1, где отрицательные значения - тени, положительные значения - блики, а абсолютное значение - величина света. источник.
5) Рассчитываются два 8-битных временных канала одноканальных изображений, одно из которых определяется интенсивностью подсветки, а другое - тенями. Оттуда очень просто использовать каждую маску, чтобы подкрасить слой, используя цвет, режим наложения и непрозрачность - одну маску для светлых участков, а другую для теней.
Исходный код Visual Basic для реализации некоторых из них можно найти здесь:
http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=51640&lngWId=1
Пожалуйста, посетите мой проект LayerEffects с открытым исходным кодом, чтобы узнать больше:
https://github.com/vinniefalco/LayerEffects.git
Я надеюсь, что это поможет кому-то.
источник