上篇文章我们看到了效果,这篇文章来回答怎么实现的,也学一下通用的CV编程。
文件不多,工作量不大
init是包的入口,使用点号绝对路径导入
在上层目录里面串联着要使用的所有库
在看一眼效果,俩鼻孔真好看
库使用了精确的除法:
代码语言:javascript复制from __future__ import division
导入Python未来支持的语言特征division(精确除法),当我们没有在程序中导入该特征时,"/"操作符执行的是截断除法(Truncating Division),当我们导入精确除法之后,"/"执行的是精确除法,如下所示:
代码语言:javascript复制>>> 3/4
0
>>> from __future__ import division
>>> 3/4
0.75
导入精确除法后,若要执行截断除法,可以使用"//"操作符:
接下来读pupil的源码
一定要找到依赖库最少相对独立的文件,这样的实现很重要,大家都依赖。
接着看结构,只有一个类
init方法
事实上初始化的方法会确定很多东西,保证我们的程序按照一个可控的情况取运行。
最后的函数在下面有实现。
把虹膜抠出来
先说使用的装饰器:
一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。
而使用@staticmethod或@classmethod,就可以不需要实例化,直接以类名.方法名()来调用。
这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于 命名空间的整洁。
既然@staticmethod和@classmethod都可以直接类名.方法名()来调用,那他们有什么区别呢?从它们的使用上来看:
- @staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。
- @classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。 如果在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。 而@classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等,避免硬编码。
好处就是避免乱拉屎的情况。
CV是,先搞一个小的像素点,接着双边滤波一下,那么什么是双边略波?
双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的。均值滤波、中值滤波和高斯滤波,都属于各向同性滤波,它们对待噪声和图像的边缘信息都采取一样的态度,结果,噪声被磨平的同时,图像中具有重要地位的边缘、纹理和细节也同时被抹平了,这是我们所不希望看到的。具有简单、非迭代、局部的特点。双边滤波器的好处是可以做边缘保存(edge preserving),一般过去用的维纳滤波或者高斯滤波去降噪,都会较明显地模糊边缘,对于高频细节的保护效果并不明显,为了解决这个问题,人们陆续提出了一些算法来把图像边缘和噪声区别对待,比如双边滤波和导向滤波。
变得清晰了一些,然后腐蚀一下,变得大一点,二值化,最后把值返回。
检测虹膜并且找到对应得位置。
函数一开始没有说得,这里是寻找轮廓,以树形结构输出信息,储存所有点得信息。
输出是:
Python3里返回三个值:image,contours,hierarchy
image:可能是跟输入contour类似的一张二值图;
contours:list结构,列表中每个元素代表一个边沿信息。每个元素是(x,1,2)的三维向量,x表示该条边沿里共有多少个像素点,第三维的那个“2”表示每个点的横、纵坐标;
注意:如果输入选择cv2.CHAIN_APPROX_SIMPLE,则contours中一个list元素所包含的x点之间应该用直线连接起来,这个可以用cv2.drawContours()函数观察一下效果。
hierarchy:返回类型是(x,4)的二维ndarray。x和contours里的x是一样的意思。如果输入选择cv2.RETR_TREE,则以树形结构组织输出,hierarchy的四列分别对应下一个轮廓编号、上一个轮廓编号、父轮廓编号、子轮廓编号,该值为负数表示没有对应项。
使用了:
这样得处理办法,提取了我要的东西
下面是排序了一下,按照轮廓的面积排布。
排序是从小到大,现在又取了最后两个,两个最大的眼孔。
接下来看这个
就是几个函数而已
接着初始化
左右眼要同时满足才算矫正
阈值是左右眼都有,求和除以长度,有点面密度的味道
虹膜占多大
这个图清晰吧
先取中间的RIO区域,把图像抽取出来,X完以后就是一个面积,之后-不为黑色位置,不就是白色圈。最后一比
开始使用遍历的方法来找到二值化的阈值是多少
先计算一下平均的虹膜大小,创建一个数据容器,按照5的step计算20次。
这里注意,二值化的函数返回值有两个,需要[1],读取的是第二个参数的内容,是一张图。
接着计算这图的比值,将内容放到字典里面。
最后把20次的内容,做计算,事实上,使用的内置的min函数:
语法:min(iterable, *[, key, default]) 参数:iterable是可迭代的对象,key指定寻找最小值的关键字,若key不指定则采用默认位置,与内置函数sorted类似 返回值:返回值是iterable中寻找到的最小值
我们要的是瞳孔的位置,所以比值要小,这里取小。
如图所示
这里就是可以一个眼睛一个眼睛的校准,存到字典里面
校准20次就可以了
最后一个
上面那么多内容都是给它做准备
初始化
先用dlib找到人脸,接着是把要寻找的特征文件准备好,下面一个函数把姿态点计算出来。
@property的作用: 广泛用于类的定义中,把方法变成属性,保证对参数进行必要的检查,减少程序运行时出错的可能性。
是否定位的函数
在我们上面分析的代码里面
漏了一个函数,补全:
读这个
初始化的内容
内置的工具函数,下划线为了访问限制
这个函数比较复杂
把里面的点解出来,放一个数组里面,转换数据类型,放在新的数组里面
写挺明白的了
转换过的点在这里
把眼睛割出来
X[:,0]是numpy中数组的一种写法,表示对一个二维数组,取该二维数组第一维中的所有数据,第二维中取第0个数据,直观来说,X[:,0]就是取所有行的第0个数据, X[:,1] 就是取所有行的第1个数据。
然后
大概就这样把
前面4个取点,后面两个算东西,接着算比值
如图
写不动了。。。我之后出个补篇,把屁股擦了。