
在

點的某個鄰域內具有任意階導數,則


















我們一般將其表示為:


尺度空間理論的基本思想是:在圖像信息處理模型中引入一個被視為尺度的參數,通過連續變化尺度參數獲得多尺度下的尺度空間表示序列,對這些序列進行尺度空間主輪廓的提取,並以該主輪廓作為一種特征向量,實現邊緣、角點檢測和不同分辨率上的特征提取等。
尺度空間理論的特點是:將傳統的單尺度圖像信息處理技術納入尺度不斷變化的動態分析框架中,更容易獲取圖像的本質特征。尺度空間中各尺度圖像的模糊程度逐漸變大,能夠模擬人在距離目標由近到遠時目標在視網膜上的形成過程。
尺度空間理論的一個直觀理解:我們人在遠近不同距離上對同一物體,都可以實現辨識。
高斯卷積核是實現尺度變換的唯一線性核(高斯函數可以稱為最偉大和最重要的函數)。
一幅圖像的尺度空間可以定義為:




對全圖直接做偏導操作 = 對原圖以特定的高斯核做卷積
基於這個推論,對於圖的Hessian運算將極大地降低計算量,同時提高運算速度。
|a b|
|c d|
這個是一元二次方程,可以計算得到有兩個解,分別為
λ1=(a+d+√((a-d)^2+4bc))/2
λ2=(a+d-√((a-d)^2+4bc))/2










二維高斯分布,其曲線圖如下:
根據定義,我們可以求得一下內容。
二維高斯函數的一階偏導數:
二維高斯函數的二階偏導數
這里從原函數到二階偏導的推斷都是本科的知識,建議大家自己推一下,很簡單,對於這個問題的深入認識很有幫助,后面我們在代碼部分將再一次提及。
二、“血管增強”算法的原理
Frangi A F, Niessen W J, Vincken K L, et al. 《Multiscale vessel enhancement filtering》[C]//International Conference on Medical Image Computing and Computer-Assisted Intervention. Springer Berlin Heidelberg, 1998: 130-137.


//使用默認參數設定Frangi
frangi2d_opts_t opts;
frangi2d_createopts( & opts);
//讀取圖片,進行處理
Mat input_img = imread( "E:/template/51.bmp" , 0 );
Mat input_img_fl;
//轉換為單通道,浮點運算
input_img.convertTo(input_img_fl, CV_32FC1);
//進行處理
Mat vesselness, scale, angles;
frangi2d(input_img_fl, vesselness, scale, angles, opts);
//顯示結果
vesselness.convertTo(vesselness, CV_8UC1, 255 );
scale.convertTo(scale, CV_8UC1, 255 );
angles.convertTo(angles, CV_8UC1, 255 );
imshow( "result" , vesselness);
}
//Frangi filter//
/////////////////
//frangi濾波主要過程
void frangi2d( const cv : : Mat & src, cv : : Mat & J, cv : : Mat & scale, cv : : Mat & directions, frangi2d_opts_t opts);
////////////////////
//Helper functions//
////////////////////
//計算Hessian矩陣 with parameter sigma on src, save to Dxx, Dxy and Dyy.
void frangi2d_hessian( const cv : : Mat & src, cv : : Mat & Dxx, cv : : Mat & Dxy, cv : : Mat & Dyy, float sigma);
//參數設置 (sigma_start = 3, sigma_end = 7, sigma_step = 1, BetaOne = 1.6, BetaTwo 0.08)
void frangi2d_createopts(frangi2d_opts_t * opts);
//計算特征值 from Dxx, Dxy, Dyy. Save results to lambda1, lambda2, Ix, Iy.
void frangi2_eig2image( const cv : : Mat & Dxx, const cv : : Mat & Dxy, const cv : : Mat & Dyy, cv : : Mat & lambda1, cv : : Mat & lambda2, cv : : Mat & Ix, cv : : Mat & Iy);
void frangi2d_hessian( const cv : : Mat & src, cv : : Mat & Dxx, cv : : Mat & Dxy, cv : : Mat & Dyy, float sigma);
j = 0 ;
for ( int y = - round( 3 * sigma); y < = round( 3 * sigma); y ++ ){
kern_xx_f[i * n_kern_y + j] = 1 .0f / ( 2 .0f * M_PI * sigma * sigma * sigma * sigma) * (x * x / (sigma * sigma) - 1 ) * exp( - (x * x + y * y) / ( 2 .0f * sigma * sigma));
kern_xy_f[i * n_kern_y + j] = 1 .0f / ( 2 .0f * M_PI * sigma * sigma * sigma * sigma * sigma * sigma) * (x * y) * exp( - (x * x + y * y) / ( 2 .0f * sigma * sigma));
j ++ ;
}
i ++ ;
}
for ( int j = 0 ; j < n_kern_y; j ++ ){
for ( int i = 0 ; i < n_kern_x; i ++ ){
kern_yy_f[j * n_kern_x + i] = kern_xx_f[i * n_kern_x + j];
}
}
這里我們就是首先把“特定的高斯核”計算出來。然后我們回憶當時介紹的二維高斯函數的二階偏導數
那么它翻譯成代碼是什么樣子的了?matlab版本
//DGaussxx = 1/(2*pi*Sigma^4) * (X.^2/Sigma^2 - 1) .* exp(-(X.^2 + Y.^2)/(2*Sigma^2));
//DGaussxy = 1/(2*pi*Sigma^6) * (X .* Y) .* exp(-(X.^2 + Y.^2)/(2*Sigma^2));
//DGaussyy = DGaussxx';
cv : : Mat tmp2 = - 1 * ((EWM(X,X) + EWM(Y,Y)) / ( 2 * Sigma * Sigma));
exp(tmp2,tmp2);

Mat tmp, tmp2;
tmp2 = Dxx - Dyy;
sqrt(tmp2.mul(tmp2) + 4 * Dxy.mul(Dxy), tmp);
Mat v2x = 2 * Dxy;
Mat v2y = Dyy - Dxx + tmp;
//normalize
Mat mag;
sqrt((v2x.mul(v2x) + v2y.mul(v2y)), mag);
Mat v2xtmp = v2x.mul( 1 .0f / mag);
v2xtmp.copyTo(v2x, mag != 0 );
Mat v2ytmp = v2y.mul( 1 .0f / mag);
v2ytmp.copyTo(v2y, mag != 0 );
//eigenvectors are orthogonal
Mat v1x, v1y;
v2y.copyTo(v1x);
v1x = - 1 * v1x;
v2x.copyTo(v1y);
//compute eigenvalues
Mat mu1 = 0 . 5 * (Dxx + Dyy + tmp);
Mat mu2 = 0 . 5 * (Dxx + Dyy - tmp);

for (float sigma = opts.sigma_start; sigma <= opts.sigma_end; sigma += opts.sigma_step){……}
//多尺度疊加
for (int i=1; i < ALLfiltered.size(); i++){
maxVals = max(maxVals, ALLfiltered[i]);
whatScale.setTo(sigma, ALLfiltered[i] == maxVals);
ALLangles[i].copyTo(outAngles, ALLfiltered[i] == maxVals);
sigma += opts.sigma_step;
}
程序最外面的框架告訴我們,整個程序是多次運算(尺度)的疊加。
Dyy = Dyy * sigma * sigma;
Dxy = Dxy * sigma * sigma;
//calculate (abs sorted) eigenvalues and vectors
Mat lambda1, lambda2, Ix, Iy;
frangi2_eig2image(Dxx, Dxy, Dyy, lambda1, lambda2, Ix, Iy);
在每次計算中,首先計算出的值,代碼中對於的變量叫做lambda1,lambda2。
lambda2.setTo(nextafterf( 0 , 1 ), lambda2 == 0 );
Mat Rb = lambda1.mul( 1 . 0 / lambda2);
Rb = Rb.mul(Rb);
Mat S2 = lambda1.mul(lambda1) + lambda2.mul(lambda2);
Mat tmp1, tmp2;
exp( - Rb / beta, tmp1);
exp( - S2 / c, tmp2);


float c = 2 * opts.BetaTwo * opts.BetaTwo;


