Nie szukasz krawędzi (= granic między rozszerzonymi obszarami o wysokiej i niskiej wartości szarości), szukasz grzbietów (cienkie linie ciemniejsze lub jaśniejsze niż ich sąsiedztwo), więc filtry krawędziowe mogą nie być idealne: Filtr krawędziowy będzie daje dwie flanki (po jednej z każdej strony linii) i niską odpowiedź na środku linii:
DODAJ : Jeśli poproszono Cię o wyjaśnienie różnicy między detektorem krawędzi a detektorem grzbietu. Z góry przepraszam, jeśli ta odpowiedź będzie bardzo długa.
Detektor krawędzi jest (zwykle) pierwszym operatorem pochodnym: jeśli wyobrażasz sobie obraz wejściowy jako krajobraz 3D, detektor krawędzi mierzy nachylenie zbocza w każdym punkcie tego krajobrazu:
Jeśli chcesz wykryć granicę rozszerzonego jasnego lub ciemnego regionu, jest to w porządku. Ale dla żył na obrazie OP da ci to samo: kontury po lewej i prawej stronie każdej żyły:
To wyjaśnia również „wzór podwójnej linii” w wynikach detektora krawędzi Canny:
Jak zatem rozpoznajesz te cienkie linie (np. Grzbiety)? Chodzi o to, że wartości pikseli może być (lokalnie) aproksymować 2nd rzędu wielomianu, czyli wtedy, gdy funkcja jest obraz , wówczas dla małych wartości i :gxy
g(x,y)≈12x2∂2g∂x2+xy∂2g∂x∂y+12y2∂2g∂y2+x∂g∂x+y∂g∂y+g(0,0)
lub w formie matrycy:
g(x,y)≈12(xy).⎛⎝⎜∂2g∂x2∂2g∂x∂y∂2g∂x∂y∂2g∂y2⎞⎠⎟.(xy)+(xy).(∂g∂x∂g∂y)+g(0,0)
Macierz pochodna drugiego rzędu nazywany jest „ Matryca Hesji ”. Opisuje interesującą nas strukturę drugiego rzędu.⎛⎝⎜∂2g∂x2∂2g∂x∂y∂2g∂x∂y∂2g∂y2⎞⎠⎟
Część tej funkcji drugiego rzędu można przekształcić w sumę dwóch paraboli obróconych o pewien kąt, poprzez rozkład powyższej macierzy Hesji na czasy obrotu diagonalnej macierzy jej wartości własnych ( Rozkład macierzy ). Nie dbamy o rotację (chcemy wykrywać grzbiety w dowolnej orientacji), więc interesują nas tylko iλ1x2+λ2y2λ1λ2
Jakie kształty może mieć to przybliżenie funkcji? Właściwie nie tak wiele:
Aby wykryć grzbiety, chcemy znaleźć obszary na obrazie, które wyglądają jak ostatnie z powyższych wykresów, dlatego szukamy obszarów, w których główna wartość własna Hesji jest duża (w porównaniu do mniejszej wartości własnej). Najprostszym sposobem na wykrycie tego jest obliczenie głównej wartości własnej dla każdego piksela - i to właśnie robi poniższy filtr kalenicowy.
Filtr grzbiet będzie prawdopodobnie dać lepsze wyniki. Wypróbowałem wbudowaną RidgeFilter
funkcję Mathematica (która oblicza główną wartość własną macierzy Hesji dla każdego piksela) na twoim obrazie:
Jak widać, na każdą cienką ciemną linię jest tylko jeden pik. Plony binaryzacji i szkieletowania:
Po przycięciu szkieletu i usunięciu małych elementów (szumów) z obrazu, otrzymuję ten ostateczny szkielet:
Pełny kod Mathematica:
ridges = RidgeFilter[ColorNegate@src];
skeleton = SkeletonTransform[Binarize[ridges, 0.007]];
DeleteSmallComponents[Pruning[skeleton, 50], 50]
DODAJ:
Nie jestem ekspertem Matlaba, nie wiem, czy ma on wbudowany filtr kalenicy, ale mogę pokazać, jak zaimplementować go „ręcznie” (ponownie, używając Matematiki). Jak powiedziałem, filtr kalenicowy jest główną wartością własną macierzy Hesji. Potrafię obliczyć tę wartość własną symbolicznie w Mathematica:
eigenvalue=Last[Eigenvalues[(HxxHxyHxyHyy)]]
=>12(Hxx+Hyy+H2xx+4H2xy−2HxxHyy+H2yy−−−−−−−−−−−−−−−−−−−−−−−√)
Musisz więc obliczyć drugie pochodne , , (używając sobela lub pochodnej filtru gaussowskiego) i wstawić je do powyższego wyrażenia i masz swój filtr kalenicy. H xy H yyHxxHxyHyy