Application of Hessian Matrix in Vascular Enhancement

       The Hessian matrix has a wide range of applications in image processing: in the field of image segmentation, including edge detection, texture analysis, etc.

principle:

      Assuming that the function of the image pixel value with respect to the coordinates (x, y) is f(x, y), then expand f(x+dx, y+dy) at f(x0, y0) to obtain the following formula

39dc308f3123831e7b5d97cd0108277e.png

      If this formula is represented by a matrix, and the remainder is discarded

cbd5e5513af2a7ea14293dfce2198097.png

      The second matrix in the third term on the right side of the above equation is the Hessian matrix in two-dimensional space.

95ec2415bd0ccda4b0c7a21670e49d1c.png

      Simplified 2D

8fefd7ad22fa39fdf5f27609bbb6dc9b.png

      Taking a two-dimensional image as an example, the point structure in the image is isotropic, while the linear structure is anisotropic. Therefore, we can use the Hessian matrix to enhance the linear structure in the image and filter out the point-like structure and noise points. Similarly, it can also be used to find out the point structure in the image and filter out other information.

      Generally, the second-order derivation is directly performed on digital graphics, but this method has poor robustness and is easily disturbed by noise. So it will increase the Gaussian function.

application:

We next perform vessel enhancement based on the annotated Frangi filter.

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

Show test results:

ce645c81582ce81a667d9fee81ce1db7.png

9449f3a09b365bc5bdc36152e6392518.png

The principle of the 3D version of Frangi filtering is the same as that of the 2D version. This article will no longer provide it directly. Readers who need it can private message me.

Guess you like

Origin blog.csdn.net/weixin_41202834/article/details/121882547