Algorytm skosu bitmapy?

14

Chcę stworzyć algorytm, który doda efekt fazy do mapy bitowej, używając jej alfa jako mapy wypukłości.

Jak mógłbym zrobić coś takiego? Próbowałem lustrzanego oświetlenia, ale dostaję tylko podświetlenie, a nie cień.

Oto efekt, o którym mówię (wykonany w Photoshopie): wprowadź opis zdjęcia tutaj

Wszystkie te zostały wykonane przy użyciu size: 30px(głębokość skosu od konturu bitmapy) angle 130, altitude 50.

Od lewej do prawej, od góry do dołu:

  1. Dłuto Twarde fazowanie
  2. Dłuto Soft Bevel
  3. Smooth Bevel
  4. Dłuto twarde z soften: 16px- niewyraźnym fazowaniem?

Staram się stworzyć każdy z tych efektów, jak bym przystąpił do tworzenia podstawowej fazy? i co muszę dostać się do każdego z nich z tego skosu

Shedokan
źródło

Odpowiedzi:

10

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);

wprowadź opis zdjęcia tutaj

    //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);

wprowadź opis zdjęcia tutaj

    //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);

wprowadź opis zdjęcia tutaj

    waitKey(0);
}
Matt M.
źródło
Te wyglądają niesamowicie! Ten z funkcją zmiękczania wygląda jak rozmycie, ale jak mam zrobić z nich „Smooth Bevel”?
Shedokan
Wierzę, że Smooth Bevel rozmywa maskę odległości przed splotem, a Soften rozmywa wynik po splotie.
Matt M.,
4

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.

Vinnie Falco
źródło
Dziękuję, jestem bardzo zainteresowany wspomnianą przez ciebie transformacją odległości Gaussa, czy znasz jakiś dostępny kod? Nie jestem w stanie dobrze czytać formuł. :(
Shedokan
Nie znalazłem nic na temat GDT poza informacjami, które już opublikowałem.
Vinnie Falco
Co rozumiesz przez „2) Zastosuj mapowanie wypukłości do obrazu transformacji odległości”? Transformacja odległości podaje odległości (1 liczba na każdy piksel), podczas gdy mapowanie nierówności wymaga wartości normalnych (2 liczby na każdy piksel) ... Czy na pewno wiesz, o czym mówisz?
Ivan Kuckir
@IvanKuckir Powinienem być bardziej wyraźny - normalną powierzchnię można obliczyć, traktując transformację odległości jako mapę wysokości i obliczając dx / dy z sąsiednich wartości pionowych i poziomych. Te dwie liczby zapewniają normalną wymaganą wartość dla mapowania wypukłości.
Vinnie Falco