Opencv之LBP特征(算法)

LBP(Local Binary Pattern),即局部二进制模式,对一个像素点以半径r画一个圈,在圈上取K个点(一般为8),这K个点的值(像素值大于中心点为1,否则为0)组成K位二进制数。此即局部二进制模式,实际中使用的是LBP特征谱的直方统计图。在旧版的Opencv里,使用CvHaarClassifierCascade函数,只支持Harr特征。新版使用CascadeClassifier类,还可以支持LBP特征。Opencv的人脸识别使用的是Extended LBP(即circle_LBP),其LBP特征值的模式为256(0-255)种。

优点:

1,旋转不变性(局部二进制循环左移或右移其表示不变)

2,一定程度上消除了光照变化的问题

3,纹理特征维度低,计算速度快

缺点:

1,当光照变化不均匀时,各像素间的大小关系被破坏,对应的LBP算子也就发生了变化

2,通过引入旋转不变的定义,使LBP算子更具鲁棒性。但这也使得LBP算子丢失了方向信息(如使局部二进制左移或右移,结果是一样的,但是图像不一样)

 以下介绍若干中LBP:

1,原始LBP。基于方框选取中心点周围8个像素,构成8位二进制

1# 以下不再重复这个部分 2import cv2 3import numpy as np 4 5image_path=your_img_path 6 7# 原始LBP算法:选取中心点周围的8个像素点,大于中心点为1,小于为0,将这些10顺时针串成8位二进制,即最终表示 8def origin_LBP(img): 9 dst = np.zeros(img.shape,dtype=img.dtype) 10 h,w=img.shape 11 start_index=1 12 for i in range(start_index,h-1): 13 for j in range(start_index,w-1): 14 center = img[i][j] 15 code = 0 16# 顺时针,左上角开始的8个像素点与中心点比较,大于等于的为1,小于的为0,最后组成82进制 17 code |= (img[i-1][j-1] >= center) << (np.uint8)(7) 18 code |= (img[i-1][j ] >= center) << (np.uint8)(6) 19 code |= (img[i-1][j+1] >= center) << (np.uint8)(5) 20 code |= (img[i ][j+1] >= center) << (np.uint8)(4) 21 code |= (img[i+1][j+1] >= center) << (np.uint8)(3) 22 code |= (img[i+1][j ] >= center) << (np.uint8)(2) 23 code |= (img[i+1][j-1] >= center) << (np.uint8)(1) 24 code |= (img[i ][j-1] >= center) << (np.uint8)(0) 25 dst[i-start_index][j-start_index]= code 26 return dst 27# 读入灰度图 28gray = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) 29# LBP处理 30org_lbp = origin_LBP(gray)cv2.imshow('img', gray) 31cv2.imshow('org_lbp', org_lbp) 32# 若针对视频取图片,delay=k时表示下一帧在kms后选取 33cv2.waitKey(0)

2,Extended LBP

1# 使用圆形选取框替代矩形框选:给定半径为r(半径越小,纹理越细),在此圆上选择K个点(选取点越多,亮度越高),同样,逆/顺时针组成K为二进制 2# 称为extend LBP 3def circular_LBP(img, radius=3, neighbors=8): 4 h,w=img.shape 5 dst = np.zeros((h-2*radius, w-2*radius),dtype=img.dtype) 6 for i in range(radius,h-radius): 7 for j in range(radius,w-radius): 8 # 获得中心像素点的灰度值 9 center = img[i,j] 10 for k in range(neighbors): 11 # 计算采样点对于中心点坐标的偏移量rx,ry 12 rx = radius * np.cos(2.0 * np.pi * k / neighbors) 13 ry = -(radius * np.sin(2.0 * np.pi * k / neighbors)) 14 # 为双线性插值做准备 15 # 对采样点偏移量分别进行上下取整 16 x1 = int(np.floor(rx)) 17 x2 = int(np.ceil(rx)) 18 y1 = int(np.floor(ry)) 19 y2 = int(np.ceil(ry)) 20 # 将坐标偏移量映射到0-1之间 21 tx = rx - x1 22 ty = ry - y1 23 # 根据0-1之间的x,y的权重计算公式计算权重,权重与坐标具体位置无关,与坐标间的差值有关 24 w1 = (1-tx) * (1-ty) 25 w2 = tx * (1-ty) 26 w3 = (1-tx) * ty 27 w4 = tx * ty 28 # 根据双线性插值公式计算第k个采样点的灰度值 29 neighbor=img[i+y1,j+x1] * w1 + img[i+y2,j+x1] *w2 + img[i+y1,j+x2] * w3 +img[i+y2,j+x2] *w4 30 # LBP特征图像的每个邻居的LBP值累加,累加通过与操作完成,对应的LBP值通过移位取得 31 dst[i-radius,j-radius] |= (neighbor>center) << (np.uint8)(neighbors-k-1) 32 return dst 33 34gray = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) 35circul_1_8 = circular_LBP(gray,1,8) 36circul_3_8 = circular_LBP(gray,3,8) 37circul_3_6 = circular_LBP(gray,3,6) 38# 最好是先计算完,统一显示 39cv2.imshow('img', gray) 40cv2.imshow('r1k8', circul_1_8) 41cv2.imshow('r3k8', circul_3_8) 42cv2.imshow('r3k6', circul_3_6) 43cv2.waitKey(0) 44cv2.destroyAllWindows()

其中,双线性插值公式为:

 3,加入旋转不变性

1# 在圆形选取框基础上,加入旋转不变操作 2def rotation_invariant_LBP(img, radius=3, neighbors=8): 3 h,w=img.shape 4 dst = np.zeros((h-2*radius, w-2*radius),dtype=img.dtype) 5 for i in range(radius,h-radius): 6 for j in range(radius,w-radius): 7 # 获得中心像素点的灰度值 8 center = img[i,j] 9 for k in range(neighbors): 10 # 计算采样点对于中心点坐标的偏移量rx,ry 11 rx = radius * np.cos(2.0 * np.pi * k / neighbors) 12 ry = -(radius * np.sin(2.0 * np.pi * k / neighbors)) 13 # 为双线性插值做准备 14 # 对采样点偏移量分别进行上下取整 15 x1 = int(np.floor(rx)) 16 x2 = int(np.ceil(rx)) 17 y1 = int(np.floor(ry)) 18 y2 = int(np.ceil(ry)) 19 # 将坐标偏移量映射到0-1之间 20 tx = rx - x1 21 ty = ry - y1 22 # 根据0-1之间的x,y的权重计算公式计算权重,权重与坐标具体位置无关,与坐标间的差值有关 23 w1 = (1-tx) * (1-ty) 24 w2 = tx * (1-ty) 25 w3 = (1-tx) * ty 26 w4 = tx * ty 27 # 根据双线性插值公式计算第k个采样点的灰度值 28 neighbor = img[i+y1,j+x1] * w1 + img[i+y2,j+x1] *w2 + img[i+y1,j+x2] * w3 +img[i+y2,j+x2] *w4 29 # LBP特征图像的每个邻居的LBP值累加,累加通过与操作完成,对应的LBP值通过移位取得 30 dst[i-radius,j-radius] |= (neighbor>center) << (np.uint8)(neighbors-k-1) 31 # 进行旋转不变处理 32 for i in range(dst.shape[0]): 33 for j in range(dst.shape[1]): 34 currentValue = dst[i,j] 35 minValue = currentValue 36 for k in range(1, neighbors): 37 # 对二进制编码进行循环左移,意思即选取移动过程中二进制码最小的那个作为最终值 38 temp = (np.uint8)(currentValue>>(neighbors-k)) | (np.uint8)(currentValue<<k) 39 if temp < minValue: 40 minValue = temp 41 dst[i,j] = minValue 42 43 return dst 44 45gray = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) 46rotation_invariant = rotation_invariant_LBP(gray,3,8) 47cv2.imshow('img', gray) 48cv2.imshow('ri', rotation_invariant) 49cv2.waitKey(0) 50cv2.destroyAllWindows()

4,等价模式

1def get_shifts(data): 2 ''' 3 计算跳变次数,即二进制码相邻2位不同,总共出现的次数 4 ''' 5 count = 0 6 binaryCode = "{0:0>8b}".format(data) 7 8 for i in range(1,len(binaryCode)): 9 if binaryCode[i] != binaryCode[(i-1)]: 10 count+=1 11 return count 12def create_table(img): 13 # LBP特征值对应图像灰度编码表,直接默认采样点为814 temp = 1 15 table =np.zeros((256),dtype=img.dtype) 16 for i in range(256): 17# 跳变小于3定义为等价模式类,共58,混合类算做118 if get_shifts(i)<3: 19 table[i] = temp 20 temp+=1 21 return table 22 23 24# 等价模式类:二进制码跳变次数小于38位二进制码共58种等价模式,其他256-58种为混合类。混合类的LBP特征将置为0,所以最终图像偏暗 25def uniform_pattern_LBP(img,table,radius=3, neighbors=8): 26 h,w=img.shape 27 dst = np.zeros((h-2*radius, w-2*radius),dtype=img.dtype) 28 for i in range(radius,h-radius): 29 for j in range(radius,w-radius): 30 # 获得中心像素点的灰度值 31 center = img[i,j] 32 for k in range(neighbors): 33 # 计算采样点对于中心点坐标的偏移量rx,ry 34 rx = radius * np.cos(2.0 * np.pi * k / neighbors) 35 ry = -(radius * np.sin(2.0 * np.pi * k / neighbors)) 36 # 为双线性插值做准备 37 # 对采样点偏移量分别进行上下取整 38 x1 = int(np.floor(rx)) 39 x2 = int(np.ceil(rx)) 40 y1 = int(np.floor(ry)) 41 y2 = int(np.ceil(ry)) 42 # 将坐标偏移量映射到0-1之间 43 tx = rx - x1 44 ty = ry - y1 45 # 根据0-1之间的x,y的权重计算公式计算权重,权重与坐标具体位置无关,与坐标间的差值有关 46 w1 = (1-tx) * (1-ty) 47 w2 = tx * (1-ty) 48 w3 = (1-tx) * ty 49 w4 = tx * ty 50 # 根据双线性插值公式计算第k个采样点的灰度值 51 neighbor = img[i+y1,j+x1] * w1 + img[i+y2,j+x1] *w2 + img[i+y1,j+x2] * w3 +img[i+y2,j+x2] *w4 52 # LBP特征图像的每个邻居的LBP值累加,累加通过与操作完成,对应的LBP值通过移位取得 53 dst[i-radius,j-radius] |= (neighbor>center) << (np.uint8)(neighbors-k-1) 54 # 进行LBP特征的UniformPattern编码 55 # 8位二进制码形成后,查表,对属于混合类的特征置0 56 if k==neighbors-1: 57 dst[i-radius,j-radius] = table[dst[i-radius,j-radius]] 58 return dst 59 60gray = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) 61table=create_table(gray) 62uniform_pattern = uniform_pattern_LBP(gray,table,3,8) 63cv2.imshow('img', gray) 64cv2.imshow('up', uniform_pattern) 65cv2.waitKey(0) 66cv2.destroyAllWindows()

5,MB_LBP:先对像素做区域平均处理,再使用原始LBP

1# 先对像素分割,用一个小区域的平均值代替这个区域,再用LBP特征处理 2def multi_scale_block_LBP(img,scale): 3 h,w= img.shape 4 5 # cellSize表示一个cell大小 6 cellSize = int(scale / 3) 7 offset = int(cellSize / 2) 8 cellImage = np.zeros((h-2*offset, w-2*offset),dtype=img.dtype) 9 10 for i in range(offset,h-offset): 11 for j in range(offset,w-offset): 12 temp = 0 13 for m in range(-offset,offset+1): 14 for n in range(-offset,offset+1): 15 temp += img[i+n,j+m] 16# 即取一个cell里所有像素的平均值 17 temp /= (cellSize*cellSize) 18 cellImage[i-offset,j-offset] = np.uint8(temp) 19# 再对平均后的像素做LBP特征处理 20 dst = origin_LBP(cellImage) 21 return dst 22 23gray = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) 24mb_3 = multi_scale_block_LBP(gray,3) 25mb_9 = multi_scale_block_LBP(gray,9) 26mb_15 = multi_scale_block_LBP(gray,15) 27cv2.imshow('img', gray) 28cv2.imshow('mb_3', mb_3) 29cv2.imshow('mb_9', mb_9) 30cv2.imshow('mb_15', mb_15) 31cv2.waitKey(0) 32cv2.destroyAllWindows()

5,LBPH,Local Binary Patterns Histograms

此处基于等价模式,再使用像素各分割块的直方统计图,拼接为最后的特征向量

1# 先使用等价模式预处理图像,降维。再分割图像,对每个分割块进行直方统计(降维后的类别为59),返回密度向量,再拼接各个分割块对应的密度向量 2# 最终返回grid_x*grid_y*numPatterns维的特征向量,作为图像的LBPH特征向量 3def getLBPH(img_lbp,numPatterns,grid_x,grid_y,density): 4 ''' 5 计算LBP特征图像的直方图LBPH 6 ''' 7 h,w=img_lbp.shape 8 width = int(w / grid_x) 9 height = int(h / grid_y) 10 # 定义LBPH的行和列,grid_x*grid_y表示将图像分割的块数,numPatterns表示LBP值的模式种类 11 result = np.zeros((grid_x * grid_y,numPatterns),dtype=float) 12 resultRowIndex = 0 13 # 对图像进行分割,分割成grid_x*grid_y块,grid_x,grid_y默认为8 14 for i in range(grid_x): 15 for j in range(grid_y): 16 # 图像分块 17 src_cell = img_lbp[i*height:(i+1)*height,j*width:(j+1)*width] 18 # 计算直方图 19 hist_cell = getLocalRegionLBPH(src_cell,0,(numPatterns-1),density) 20 #将直方图放到result中 21 result[resultRowIndex]=hist_cell 22 resultRowIndex+=1 23 return np.reshape(result,(-1)) 24 25def getLocalRegionLBPH(src,minValue,maxValue,density=True): 26 ''' 27 计算一个LBP特征图像块的直方图 28 ''' 29 data = np.reshape(src,(-1)) 30 # 计算得到直方图bin的数目,直方图数组的大小 31 bins = maxValue - minValue + 1; 32 # 定义直方图每一维的bin的变化范围 33 ranges = (float(minValue),float(maxValue + 1)) 34# density为True返回的是每个bin对应的概率值,bin为单位宽度时,概率总和为1 35 hist, bin_edges = np.histogram(src, bins=bins, range=ranges, density=density) 36 return hist 37 38uniform_pattern = uniform_pattern_LBP(gray,table,3,8) 39#等价模式58种,混合模式算140lbph = getLBPH(uniform_pattern,59,8,8,True)

参考博客:https://blog.csdn.net/lk3030/article/details/84034963

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )