2021WSB-day2-4: Raffaele教授演示利用OpenCV和Python实现一个指纹识别系统 (含代码) part 1



听百家之言,集百家智慧,站在巨人肩上攀登


我的心太乱,有一些空白
我的心太乱,不敢再贪更多爱。
刚刚过了论文答辩,现在接着整理指纹识别的代码,Raffaele教授优雅的代码折服了我。

指纹的分割

首先加载一个指纹图片看看,使用numpy去存储:

fingerprint = cv.imread('samples/sample_1_1.png', cv.IMREAD_GRAYSCALE)
show(fingerprint, f'Fingerprint with size (w,h): {fingerprint.shape[::-1]}')

在这里插入图片描述
分割的目标主要是将指纹(前景)从背景中分割出来。图片的前景通过观察可知是由条状或者圆形的一些组成,而背景就只是一个均匀的底色而已。我们使用非常简单的手段,基于局部梯度就可以很容易实现我们的目标。

那么使用sobel滤波是一个非常好的选择。Sobel 算子是一个离散微分算子 (discrete differentiation operator)。 它结合了高斯平滑和微分求导,用来计算图像灰度函数的近似梯度。在图像边缘,相素值会发生显著的变化了。表示这一改变的一个方法是使用 导数 。 梯度值的大变预示着图像中内容的显著变化。用更加形象的图像来解释,假设我们有一张一维图形。下图1中灰度值的”跃升”表示边缘的存在,图2中使用一阶微分求导我们可以更加清晰的看到边缘”跃升”的存在。
在这里插入图片描述

图1 灰度值的”跃升”表示边缘的存在

在这里插入图片描述

图2 一阶微分求导:边缘”跃升”

具体的计算算法为:


Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。

我们使用sobel在指纹上:

# Calculate the local gradient (using Sobel filters)
gx, gy = cv.Sobel(fingerprint, cv.CV_32F, 1, 0), cv.Sobel(fingerprint, cv.CV_32F, 0, 1)
show((gx, 'Gx'), (gy, 'Gy'))

在这里插入图片描述

可以看到两个方向的梯度在指纹的条纹上展现了很明显的特征,横向Gx可以看到左右部分明显的轮廓。纵向Gy可以看到上下部分明显的轮廓。我们可以计算一下梯度的平方来看一下效果,平方就不管是正负了。

# Calculate the magnitude of the gradient for each pixel
gx2, gy2 = gx**2, gy**2
gm = np.sqrt(gx2 + gy2)
show((gx2, 'Gx**2'), (gy2, 'Gy**2'), (gm, 'Gradient magnitude'))

在这里插入图片描述
这里,gm是两个相加的结果。可以看到相加之后,主要的纹理特征已经可以很明显的提取出来了。Perfect!

接下来,使用一个积分模块,在一个方形区域进行积分:

# Integral over a square window
sum_gm = cv.boxFilter(gm, -1, (25, 25), normalize = False)
show(sum_gm, 'Integral of the gradient magnitude')

在这里插入图片描述

可以看到大部分指纹区域都变白色,而没有指纹区域还是黑色。我们可以使用一个简单的阈值来把背景和前景区分开:

# Use a simple threshold for segmenting the fingerprint pattern
thr = sum_gm.max() * 0.2
mask = cv.threshold(sum_gm, thr, 255, cv.THRESH_BINARY)[1].astype(np.uint8)
show(fingerprint, mask, cv.merge((mask, fingerprint, fingerprint)))

在这里插入图片描述
左边是原始的指纹图像,中间是mask,右边则是将指纹和mask合并之后得到的图像。

预估局部脊线的方向

位置(x,y)的局部脊线的方向在【0-180】之间,是脊线和水平轴形成的。对于每一个像素点,我们计算他的梯度Gx,Gy,也就是上面我们计算的。那么某一个像素点的方向就可以计算为这一点的梯度方向的正交方向,这个角度在一个预定的窗口中进行平均。

G x x = ∑ W G x 2 G_{xx}=\sum_W{G_x^2} Gxx=WGx2, G y y = ∑ W G y 2 G_{yy}=\sum_W{G_y^2} Gyy=WGy2, G x y = ∑ W G x G y G_{xy}=\sum_W{G_xG_y} Gxy=WGxGy

θ = π 2 + p h a s e ( G x x − G y y , 2 G x y ) 2 \theta=\frac{\pi}{2} + \frac{phase(G_{xx}-G_{yy}, 2G_{xy})}{2} θ=2π+2phase(GxxGyy,2Gxy)

对于每一个方向,我们也会去计算他的置信度,也就是计算在W 中有多少梯度有同样的方向,自然数量越多,计算的结果越可靠:
s t r e n g t h = ( G x x − G y y ) 2 + ( 2 G x y ) 2 G x x + G y y strength = \frac{\sqrt{(G_{xx}-G_{yy})^2+(2G_{xy})^2}}{G_{xx}+G_{yy}} strength=Gxx+Gyy(GxxGyy)2+(2Gxy)2

phase函数根据函数:
在这里插入图片描述
来计算角度,计算精度大约为0.3弧度,当x,y相等时,angle为0。
数学上函数atan2为:

该函数的值域为(-pi,pi],可以通过对负数结果加2pi的方法,将函数的结果映射到[0,2pi)范围内。

参考:

W = (23, 23)#我们定义一个23x23的窗口
gxx = cv.boxFilter(gx2, -1, W, normalize = False)# 在给定的滑动窗口大小下,对每个窗口内的像素值进行快速相加求和
gyy = cv.boxFilter(gy2, -1, W, normalize = False)
gxy = cv.boxFilter(gx * gy, -1, W, normalize = False) # gx * gy 
gxx_gyy = gxx - gyy
gxy2 = 2 * gxy

orientations = (cv.phase(gxx_gyy, -gxy2) + np.pi) / 2 # '-' to adjust for y axis direction phase函数计算方向场
sum_gxx_gyy = gxx + gyy
strengths = np.divide(cv.sqrt((gxx_gyy**2 + gxy2**2)), sum_gxx_gyy, out=np.zeros_like(gxx), where=sum_gxx_gyy!=0)#  计算置信度,也就是计算在W 中有多少梯度有同样的方向,自然数量越多,计算的结果越可靠
show(draw_orientations(fingerprint, orientations, strengths, mask, 1, 16), 'Orientation image')

在这里插入图片描述
可以看到脊线方向被正确识别出来。

Charles@Shenzhen

参考文献和学习资料

分割:
local gradient (Sobel filters)

[1] Mehtre, Babu M., and B. Chatterjee. “Segmentation of fingerprint images—a composite method.” Pattern recognition 22.4 (1989): 381-385.

[2] OpenCV: Sobel Filter

[3] https://docs.opencv.org/3.4/d2/d2c/tutorial_sobel_derivatives.html

local ridge orientation

[4] A.M. Bazen and S.H. Gerez, “Systematic methods for the computation of the directional fields and singular points of fingerprints,” in IEEE tPAMI, July 2002

评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MrCharles

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值