ヘッセ行列は、エッジ検出、テクスチャ分析などの画像セグメンテーションの分野など、画像処理において幅広い用途に使用できます。
原理:
座標 (x, y) に対する画像のピクセル値の関数を f(x, y) とすると、 f(x+dx, y+dy) を f(x0, y0) で展開すると、次のようになります。式
この式を行列で表し、余りを切り捨てた場合
上式の右辺の第 3 項の 2 番目の行列は、2 次元空間のヘッセ行列です。
簡略化された 2D
2 次元画像を例にとると、画像内の点構造は等方性ですが、線構造は異方性です。したがって、ヘシアン行列を使用して画像内の線形構造を強調し、点状の構造とノイズ ポイントを除去できます。同様に、画像内の点構造を見つけて他の情報を除外するためにも使用できます。
一般に、デジタル グラフィックス上で 2 次微分を直接実行しますが、この方法はロバスト性が低く、ノイズの影響を受けやすいです。したがって、ガウス関数が増加します。
応用:
次に、注釈付きの Frangi フィルターに基づいて血管強調を実行します。
def getkernel(kernel=7,sigma=1.0):
w = kernel//2
PI = 3.1415926
[Y,X]= np.mgrid[-w:w+1,-w:w+1]
xxGauKernel = (1-X**2/sigma**2)*np.exp(-1*(X**2+Y**2)/(2*sigma**2))*(-1/(2*PI*sigma**4))
yyGauKernel = (1-Y**2/sigma**2)*np.exp(-1*(X**2+Y**2)/(2*sigma**2))*(-1/(2*PI*sigma**4))
xyGauKernel = np.exp(-1*(X**2+Y**2)/(2*sigma**2))*((X*Y)/(2*PI*sigma**6))
return xxGauKernel,yyGauKernel,xyGauKernel
def Hessian2Dd(image,kernel=7,sigma=1.0):
xxGauKernel,yyGauKernel,xyGauKernel = getkernel(kernel,sigma)
xxDerivae = cv2.filter2D(image,-1,xxGauKernel,borderType =cv2.BORDER_CONSTANT)
yyDerivae = cv2.filter2D(image,-1,yyGauKernel,borderType =cv2.BORDER_CONSTANT)
xyDerivae = cv2.filter2D(image,-1,xyGauKernel,borderType =cv2.BORDER_CONSTANT)
return xxDerivae,xyDerivae,yyDerivae
def eig2image(Dxx,Dxy,Dyy):
Dxx=np.array(Dxx,dtype=float)
Dyy=np.array(Dyy,dtype=float)
Dxy=np.array(Dxy,dtype=float)
if (len(Dxx.shape)!=2):
print("len(Dxx.shape)!=2,不是二维数组!")
return 0
tmp = np.sqrt( (Dxx - Dyy)**2 + 4*Dxy**2)
v2x = 2*Dxy
v2y = Dyy - Dxx + tmp
mag = np.sqrt(v2x**2 + v2y**2)
i=np.array(mag!=0)
v2x[i==True] = v2x[i==True]/mag[i==True]
v2y[i==True] = v2y[i==True]/mag[i==True]
v1x = -v2y
v1y = v2x
mu1 = 0.5*(Dxx + Dyy + tmp)
mu2 = 0.5*(Dxx + Dyy - tmp)
check=abs(mu1)>abs(mu2)
Lambda1=mu1.copy()
Lambda1[check==True] = mu2[check==True]
Lambda2=mu2
Lambda2[check==True] = mu1[check==True]
Ix=v1x
Ix[check==True] = v2x[check==True]
Iy=v1y
Iy[check==True] = v2y[check==True]
return Lambda1,Lambda2,Ix,Iy
def FrangiFilter2D(I):
I=np.array(I,dtype=float)
defaultoptions = {'FrangiScaleRange':(1,10), 'FrangiScaleRatio':2, 'FrangiBetaOne':0.5, 'FrangiBetaTwo':15, 'verbose':True,'BlackWhite':True};
options=defaultoptions
sigmas=np.arange(options['FrangiScaleRange'][0],options['FrangiScaleRange'][1],options['FrangiScaleRatio'])
sigmas.sort()
beta = 2*pow(options['FrangiBetaOne'],2)
c = 2*pow(options['FrangiBetaTwo'],2)
shape=(I.shape[0],I.shape[1],len(sigmas))
ALLfiltered=np.zeros(shape)
ALLangles =np.zeros(shape)
Rb=0
S2=0
for i in range(len(sigmas)):
#Show progress
if(options['verbose']):
print('Current Frangi Filter Sigma: ',sigmas[i])
S_round=np.round(3*sigmas[i])*2+1
[Dxx,Dxy,Dyy] = Hessian2Dd(I,S_round,sigmas[i])
Dxx = pow(sigmas[i],2)*Dxx
Dxy = pow(sigmas[i],2)*Dxy
Dyy = pow(sigmas[i],2)*Dyy
[Lambda2,Lambda1,Ix,Iy]=eig2image(Dxx,Dxy,Dyy)
angles = np.arctan2(Ix,Iy)
Lambda1[Lambda1==0] = np.spacing(1)
Rb = (Lambda2/Lambda1)**2
S2 = Lambda1**2 + Lambda2**2
Ifiltered = np.exp(-Rb/beta) * (np.ones(I.shape)-np.exp(-S2/c))
if(options['BlackWhite']):
Ifiltered[Lambda1<0]=0
else:
Ifiltered[Lambda1>0]=0
ALLfiltered[:,:,i] = Ifiltered
ALLangles[:,:,i] = angles
if len(sigmas) > 1:
outIm=ALLfiltered.max(2)
else:
outIm = (outIm.transpose()).reshape(I.shape)
return outIm
テスト結果を表示:
フランジ フィルタリングの 3D バージョンの原理は 2D バージョンと同じです。この記事では直接提供されなくなりました。必要な読者は私にプライベート メッセージを送ってください。