参考博客: https://blog.csdn.net/xue_wenyuan/article/details/51533953
https://blog.csdn.net/jinshengtao/article/details/17797641
傅里叶变换是一种信号处理中的有力工具, 可以帮助我们将图像从空域转换到频域, 并提取到空域上不易提取的特征. 但是经过傅里叶变换后,
图像在不同位置的频度特征往往混合在一起, 但是 Gabor 滤波器却可以抽取空间局部频度特征, 是一种有效的纹理检测工具.
在图像处理中, Gabor 函数是一个用于边缘提取的线性滤波器. Gabor 滤波器的频率和方向表达同人类视觉系统类似. 研究发现, Gabor 滤波器十分适合纹理表达和分离. 在空间域中, 一个二维 Gabor 滤波器是一个由正弦平面波调制的高斯核函数.
gabor 核函数的表达式:
复数表达式:
可以拆解: 实部:
虚部:
其中:
和
参数介绍:
方向(θ): 这个参数指定了 Gabor 函数并行条纹的方向, 它的取值为 0 到 360 度
波长(λ): 它的值以像素为单位指定, 通常大于等于 2. 但不能大于输入图像尺寸的五分之一.
相位偏移(φ): 它的取值范围为 - 180 度到 180 度. 其中, 0he180 度分别对应中心对称的 center-on 函数和 center-off 函数, 而 - 90 度和 90 度对应反对称函数.
长宽比 (γ): 空间纵横比, 决定了 Gabor 函数形状(support, 我翻译为形状) 的椭圆率(ellipticity). 当γ= 1 时, 形状是圆的. 当γ< 1 时, 形状随着平行条纹方向而拉长. 通常该值为 0.5
带宽(b):Gabor 滤波器的半响应空间频率带宽 b 和σ/ λ的比率有关, 其中σ表示 Gabor 函数的高斯因子的标准差, 如下:
σ的值不能直接设置, 它仅随着带宽 b 变化. 带宽值必须是正实数, 通常为 1, 此时, 标准差和波长的关系为:σ= 0.56 λ. 带宽越小, 标准差越大, Gabor 形状越大, 可见平行兴奋和抑制区条纹数量越多.
好介绍完毕.
现在进入主题, 我们提取纹理特征.
提取纹理特征, 还有增强纹理特征, 很多时候我们都是要先提取 ROI 感兴趣区域来进行操作的. 很多图片上的其他空间其实对我们没有什么太大的作用, 还影响程序的运行速度. 则我们只拿 ROI 区域进行纹理提取.
先看看原来的指静脉图片:
这图片区域很多, 一般我们只需要中间那部分指静脉纹理最多的 ROI 区域.
代码:
- #!/usr/bin/python
- #coding:utf-8
- import numpy as np
- import os
- import cv2
- def pathFile(path):
- return os.getcwd() + '/' + path
- def brightestColumn(img):
- w, h = img.shape
- r = range(h / 2, h - 1)
- c = range(0, w - 1)
- return img[c][:,r].sum(axis=0).argmax()
- # 构建 GABOR 滤波器
- def build_filters():
- """returns a list of kernels in several orientations"""
- filters = []
- ksize = 31 #gaborl 尺度 这里是一个
- for theta in np.arange(0, np.pi, np.pi / 4): #gaborl 方向 0 45 90 135 角度尺度的不同会导致滤波后图像不同
- params = {'ksize':(ksize, ksize), 'sigma':3.3, 'theta':theta, 'lambd':18.3,
- 'gamma':4.5, 'psi':0.89, 'ktype':cv2.CV_32F}
- #gamma 越大核函数图像越小, 条纹数不变, sigma 越大 条纹和图像都越大
- #psi 这里接近 0 度以白条纹为中心, 180 度时以黑条纹为中心
- #theta 代表条纹旋转角度
- #lambd 为波长 波长越大 条纹越大
- kern = cv2.getGaborKernel(**params) #创建内核
- kern /= 1.5*kern.sum()
- filters.append((kern,params))
- return filters
- # 滤波过程
- def process(img, filters):
- """returns the img filtered by the filter list"""
- accum = np.zeros_like(img) #初始化 img 一样大小的矩阵
- for kern,params in filters:
- fimg = cv2.filter2D(img, cv2.CV_8UC3, kern) #2D 滤波函数 kern 为其滤波模板
- np.maximum(accum, fimg, accum) #参数 1 与参数 2 逐位比较 取大者存入参数 3 这里就是将纹理特征显化更加明显
- return accum
- # 获取感兴趣区域的 top 和 bottom 值 用于切割显示图像
- def getRoiHCut2(img, p0):
- h, w = img.shape
- maxTop = np.argmax(img[0: h / 2, 0]) #在一定区域遍历选取指静脉边缘 具体高宽结合图像
- minTop = np.argmax(img[0: h / 2, w-1])
- if(maxTop < 65):
- maxBottom = np.argmax(img[(13 * h / 16): 40*h/48 , 0]) + 3 * h / 4
- minBottom = np.argmax(img[(13 * h / 16): 40*h/48, w-1]) + 3 * h / 4
- else:
- maxBottom = np.argmax(img[(3 * h / 4): h , 0]) + 3 * h / 4
- minBottom = np.argmax(img[(3 * h / 4): h, w-1]) + 3 * h / 4
- maxTop = (2*maxTop + minTop) / 3
- maxBottom = (maxBottom + 2*minBottom) / 3
- return img[maxTop:maxBottom,:]
- # 获取感兴趣区域范围
- def getRoi(img):
- height, width = img.shape
- heightDist = height / 4
- w = img.copy()
- w1 = w[heightDist:3 * heightDist,width / 4:]
- p0 = brightestColumn(w1) + heightDist + height / 2 #将手指边缘的高度加上四分之三原始高度
- pCol = w[:,p0:p0 + 1]
- pColInv = pCol[::-1]
- clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) #构建一个有限对比适应性直方图均衡化器
- w1_2 = clahe.apply(w[:, (p0 /20):(p0 + p0 / 2)]) #截取区域宽度大概是 p0 高度的一点五倍 apply 是获取一个返回值 这里是为了方便参数的传递
- w2 = getRoiHCut2(w1_2, p0)
res = cv2.resize(w2, (270, 150), interpolation=cv2.INTER_CUBIC)
- return clahe.apply(res)
- def logImg(img):
- return img.astype(float) / 255 #将图像数据转为0-1存储
- mDir=[]
- imgs = []
- dbDir = os.getcwd() + "/db100/"
- people = os.listdir(dbDir)
- people.sort()
- for person in people:
- personDir = dbDir + person + "/"
- hands = os.listdir(personDir)
- for hand in hands:
- handDir = personDir + hand + "/"
- mDir += [handDir]
- mg = os.listdir(handDir)
- mg.sort()
- imgs = imgs + [handDir + s.split(".")[0] for s in mg if not s.split(".")[0] == "Thumbs"]
- p0Imgs = [i.replace('db', 'gab_roi_db') for i in imgs] #p0Imgs 是每个文件的路径, mDir 是需要创建路径所有文件夹存放预处理后图片
- mDir = [i.replace('db', 'gab_roi_db') for i in mDir]
- # 判断路径是否存在 不存在就创建路径
- for path in mDir:
- if not os.path.exists(path):
- os.makedirs(path)
- filters = build_filters()
- for index, imgPath in enumerate(imgs):
- img = cv2.imread(imgPath + ".bmp", 0)
- res0 = process(getRoi(img), filters) #获取 ROI 进行直方图均衡化 切割后 在 gabor 滤波
- cv2.imwrite(p0Imgs[index] + ".png", res0)
- print index
- cv2.waitKey(0)
- cv2.destroyAllWindows()
好现在看看处理后的指静脉图片:
看起来还不错吧, 预处理之后就可以 进行纹理特征提取放入文件进行模式匹配啊 进行指静脉识别啊. 有兴趣的就期待在下之后的博客.
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/8989836.html