参考博客: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