エッジ(=グレー値の高い領域と低い領域の間の境界線)を探しているのではなく、隆線(その周囲よりも細い線または細い線)を探しているので、エッジフィルターは理想的ではないかもしれません:エッジフィルターは2つの側面(ラインの両側に1つ)とラインの中央に低い応答を提供します。
追加:エッジ検出器とリッジ検出器の違いをより明確に説明するよう求められた場合。この回答が非常に長くなっている場合は、事前に謝罪します。
エッジ検出器は(通常)一次微分演算子です:入力画像を3Dランドスケープとして想像する場合、エッジ検出器はそのランドスケープの各ポイントで傾斜の急峻さを測定します:
拡張された明るい領域または暗い領域の境界線を検出する場合、これで十分です。しかし、OPの画像の静脈については、同じことを示します。各静脈の左右の輪郭:
また、キャニーエッジ検出器の結果の「二重線パターン」についても説明します。
それでは、これらの細い線(つまり、尾根)をどのように検出しますか?アイデアは、ピクセル値を(局所的に)2次多項式で近似できることです。つまり、画像関数が場合、と小さな値に対して:gxy
g(x,y)≈12x2∂2g∂x2+xy∂2g∂x∂y+12y2∂2g∂y2+x∂g∂x+y∂g∂y+g(0,0)
または、マトリックス形式で:
g(x,y)≈12(xy).⎛⎝⎜∂2g∂x2∂2g∂x∂y∂2g∂x∂y∂2g∂y2⎞⎠⎟.(xy)+(xy).(∂g∂x∂g∂y)+g(0,0)
二次微分行列は「ヘッセ行列」。興味のある2次構造を記述します。⎛⎝⎜∂2g∂x2∂2g∂x∂y∂2g∂x∂y∂2g∂y2⎞⎠⎟
この関数の2次部分は、上のヘッセ行列をその固有値の対角行列の回転倍に分解することにより、ある角度だけ回転した2つの放物線の合計に変換できます。(マトリックス分解)。回転は気にしません(どの方向の尾根も検出したいので)、とのみ関心があります。λ1x2+λ2y2λ1λ2
この関数近似にはどのような形状がありますか?実際、それほど多くはありません:
隆起を検出するために、上のプロットの最後のように見える画像内の領域を見つけたいので、ヘッシアンの主要な固有値が大きい領域を探しています(マイナーな固有値と比較して)。これを検出する最も簡単な方法は、各ピクセルで主要な固有値を計算することです。これが、以下のリッジフィルターの機能です。
リッジフィルタは、おそらくより良い結果が得られます。Mathematicaの組み込みRidgeFilter
(各ピクセルでヘッセ行列の主要な固有値を計算)を画像で試しました:
ご覧のとおり、すべての細い暗線にはピークが1つしかありません。バイナリ化とスケルトン化の結果:
スケルトンを切り取り、画像から小さなコンポーネント(ノイズ)を削除すると、この最終的なスケルトンが得られます。
完全なMathematicaコード:
ridges = RidgeFilter[ColorNegate@src];
skeleton = SkeletonTransform[Binarize[ridges, 0.007]];
DeleteSmallComponents[Pruning[skeleton, 50], 50]
追加:
私はMatlabの専門家ではありません。リッジフィルターが組み込まれているかどうかはわかりませんが、「手作業で」実装する方法を示します(再びMatematicaを使用)。先ほど言ったように、リッジフィルターはヘッセ行列の主要な固有値です。Mathematicaでその固有値を記号的に計算できます:
eigenvalue=Last[Eigenvalues[(HxxHxyHxyHyy)]]
=>12(Hxx+Hyy+H2xx+4H2xy−2HxxHyy+H2yy−−−−−−−−−−−−−−−−−−−−−−−√)
あなたがしなければならないのは、二次導関数、、を計算し(ガウスフィルターのsobelまたは導関数を使用)、それらを挿入することです上記の式に追加すると、リッジフィルターが得られます。 H xy H yyHxxHxyHyy