Ogólnie wykrywanie krawędzi sprowadza się do wykrywania obszarów obrazu o wysokiej wartości gradientu.
W naszym przypadku z grubsza widzimy gradient jako pochodną funkcji obrazu, dlatego wielkość gradientu daje informacje o tym, jak bardzo twój obraz zmienia się lokalnie (w odniesieniu do sąsiednich pikseli / tekstur).
Teraz krawędź jest, jak mówisz, oznaką nieciągłości, więc teraz, kiedy zdefiniowaliśmy gradient, jasne jest, że te informacje są wszystkim, czego potrzebujemy. Gdy znajdziemy gradient obrazu, wystarczy po prostu zastosować do niego próg, aby uzyskać wartość binarną edge / non-edge.
Jak znaleźć ten gradient, tak naprawdę pytasz, a ja jeszcze nie odpowiem :)
Wiele sposobów! Oto kilka :)
Wbudowane funkcje cieniowania
Zarówno hlsl, jak i glsl oferują funkcje pochodne. W GLSL masz dFdx i dFdy, które dają ci odpowiednio informacje o gradiencie w kierunku xiy. Zazwyczaj funkcje te są oceniane w bloku 2x2 fragmentów.
Jeśli nie interesuje Cię jeden kierunek, dobrym sposobem na uzyskanie zwartego wyniku, który wskazuje, jak silny jest gradient w regionie, jest szerokość, która daje ci tylko sumę wartości bezwzględnej dFdy i dFdy.
Prawdopodobnie interesuje Cię krawędź ogólnego obrazu, a nie konkretnego kanału, więc możesz chcieć przekształcić swoją funkcję obrazu w luma. Mając to na uwadze, jeśli chodzi o wykrywanie krawędzi, twój shader może zawierać coś takiego jak:
float luminance = dot(yourFinalColour,vec3(0.2126, 0.7152, 0.0722));
float gradient = fwidth(luminance );
float isEdge = gradient > threshold;
Przy wysokim progu znajdziesz grubsze krawędzie i możesz przegapić niektóre, odwrotnie, przy niskim progu możesz wykryć fałszywe krawędzie. Musisz eksperymentować, aby znaleźć próg, który lepiej odpowiada Twoim potrzebom.
Powód, dla którego te funkcje działają, jest warty wspomnienia, ale teraz nie mam na to czasu, prawdopodobnie zaktualizuję tę odpowiedź później :)
Post-proces przestrzeni ekranu
Możesz być bardziej wymyślny, teraz pole wykrywania krawędzi w przetwarzaniu obrazu jest ogromne. Mógłbym przytoczyć dziesiątki dobrych sposobów wykrywania wykrycia krawędzi zgodnie z Twoimi potrzebami, ale na razie bądźmy prostymi, jeśli jesteś zainteresowany, mogę przytoczyć więcej opcji!
Pomysł byłby więc podobny do powyższego, z tą różnicą, że można spojrzeć na szersze sąsiedztwo i użyć zestawu ciężarków na otaczających próbkach, jeśli chcesz. Zazwyczaj uruchamiasz splot obrazu, używając jądra, które daje w rezultacie dobre informacje o gradiencie.
Bardzo popularnym wyborem jest jądro Sobela
Które odpowiednio dają gradienty w kierunkach xiy:
G r a di e n t M.gn i t u de = ( G r a di e n tx)2)+ ( G r a di e n ty)2)-----------------------√
Następnie możesz przekroczyć próg w taki sam sposób, jak wspomniałem powyżej.
To jądro, jak widać, nadaje większą wagę środkowemu pikselowi, więc skutecznie oblicza gradient + odrobinę wygładzenia, co tradycyjnie pomaga (często obraz jest gaussowski zamazany, aby wyeliminować małe krawędzie).
Powyższe działa całkiem dobrze, ale jeśli nie lubisz wygładzania, możesz użyć jąder Prewitt:
(Uwaga: spieszy mi się, wkrótce napiszę odpowiednio sformatowany tekst zamiast obrazów!)
Naprawdę jest o wiele więcej jąder i technik, aby znaleźć wykrywanie krawędzi w procesie przetwarzania obrazu, a nie w czasie rzeczywistym, więc wykluczyłem bardziej skomplikowane (nie zamierzone) metody, ponieważ prawdopodobnie byłoby dobrze z funkcjami dFdx / y .