Java代码韦伯分布_第十五节、韦伯局部描述符(WLD,附源码)

纹理作为一种重要的视觉线索,是图像中普遍存在而又难以描述的特征,图像的纹理特征一般是指图像上地物重复排列造成的灰度值有规则的分布。纹理特征的关键在于纹理特征的提取方法。目前,用于纹理特征提取的方法有很多,最具有代表性的是有基于二阶概率密度的灰度共生矩阵、符合人眼视觉特性的小波变换、纹理谱法以及基于图像结构基元的纹理元方法等。

为了更有效地描述图像局部纹理特征,又先后提取了局部二值模式(Local Binary Pattern,LBP)和韦伯局部描述符(Weber Local Descriptor,WLD),这两种方法都是基于邻域像素点间的灰度变化特征来描述图像纹理的。 因两者易于理解、便于计算且具有较好的局部特征描述能力而被广泛地应用于纹理分类 、目标检测、人脸识别 、合成孔径雷达(Synthetic Aperture Radar,SAR) 图像索引 、指纹活性检测 、图像伪造检测等众多领域中。

一 WLD原理

韦伯定律是反映心理量和物理量之间关系的定律,它表明能够引起感觉差异的差别阈值与原始刺激的强度之比是一个常量,即:

$$\frac{ΔI}{I}=k$$

其中$k$是一个常量;$ΔI$表示差别阈值;$I$表示原始刺激的强度。由此可以推知,刺激的变化所引起的感觉差异不仅与刺激变化的大小有关,还与原始刺激的强度有关。局部图像描述符WLB就是根据该定律提出的,它包含两个算子:差分激励算子和方向算子。WLD计算除边缘像素点外的每个像素点的差分激励和方向,并以其二维分布直方图来联合表征图像的纹理特征。

1、差分激励算子

差分激励反映局部窗内灰度变化的强度信息。通过计算局部窗内邻域像素点与中心像素点间的灰度差值和与中心像素点灰度值的比值$G_{ratio}(x_c)$,再利用反正切变换将分布在$[-P,+∞]$范围内的$G_{ratio}(x_c)$映射到区间$(-\frac{\pi}{2},\frac{\pi}{2})$内得到,差分激励$ξ(x_c)$的计算式为:

$$ξ(x_c)=arctan(G_{ratio}(x_c))=arctan(\sum\limits_{i=0}^{P-1}\frac{(x_i-x_c)}{x_c})$$

其中,$x_c$和$x_i,i=0,1,...,P-1$分别表示中心像素点和邻域像素点的灰度值;$P$表示邻域像素点个数。

2、方向算子

方向反映局部窗内灰度变化的空间分布信息。通过局部窗内水平方向与垂直方向上邻域像素点的灰度差值比值的反正切变换来描述。 其计算式为:

$$Φ(x_c)=arctan(\frac{D_V}{D_H})$$

其中,$D_H$和$D_V$分别表示水平方向上和垂直方向上中心像素点两侧的邻域像素点间的灰度差异,若对于$3\times3$像素的局部窗口如下图所示,则$D_H=x_7-x_3$,$D_V=x_5-x_1$。

8f6159fc46ff168f2d908d20f9965d35.png

为了能够更加有效的区分局部窗口的灰度分布变换,进一步将方向由$Φ(x_c)\in(-\frac{\pi}{2},\frac{\pi}{2})$变换到了$Φ'(x_c)\in[0,2\pi]$,其变换公式为:

$$Φ'(x_c)=\begin{cases} Φ(x_c) \qquad D_H>0,D_V>0 \\ \pi+Φ(x_c) \qquad D_H<0,D_V>0 \\\pi+Φ(x_c) \qquad D_H<0,D_V<0 \\ 2\pi+Φ(x_c) \qquad D_H>0,D_V<0 \end{cases}$$

3、WLD直方图

WLD采用均匀量化技术,将方向$Φ'(x_c)$均匀地量化为$T$个方向,将差分激励均匀地划分为$M$个频段,分别对应于图像中的高频、中频和低频变化,再将划分的每个频段上将差分激励均匀地量化为$S$格,形成一个$T\times{C}=T\times(M\times{S})$的二维直方图,并通过编码将其转化为一维向量用于表示图像的纹理特征。

962629a6484310ccd11f8023bdac0f37.png

二维直方图如上图所示,横轴表示方向,纵轴表示差分激励。每个小矩形表示在该方向下所在差分激励区间像素的数量,数量不同,颜色不同。

下图是WLD直方图得到的过程:

48e5624dfb126b52951e417f40008cf5.png

1、在每个主方向上得到差分激励子直方图,得到$H(0)$至$H(T-1)$;

2、将$H(k)$分成$M$个子区间,即$l_m,m=0,...,M-1$,将$H(k)$中的${l_m}$对应放置在$t=k$和$m=i$处;

3、将$m=i$的一行子直方图拼接成一个直方图,即$H_i$;

4、将$H_i$组合成一个直方图,即WLD直方图。

然后可以把WLD直方图用于后续分类。

4、缺点

我们来看下图所示的3个局部灰度分布示例。从3个局部窗内的灰度分布看,(a)~(c)分别表示了高频、中频和低频3种变换。按照WLD的计算方法,他们的$ΔI$都等于0,即差分激励等于0,而且,在垂直方向上的灰度值差值也为0,表明方向也等于0.这意味着,WLD将无法区分这3个纹理模式。

abe0da3bcc0ed9ff48e1aad2bd047321.png

存在上述问题的主要原因有:

WLD的差分激励算子是利用各向同性的边缘检测滤波器———拉普拉斯算子统计局部窗内$P$个邻域像素点与中心像素点间的灰度差值之和$ΔI$,导致了灰度变化的正负差值相互抵消,换言之,局部窗内的灰度变化信息没有充分体现;

WLD 的方向算子仅表达了水平方向和垂直方向上邻域像素点间灰度变化梯度的空间分布方位,不能充分反映局部窗内灰度变化的空间分布结构信息,难以体现纹理的内在变化特征;

5、改进

纹理特征是指与空间分布相关的图像灰度等级的变化。 这意味着灰度图像的纹理既与各像素点间灰度变化的梯度幅值有关,也与其梯度的空间分布密切相关,两者是有机的一体。 针对WLD 存在的问题,提出一种基于正负梯度改进的 WLD(WLD-PNG)。

其核心思想是:

基于局部窗内邻域像素点与中心像素点间灰度变化的正负梯度信息,分离计算正、负差分激励以保留灰度等级的变化特征;

利用 LBP 模式提取正负梯度分布的结构信息,以反映灰度等级变化的空间分布特征。 最后,采用均匀量化和编码技术,将两者有机联合建立图像的纹理特征。

三 代码实现

由于opencv没有提供WLD算法的实现,但是从网上我们可以找到基于Weber local descriptors的人脸识别的代码和基于OPENCV的WLD特征提取程序,我们作为参考,修改自己的代码如下:

#-*- coding: utf-8 -*-

"""Created on Sat Sep 1 19:08:10 2018

@author: zy"""

'''WLD

韦伯局部描述符'''

importcv2importnumpy as npclassWLD(object):def __init__(self):#差分激励由中心像素与周围像素强度的差异以及中心像素强度组成,分别由f1和f2滤波器得出。

self.__f1 = np.array([[1,1,1],

[1,-8,1],

[1,1,1]])

self.__f2 =np.array([[0,0,0],

[0,1,0],

[0,0,0]])#方向反映局部窗内灰度变化的空间分布信息。通过局部窗内水平方向与垂直方向上邻域像素点

#的灰度差值比值的反正切变换来描述。 方向分为竖直方向和水平方向,由f3和f4滤波器得出。

self.__f3 = np.array([[0,-1,0],

[0,0,0],

[0,1,0]])

self.__f4 =np.array([[0,0,0],

[1,0,-1],

[0,0,0]])#方向量化个数 如果修改,也需要修改__classify_fai函数

self.__T = 12

#差分激励量化个数 如果修改,也需要修改__classify_epc函数

self.__M= 8

#每个频段上将差分激励均匀地量化为S格 可以修改

self.__S = 4

def calc_hist(self,image,concatenate=True):'''输出统计直方图 形状[M,T,S]或[MxTxS,]

args:

image:输入灰度图

concatenate:表明输出直方图是否合并为一维'''his= np.zeros((self.__M,self.__T,self.__S),np.float32)

rows,cols= image.shape[:2]#计算像素点个数

sum_pix = rows*cols

epc,theta= self.__compute(image)for i inrange(rows):for j inrange(cols):#把差分激励分为8个区间,分别对应一个类别

m = self.__classify_epc(epc[i][j])

t=theta[i][j]

s= self.__classify_s(epc[i][j],m)

his[m-1][t-1][s-1] += 1

#归一化

his /=sum_pixifconcatenate:

his= np.reshape(his,-1)returnhisdef __compute(self,image):'''计算每个像素点的差分激励和方向'''rows,cols= image.shape[:2]#用于保存每个像素点对应的差分激励算子

epc = np.zeros((rows,cols),dtype=np.float32)#用于保存每个像素点对应的方向算子

theta = np.zeros((rows,cols),dtype=np.float32)'''计算差分激励ξ'''v1= cv2.filter2D(image,cv2.CV_16SC1,self.__f1)

v2= cv2.filter2D(image,cv2.CV_16SC1,self.__f2)for i inrange(rows):for j inrange(cols):#-π/2~π/2

epc[i][j] = np.arctan(v1[i][j]/(v2[i][j]+0.0001))'''计算每个像素点的方向Φ,把方向[0,2pi]均匀地量化为12个区间'''v3= cv2.filter2D(image,cv2.CV_16SC1,self.__f3)

v4= cv2.filter2D(image,cv2.CV_16SC1,self.__f4)for i inrange(rows):for j inrange(cols):

theta[i][j]= np.arctan(v3[i][j]/((v4[i][j])+0.0001))if v3[i][j]>0 and v4[i][j]>0:pass

elif v3[i][j]>0 and v4[i][j]<0:

theta[i][j]= theta[i][j]+2*np.pielse:

theta[i][j]=theta[i][j]+np.pi

theta[i][j]= self.__classify_fai(theta[i][j])

theta=theta.astype(np.uint8)returnepc,thetadef __classify_fai(self,value):'''把方向值value分类 类别为1、2、3、4、5、6、7、8、9、10、11、12

args:

value:数值 0~2π之间'''

if value >= 0 and value < 0.15*np.pi:return 1

elif value >= np.pi*0.15 and value < 0.35*np.pi:return 2

elif value >= np.pi*0.35 and value < 0.5*np.pi:return 3

elif value >= np.pi*0.5 and value < 0.65*np.pi:return 4

elif value >= 0.65*np.pi and value < 0.85*np.pi:return 5

elif value >= np.pi*0.85 and value

elif value >= np.pi and value < 1.15*np.pi:return 7

elif value >= 1.15*np.pi and value < 1.35*np.pi:return 8

elif value >= np.pi*1.35 and value < 1.5*np.pi:return 9

elif value >= 1.5*np.pi and value < 1.65*np.pi:return 10

elif value >= 1.65*np.pi and value < 1.85*np.pi:return 11

else:return 12

def __classify_epc(self,value):'''把差分激励值value分类,划分为8个区间 类别为1、2、3、4、5、6、7、8

args:

value:数值 -π/2~π/2之间'''

if value >= np.pi*(-0.5) and value < (-0.3)*np.pi:return 1

elif value >= np.pi*(-0.3) and value < (-0.15)*np.pi:return 2

elif value >= np.pi*(-0.15) and value < (-0.05)*np.pi:return 3

elif value >= np.pi*(-0.05) and value <0:return 4

elif value >= 0 and value < 0.05*np.pi:return 5

elif value >= np.pi*0.05 and value < 0.15*np.pi:return 6

elif value >= np.pi*0.15 and value < 0.3*np.pi:return 7

else:return 8

def __classify_s(self,value,label):'''将每个区间的差分激励再次划分为S格

args:

value:差分激励值 -π/2~π/2之间

label:当前所属区间 1,2,3,...,8'''

if label == 1:

space= ((-0.3)*np.pi - (-0.5)*np.pi)/self.__S

return int((value - (-0.5)*np.pi)/space)+1

elif label == 2:

space= ((-0.15)*np.pi - (-0.3)*np.pi)/self.__S

return int((value - (-0.3)*np.pi)/space)+1

elif label == 3:

space= ((-0.05)*np.pi - (-0.15)*np.pi)/self.__S

return int((value - (-0.15)*np.pi)/space)+1

elif label == 4:

space= 0-(-0.05)*np.pi/self.__S

return int((value - (-0.05)*np.pi)/space)+1

elif label == 5:

space= 0.05*np.pi /self.__S

return int(value /space)+1

elif label == 6:

space= (0.15*np.pi - 0.05*np.pi)/self.__S

return int((value - 0.05*np.pi)/space)+1

elif label == 7:

space= (0.3*np.pi - 0.15*np.pi)/self.__S

return int((value - 0.15*np.pi)/space)+1

else:

space= (0.5*np.pi - 0.3*np.pi)/self.__Sn= int((value - 0.3*np.pi)/space)+1

if n == self.__S+1:

n= self.__S

returnndefdraw_hist(hist):'''绘制直方图'''

#首先先创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像

#图像高为100,宽为直方图的长度

width =len(hist)

height= 100draw_image= np.zeros((height,width,3),dtype=np.uint8)#获取最大值

max_value =np.max(hist)#数值量化

value = np.asarray((hist*0.9/max_value*height),dtype=np.int8)for i inrange(width):

cv2.line(draw_image,(i,height-1),(i,height-1-value[i]),(255,0,0))#显示

cv2.imshow('hist',draw_image)

cv2.waitKey(0)

cv2.destroyAllWindows()if __name__=='__main__':

image= cv2.imread('./image/match1.jpg')

image= cv2.resize(image,dsize=(600,400))

imgray=cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

wld=WLD()

hist=wld.calc_hist(imgray)print(hist.shape)print(hist)print(np.sum(hist))

draw_hist(hist)

运行结果如下:

bb079bbfabfa595f7e3b328abfa1ca0c.png

13c4621910542b9a7d5e9c2815e5ffd5.png

参考文章

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/359339.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaFX真实世界应用程序:欧洲电视网广播联盟

我荣幸地与今年在德累斯顿Saxonia 系统公司工作的Alexander Casall一起在JavaOne上展示了多个JavaFX Real-World应用程序。 在准备本次演讲时&#xff0c;我们向客户和合作伙伴发送了一份调查表&#xff0c;并向他们询问了一些与他们的项目&#xff0c;他们的应用程序以及他们对…

java 三大集合_java中的三大集合入门笔记(简单实用)

为什么使用集合框架如图&#xff1a;集合的好处&#xff1a;集合弥补了数组的缺陷&#xff0c;它比数组更灵活更实用&#xff0c;可大大提高软件的开发效率&#xff0c;而且不同的集合适用于不同的场合。Java集合主要分为以下3种类型Java集合框架提供了一套性能优良、使用方便的…

Java面试题2019简书_2019最新Spring面试题大全含答案之Spring Beans(2019最全Spring超级葵花宝典)...

1.什么是Spring beans&#xff1f;Spring beans 是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化&#xff0c;装配&#xff0c;和管理。这些beans通过容器中配置的元数据创建。比如&#xff0c;以XML文件中 的形式定义。Spring 框架定义的beans都是单件bean…

使用此首选项可加快Eclipse m2e配置

谁不认识他们。 Eclipse中的旧式JFace对话框可以使您直观地看到实际上是一个相当简单的XML或属性文件。 对于m2e&#xff0c;它看起来像这样&#xff1a; 不幸的是&#xff0c;此屏幕的加载速度有点慢&#xff0c;除了检查版本号和您将永远不会更改的其他内容之外&#xff0c…

【百度地图API】发布静态图API啦!只需一个网址,即可展示定制百度地图!

【百度地图API】发布静态图API啦&#xff01;只需一个网址&#xff0c;即可展示定制百度地图&#xff01; 原文:【百度地图API】发布静态图API啦&#xff01;只需一个网址&#xff0c;即可展示定制百度地图&#xff01;摘要&#xff1a; 百度地图静态图API&#xff01;您无须执…

脚本在流程中的性能影响

我们经常看到人们出于各种目的而使用脚本&#xff08;例如&#xff0c;在服务任务&#xff0c;执行侦听器等中&#xff09;。 使用脚本和Java逻辑通常很有意义&#xff1a; 它不需要打包到jar中并放在classpath上 它使流程定义更易于理解&#xff1a;无需查看其他文件 逻辑是…

PowerDesigner使用教程

原文&#xff1a;http://www.cnblogs.com/huangcong/archive/2010/06/14/1757957.html PowerDesigner是一款功能非常强大的建模工具软件&#xff0c;足以与Rose比肩&#xff0c;同样是当今最著名的建模软件之一。Rose是专攻UML对象模型的建模工具&#xff0c;之后才向数据库建模…

红帽峰会2015所需的JBoss BPM内容指南

明年再见&#xff1f; 今年在Red Hat Summit上&#xff0c;我们在JBoss BRMS和JBoss BPM Suite演讲中获得了很多乐趣。 在DevNation周围也有一些社区会议&#xff0c;重点介绍了使我们的产品成为可能的项目。 您可以在他们的博客上找到此演讲的概述&#xff0c;并在其中提供…

设计模式 之 享元

享元模式&#xff08;Flyweight&#xff09; 运用共享技术有效地支持大量细粒度的对象。 还记得那年夏天一起在作文本上玩过的五子棋吗&#xff1f;五子棋是一种两人对弈的纯策略型棋类游戏&#xff0c;它起源于中国古代的传统黑白棋种之中的一个&#xff0c;不…

php制作简单的用户登陆,如何用php代码实现简单的用户登陆以及登陆验证功能

本文主要简单讲述了如何使用php实现简单的用户登陆以及登陆验证效果。1、首先实现通过Session实现用户的登录那么什么是session呢&#xff1f;session被译为会话&#xff0c;它主要是为了在一定访问期间在不同页面之间间传输数据&#xff0c;用来解决http协议无状态。session在…

Quick cocos2dx-Lua(V3.3R1)学习笔记(十)-----搭建安卓打包环境,用官方示例anysdk生成apk运行...

话说我这一篇就写搭建打包安卓环境&#xff0c;是不是有点过早了&#xff08;其实我主要是怕以后重装系统&#xff0c;忘了怎么搭建了&#xff09;&#xff0c;但是迟早要面对的痛苦&#xff0c;一直延后也不是办法&#xff0c;对吧。 在官方文档中&#xff0c;对于打包安卓apk…

php实现返回顶部,返回顶部js

返回顶部jsfunction goTopEx(){var objdocument.getElementById(“goTopBtn”);function getScrollTop(){return (document.documentElement.scrollTopdocument.body.scrollTop);}function setScrollTop(value){if(document.documentElement && document.documentEleme…

中国大学MOOC-数据结构基础习题集、06-2、旅游规划

题目链接&#xff1a;http://www.patest.cn/contests/mooc-ds/06-2 题目分析&#xff1a;陈姥姥说&#xff0c;这是Dijstra算法的一道题。题目是中文的&#xff0c;这里就不再啰嗦了。有一点提示一下&#xff0c;咱们平时用的Dijistra算法&#xff0c;是用来求最短路径的。这道…

iOS安全攻防(三):使用Reveal分析他人app

使用Reveal分析他人app准备工作1&#xff09;已越狱的设备&#xff0c;而且已安装了OpenSSH,MobileSubstrate等有用工具(Cydia源里安装)2&#xff09;本地已安装了Reveal操作步骤1&#xff09;拷贝framework和dylib到越狱机scp -r /Applications/Reveal.app/Contents/SharedSup…

JBoss BPM Travel Agency演示与现代BPM数据集成

不久前&#xff0c;我们启动了一个规模较大的JBoss Travel Agency演示项目&#xff0c;以展示JBoss BPM Suite的一些更有趣的功能。 我们提供了一系列视频 &#xff0c;不仅向您展示了如何安装它&#xff0c;项目中各种规则和流程工件的含义&#xff0c;还向您介绍了在实际使用…

scala入门-10 隐式转换、隐式参数、隐式类

到目前为止&#xff0c;隐式转换是scala的重点和难点了&#xff0c;加油~ 我们先创建一个类名称叫Implicit.scala 再看一个隐式参数的例子&#xff1a; 上面的例子中使用了隐式参数&#xff0c;我们也可以明显的指明参数&#xff1a; 下面看一下隐式类&#xff1a; 相当于&…

连载《一个程序猿的生命周期》-2.城市校园生活

一个程序猿的生命周期 微信平台 口 号&#xff1a;职业交流&#xff0c;职业规划&#xff1b;面对现实&#xff0c;用心去交流、感悟。 公众号&#xff1a;iterlifetime 百木-ITer职业交流奋斗 群&#xff1a;141588103 微 博&#xff1a;http://www.weibo.com/u/57234…

excel使用MySQL数据,如何使用mysql完成excel中的数据生成

Excel是数据分析中最常用的工具&#xff0c;本篇文章通过mysql与excel的功能对比介绍如何使用mysql完成excel中的数据生成&#xff0c;数据清洗&#xff0c;预处理&#xff0c;以及最常见的数据分类&#xff0c;数据筛选&#xff0c;分类汇总&#xff0c;以及数据透视等操作。本…

Spring Batch –使用JavaConfig替换XML作业配置

我最近协助一个客户启动并运行了Spring Batch实现。 该团队决定继续为批处理作业使用基于JavaConfig的配置&#xff0c;而不是传统的基于XML的配置。 随着这越来越成为配置Java应用程序的一种常用方法&#xff0c;我觉得是时候更新Keyhole的Spring Batch系列了 &#xff0c;向您…

JBoss BPM Travel Agency的微服务迁移故事

不久前&#xff0c;我们启动了一个规模较大的JBoss Travel Agency演示项目&#xff0c;以展示JBoss BPM Suite的一些更有趣的功能。 我们提供了一系列视频 &#xff0c;不仅向您展示了如何安装它&#xff0c;项目中各种规则和流程工件的含义&#xff0c;还向您介绍了在实际使…