听百家之言,集百家智慧,站在巨人肩上攀登
特别说明,本文依据Raffaele教授的workshop整理而成,读者朋友们不要草率复制粘贴作为自己的论文或者报告。
本文旨在帮助大家理解指纹识别的机制和一些算法原理,有一个好的理解之后,读者朋友们需要自己做出一些修改,提出自己的想法。
文章目录
- 指纹的分割
- 预估局部脊线的方向
- 计算局部脊线的频率
- 指纹增强处理
- 参考
指纹的分割
预估局部脊线的方向
计算局部脊线的频率
指纹增强处理
增强的目的,是为了更好的提取指纹的模式,也就是指纹的本身的特点,简而言之就是指纹的脊线。
我们使用一组Gabor filter来进行contextual convolution,达到我们的增强的目的。
在这个案例中,我们假定的是一个固定的脊线频率,所以所有的filter都会有一样的周期,那么唯一变动的参数就是方向。
由于是contextual convolution,那么根据相应的脊线方向,不同的filter会被使用到每一个像素上面。不过,这种操作在opencv里面暂时没有被实现,而且我们使用python去实现也会很复杂低效。
所以,这里我们把所有的filter都使用到整个图像,换句话说,每一个filter都会生成一个对应的filter之后的图像,然后,我们把filter之后的图像正确的像素拿出来,组合到一起,生产最后我们需要的增强图像。我们使用离散的方向索引作为我们的查找表来组合。
详细的代码:
首先我们创建8个方向的filter,组成filter bank
# Create the filter bank
or_count = 8
gabor_bank = [gabor_kernel(ridge_period, o) for o in np.arange(0, np.pi, np.pi/or_count)]
show(*gabor_bank)
然后我们使用每一种filter对这个图像进行filter操作:
# Filter the whole image with each filter
# Note that the negative image is actually used, to have white ridges on a black background as a result
nf = 255-fingerprint
all_filtered = np.array([cv.filter2D(nf, cv.CV_32F, f) for f in gabor_bank])
show(nf, *all_filtered)
可以看到,第一张图是原始图,后面的是8张处理之后的图:
那么我们可以发现,每个方向的filter 处理的图像的确是不一样的,根据方向进行卷积:
最后,我们把所有的卷积操作之后的图片组合起来:
对于每个像素,找到和这个像素的脊线方向最接近的filter,然后得到他的index,然后将相应卷积之后的结果拿出来,合并到最后的结果图像中,如此组装所有的像素点,得到最后的图像。
最后一步是使用之前分割得到的mask去进行处理,得到最终增强的图片,如下:
y_coords, x_coords = np.indices(fingerprint.shape)
# For each pixel, find the index of the closest orientation in the gabor bank
orientation_idx = np.round(((orientations % np.pi) / np.pi) * or_count).astype(np.int32) % or_count
# Take the corresponding convolution result for each pixel, to assemble the final result
filtered = all_filtered[orientation_idx, y_coords, x_coords]
# Convert to gray scale and apply the mask
enhanced = mask & np.clip(filtered, 0, 255).astype(np.uint8)
show(fingerprint, enhanced)
Charles@Shenzhen, 20210304
参考
[1] Hong, Lin, and Anil Jain. “Fingerprint enhancement.” Automatic Fingerprint Recognition Systems. Springer, New York, NY, 2004. 127-143.