Алгоритм растрового альфа-скоса?

14

Я ищу, чтобы создать алгоритм, который добавляет эффект скоса к растровому изображению, используя его альфа в качестве карты рельефа.

Как бы я пошел делать что-то подобное? Я пробовал зеркальное освещение, но я получаю только подсветку, а не тень.

Вот эффект, о котором я говорю (сделанный с помощью Photoshop): введите описание изображения здесь

Все это было сделано с помощью size: 30px(глубина скоса от контура битовой карты), angle 130, altitude 50.

Слева направо, сверху вниз:

  1. Зубило Твердый скос
  2. Стамеска Мягкая фаска
  3. Гладкий скос
  4. Зубило Хард с soften: 16px- затуманенное скос?

Я пытаюсь создать каждый из этих эффектов, как мне создать базовый скос? и что мне нужно, чтобы добраться до каждого из них с этого скоса

Shedokan
источник

Ответы:

10

Это может быть достигнуто с помощью свертки преобразования расстояния.

Используйте преобразование расстояния по краю маски. Затем пороговое значение этого преобразования расстояния для удаления значений за пределами некоторого расстояния. Я думаю, секрет получения затенения заключается в том, чтобы свести результат преобразования расстояния с ядром, которое выглядит примерно так:

[ -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);
}
Мэтт М.
источник
Те выглядят потрясающе! Тот, что с размягчением, выглядит как пятно, но как мне сделать из них "Smooth Bevel"?
Шедокан
Я считаю, что Smooth Bevel размывает маску расстояния до свертки, а Soften размывает результат после свертки.
Мэтт М.
4

Фотошоп 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

Я надеюсь, что это поможет кому-то.

Винни Фалько
источник
Спасибо, меня очень интересует упомянутое вами преобразование расстояния Гаусса, вам известен какой-либо код? Я не умею хорошо читать формулы. :(
Шедокан
Я не нашел ничего о GDT, кроме информации, которую я уже разместил.
Винни Фалько
Что вы подразумеваете под "2) Применить рельефное отображение к изображению с преобразованием расстояния"? Преобразование расстояний дает расстояния (1 число для каждого пикселя), в то время как для Bump mapping требуются нормали (2 числа для каждого пикселя) ... Вы уверены, что знаете, о чем говорите?
Иван Кукир
@IvanKuckir Я должен был быть более ясным - нормаль поверхности можно вычислить, обрабатывая преобразование расстояния как карту высот и вычисляя dx / dy из соседних значений по вертикали и горизонтали. Эти два числа обеспечивают нормаль, необходимую для рельефного отображения.
Винни Фалько