原文作者:aircraft

原文地址:https://www.cnblogs.com/DOMLX/p/8672489.html

 文中的一些图片以及思想很多都是参考https://www.cnblogs.com/My-code-z/p/5712524.html 大佬的思想 以及自己做一些个人理解的补充

  若想下载指静脉识别入门代码:https://github.com/lmskyle/process

  细化算法原理理解起来并不难,借助矩阵九宫格来实现。将九宫格定义并且编号成如下格式。

  在讲解之前有必要先看看书中是怎么说的:

  书中说的还是比较简洁的,毕竟是大牛写的,他们觉得很简单容易理解的东西,我们看起来就未必是这样了。好了闲话不多说 进入主题。

  第一步:为了不影响原图像的一些其他操作,先将原图像拷贝一份用来细化处理,在将细化后图片返回出去。

  第二步:就跟书里看的那样,需要满足四个条件来才能进行删除该点像素。这里进行的是沿着东南边界开始删除

      1: a. 2<= p2+p3+p4+p5+p6+p7+p8+p9<=6 

            大于等于2会保证p1点不是端点或孤立点,因为删除端点和孤立点是不合理的,小于等于6保证p1点是一个边界点,而不是一个内部点。等于0时候,周围没有等于1的像素,所以p1为孤立点,等于1的时候,周围只            有1个灰度等于1的像素,所以是端点(注:端点是周围有且只能有1个值为1的像素)。

          

       2:这里需要满足T(p1)=1  这里的T(p1)指的是以p2,p3...p8p9 就是p1邻居点进行轮转

          这里的轮转就是从p2开始不断的与后面的点进行组成元组的格式  比如(p2,p3)(p3,p4) (p4,p5)。。。(p9,p2) 看看这样组成的所有元组为(0,1)格式的是否恰好为1个

          假如为1个并且同时满足另外三个条件,那么他的样子大概会是这样的[[0,1,1]  这样轮转中就恰好有一个(0,1) 并且与1相邻的点必然还有像素值1 这样就是一个联通的区域 这时候p1就是边界点可以删除。

                                         [0,1,0]

                                         [0,0,0]]  

           大概的意思就是这样,我语文不好,不能说的很清楚,不过你们用本子画画就能理解我的意思了  见谅哈!!

       3:   P2*p4*p6 = 0

     4: p4*p6*p8 = 0

      这里 p4,p6出现了两次  在加上面的轮转判断 如果满足边界点条件 那么p4,p6中必然会有一个为0  至于为什么是p4,p6 就是因为这里是先沿着东南边界进行细化 

      将满足的点的索引值存入一个数组中,根据这个数组中点的索引值坐标  将图像中相应位置的点值置为0 完成一次边缘细化

  第三步:这里是沿着西北方向进行细化

      跟上面一步条件几乎一样,唯一改变就是第三和第四个条件,因为这里是为了沿着西北方向细化所以要调整为:p2*p4*p8 = 0    p2*p6*p8 = 0  这里的p2,p8出现两次的原因和 上面一步的p4,p6一样

       将满足的点的索引值存入一个数组中,根据这个数组中点的索引值坐标  将图像中相应位置的点值置为0 完成一次边缘细化

  最后:反复执行 第二步和第四步,不断的进行 左右的细化  直到没有点在可以细化  那么我们就得到了 细化后的骨架结构

现在原理已经解释完毕,那么就来看看python 是如何实现细化算法的

def neighbours(x,y,image):
"Return 8-neighbours of image point P1(x,y)
img = image
x_1, y_1, x1, y1 = x-1, y-1, x+1, y+1
return [ img[x_1][y], img[x_1][y1], img[x][y1], img[x1][y1], # P2,P3,P4,P5
img[x1][y], img[x1][y_1], img[x][y_1], img[x_1][y_1] ] # P6,P7,P8,P9 def transitions(neighbours):
n = neighbours + neighbours[0:1] # P2, P3, ... , P8, P9, P2
return sum( (n1, n2) == (0, 1) for n1, n2 in zip(n, n[1:]) ) # (P2,P3), (P3,P4), ... , (P8,P9), (P9,P2)
#将白色静脉区域细化成骨架结构  
def Refine(image):
Image_Thinned = image.copy() # deepcopy to protect the original image
changing1 = changing2 = 1 # the points to be removed (set as 0)
while changing1 or changing2: # iterates until no further changes occur in the image
# Step 1
changing1 = []
rows, columns = Image_Thinned.shape # x for rows, y for columns
for x in range(1, rows - 1): # No. of rows
for y in range(1, columns - 1): # No. of columns
P2,P3,P4,P5,P6,P7,P8,P9 = n = neighbours(x, y, Image_Thinned)
if (Image_Thinned[x][y] == 1 and # Condition 0: Point P1 in the object regions
2 <= sum(n) <= 6 and # Condition 1: 2<= N(P1) <= 6   The guarantee is not an isolated point and an endpoint or an internal point
transitions(n) == 1 and # Condition 2: S(P1)=1  (0,1)The number of rotation of the structure is 1, and the boundary point can be determined by adding other conditions
P2 * P4 * P6 == 0 and # Condition 3 Remove the southeast boundary point
P4 * P6 * P8 == 0): # Condition 4
changing1.append((x,y))
for x, y in changing1:
Image_Thinned[x][y] = 0
# Step 2
changing2 = [] for x in range(1, rows - 1):
for y in range(1, columns - 1):
P2,P3,P4,P5,P6,P7,P8,P9 = n = neighbours(x, y, Image_Thinned)
if (Image_Thinned[x][y] == 1 and # Condition 0
2 <= sum(n) <= 6 and # Condition 1
transitions(n) == 1 and # Condition 2
P2 * P4 * P8 == 0 and # Condition 3   remove the northwest border point
P2 * P6 * P8 == 0): # Condition 4
changing2.append((x,y))
for x, y in changing2:
Image_Thinned[x][y] = 0
return Image_Thinned

虽然我英文很差,但是我有百度翻译啊 ,就将我所有的注释都翻译成了英文。

这里我指给出了算法的函数原型,至于怎么调用中间的代码我就不给了,反正如果你需要用到这个算法,只要将归一化到(0,1)二值的话图片传入进来调用就行了

在看看细化后的效果图

原图:

细化后的图片:

原图的静脉是黑色的  后面我在处理的时候 将黑白二值化翻转了  白色代表静脉区域

看完这些有兴趣还可以看看我这篇对指静脉预处理提取纹理的博客:http://www.cnblogs.com/DOMLX/p/8989836.html

总结归纳:

      1,看的出来这个细化算法还是有不足的,没有那么的美观,图像在分叉点处存在像素的冗余,即非单像素点,这会使得以后对特征点的提取相当的麻烦。

      这就需要对细化算法进行改进了,这里可以采用一些模板算子对图像进行除去。

      2,至于原手指静脉图像中的噪声和阴影等会在骨架图像中产生各种毛刺,这些毛刺也会影响后期的处理。除去毛刺可以通过从每个端点开始沿着费零点搜索,直到

        交叉点时停止。在这个过程中,记录下每个端点上遍历的点数,然后取一个阈值,将小于阈值的那个端点搜索路径上的置为0。这样就完成了对图像的裁剪。

有兴趣还可以看看:

http://www.cnblogs.com/DOMLX/p/8989836.html 提取纹理特征

http://www.cnblogs.com/DOMLX/p/8672489.html 指静脉细化算法

http://www.cnblogs.com/DOMLX/p/8111507.html 指静脉切割过程

指静脉识别:

https://www.cnblogs.com/DOMLX/p/9491972.html

若有兴趣交流分享技术,可关注本人公众号,里面会不定期的分享各种编程教程,和共享源码,诸如研究分享关于c/c++,python,前端,后端,opencv,halcon,opengl,机器学习深度学习之类有关于基础编程,图像处理和机器视觉开发的知识

手指静脉细化算法过程原理解析 以及python实现细化算法的更多相关文章

  1. Web APi之过滤器执行过程原理解析【二】(十一)

    前言 上一节我们详细讲解了过滤器的创建过程以及粗略的介绍了五种过滤器,用此五种过滤器对实现对执行Action方法各个时期的拦截非常重要.这一节我们简单将讲述在Action方法上.控制器上.全局上以及授 ...

  2. Web APi之过滤器创建过程原理解析【一】(十)

    前言 Web API的简单流程就是从请求到执行到Action并最终作出响应,但是在这个过程有一把[筛子],那就是过滤器Filter,在从请求到Action这整个流程中使用Filter来进行相应的处理从 ...

  3. Twitter分布式自增ID算法snowflake原理解析

    以JAVA为例 Twitter分布式自增ID算法snowflake,生成的是Long类型的id,一个Long类型占8个字节,每个字节占8比特,也就是说一个Long类型占64个比特(0和1). 那么一个 ...

  4. Twitter分布式自增ID算法snowflake原理解析(Long类型)

    Twitter分布式自增ID算法snowflake,生成的是Long类型的id,一个Long类型占8个字节,每个字节占8比特,也就是说一个Long类型占64个比特(0和1). 那么一个Long类型的6 ...

  5. 一致性Hash算法的原理与实现(分布式映射算法)

    一致性Hash算法解决的问题: 解决分布式系统中的负载均衡问题 背景问题:有N台服务器提供缓存服务,需要对服务器进行负载均衡,将请求平均发到每台服务器上,每台服务器负载1/N的服务 硬Hash映射:将 ...

  6. 排序算法:快速排序解析及Python实现

    关键词:分而治之.递归.计算速度.基准值 1. 什么是分而治之? 1.1 分而治之(divide and conquer)一种递归式方法 1.2 找出基线条件,这种条件必须尽可能简单 1.3 不断将问 ...

  7. 【Socket通信】关于Socket通信原理解析及python实现

    Socket(套接字)通信{网络通信其实就是Socket间的通信},首先了解下概念:[来源于百度百科] "两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket.& ...

  8. 【python原理解析】python中分片的实现原理及使用技巧

    首先:说明什么是序列? 序列中的每一个元素都会被分配一个序号,即元素的位置,也称为索引:在python中的序列包含:字符串.列表和元组 然后是:什么是分片? 分片就是通过操作索引访问及获得序列的一个或 ...

  9. 【算法】(查找你附近的人) GeoHash核心原理解析及代码实现

    本文地址 原文地址 分享提纲: 0. 引子 1. 感性认识GeoHash 2. GeoHash算法的步骤 3. GeoHash Base32编码长度与精度 4. GeoHash算法 5. 使用注意点( ...

随机推荐

  1. MVC - Routing - 网址路由

    1. Routing  : 路由 主要是比对通过浏览器传来的http要求与响应适当的网址给浏览器. @Html.ActionLink("关于","About", ...

  2. FTP无法获取目录及文件

    在防火墙打开的情况下 如果不能获取,尝试将C:\windows\system32\svchost.exe 加入防火墙允许通道中. 并且设置为 主动模式

  3. Log--检查各数据库日志的使用情况

    -- Recovery model, log reuse wait description, log file size,-- log usage size and compatibility lev ...

  4. web集群时session同步的3种方法

    在做了web集群后,你肯定会首先考虑session同步问题,因为通过负载均衡后,同一个IP访问同一个页面会被分配到不同的服务器上,如果session不同步的话,一个登录用户,一会是登录状态,一会又不是 ...

  5. perationalError: (2003, "Can't connect to MySQL server on u'192.168.1.6' (timed out)")

    在Ubuntu(192.168.1.20)中部署项目后,mysql还在另外一台windows(192.168.1.6)机子上,ping windows时可以ping通,但是访问项目提示: perati ...

  6. 「BZOJ 3123」「SDOI 2013」森林「启发式合并」

    题意 你有一个森林,你需要支持两个操作 查询两个结点路径上权值第\(k\)小 两个点之间连一条边 强制在线,结点数\(\leq 8\times 10^4\) 题解 如果可以离线,这就是一个主席树板子题 ...

  7. SDUT OJ 数据结构实验之排序八:快速排序

    数据结构实验之排序八:快速排序 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Problem Description 给定N ...

  8. Python开发MapReduce系列(一)WordCount Demo

    原创,转发请注明出处. MapReduce是hadoop这只大象的核心,Hadoop 中,数据处理核心就是 MapReduce 程序设计模型.一个Map/Reduce 作业(job) 通常会把输入的数 ...

  9. 1、TensorFlow简介

    参考:http://www.tensorfly.cn/tfdoc/get_started/basic_usage.html 1.用TensorFlow构造一个简单的线性拟合: # -*- coding ...

  10. Qt 学习之路 2(47):视图选择

    Qt 学习之路 2(47):视图选择 豆子 2013年3月28日 Qt 学习之路 2 34条评论 选择是视图中常用的一个操作.在列表.树或者表格中,通过鼠标点击可以选中某一项,被选中项会变成高亮或者反 ...