一、我们想要求的方向场的定义为:
对于任意
一点(x,y),该点的方向可以定义为其所在脊线(或谷线)位置的切线方向与水平轴
之间的夹角:
将一条直线顺时针或逆时针旋转 180°,直线的
方向保持不变。
因此,指纹方向场的取值范围一般定义为[0,π)或[-π/2, π/2),前
闭后开区间的意义在于保证方向场取值的唯一性。
二、基于梯度场计算方向场
论文 《
Analyzing Oriented Patterns》 网址:
https://wenku.baidu.com/view/f741d931cc175527072208f7.html
概述:
核心思想便是对其二倍角的分量进行平均,
流程:给定指纹图像I ,其梯度可以表示为
,
表示x方向的梯度和y方向的梯度
根据已有的梯度场,分别计算
W简单理解就是卷积运算
方向场的计算公式为:
继续可得
方向场一致性
:
当所有的方向都互相平行时,方向场一致性取最大值 1;反之,当所有的方向
都相反时,方向场一致性取最小值 0;在这两种极端情况之间,其值相应的也在 0
与 1 之间变化。因此,方向场一致性可以作为方向场有序程度的度量。所以最后结果要做一个0-1之间的normalize.
实现:
//变量
Mat img = cv::imread( "e:/template/finger.bmp",0);
Mat matX;Mat matY;
Mat Gxx;Mat Gyy;Mat Gxy;//和论文标识对应
Mat matTheta;//方向场
Mat matCoh;//方向场一致性
//实验图片
/*Mat matTst = Mat(Size(11,11),CV_8UC1,Scalar(0));
line(matTst,Point(5,0),Point(5,11),Scalar(255));
line(matTst,Point(0,5),Point(11,5),Scalar(255));*/
Mat matTst = img.clone();
//x方向求导
Sobel(matTst,matX,CV_16SC1,1,0);
//y方向求导
Sobel(matTst,matY,CV_16SC1,0,1);
//转换为float计算,否则后面算爆掉
matX.convertTo(matX,CV_32FC1);
matY.convertTo(matY,CV_32FC1);
//计算3个G
Gxx = matX.mul(matX);
Gyy = matY.mul(matY);
Gxy = matX.mul(matY);
Mat kernel8 = Mat(Size(8,8),CV_32FC1,Scalar(1));
filter2D(Gxx,Gxx,Gxx.depth(),kernel8);
filter2D(Gyy,Gyy,Gyy.depth(),kernel8);
filter2D(Gxy,Gxy,Gxy.depth(),kernel8);
//计算方向场
Mat matTmp = 2 * Gxy;
matTmp = matTmp / (Gxx - Gxy);
matTheta = Mat(matTst.size(),CV_32FC1,Scalar(0));
for (int i = 0 ;i< matTmp.rows;i++)
for (int j = 0 ;j<matTmp.cols;j++)
matTheta.at<float>(i,j) = 0.5 * atan(matTmp.at<float>(i,j)) + 3.1415926/2;
//计算方向场一致性
matTmp = Gxx - Gyy;
matTmp = matTmp.mul(matTmp);
Mat matTmp2 = 4*Gxy.mul(Gxy);
matTmp += matTmp2;
cv::sqrt(matTmp,matCoh);
matCoh = matCoh / (Gxx+Gxy);
//显示结果
normalize(matTheta,matTheta,0,1,NORM_MINMAX);
normalize(matCoh,matCoh,0,1,NORM_MINMAX);
结果:
三、基于hessian特征值的方向场
原理:
参考frangi相关知识
代码:https://github.com/ntnu-bioopt/libfrangi
github frangi项目
调用:
//hessian方法
frangi2d_opts_t opts;
opts.sigma_start = DEFAULT_SIGMA_START;
opts.sigma_end = DEFAULT_SIGMA_END;
opts.sigma_step = DEFAULT_SIGMA_STEP;
opts.BetaOne = DEFAULT_BETA_ONE; //ignore blob-like structures?
opts.BetaTwo = DEFAULT_BETA_TWO; //appropriate background suppression for this specific image, but can change.
opts.BlackWhite = true;
Mat J;Mat Scale;Mat directions;
img.convertTo(img,CV_32FC1,1.0/255);
frangi2d(img,J,Scale,directions,opts);
结果: