图像纹理特征(灰度共生矩阵等)解析和编程调用

图像纹理特征

 本文主要介绍医学影像领域常用到的基于图像灰度值变化所衍生出的各项纹理特征,理论部分主要参考了文献1,同时介绍了相关函数调用方式。

灰度共生矩阵

 灰度共生矩阵2,Gray-Level co-occurance matrix (GLCM)用于描述两个空间上符合一定分布规律的灰度值对出现的概率,矩阵 ( x , y ) (x,y) (x,y)处的值即表示了这样的灰度值对在图像中出现的频次,用公式描述为
p ( x , y ) = ∑ I { ( i , j ) ∣ i m g ( i , j ) = x , i m g ( f ( i , j ) ) = y , i = 1 , 2... h , j = 1 , 2 , . . , w } p(x,y)=\sum I\{(i,j)|img(i,j)=x,img(f(i,j))=y, i=1,2...h,j=1,2,..,w\} p(x,y)=I{(i,j)img(i,j)=x,img(f(i,j))=y,i=1,2...h,j=1,2,..,w}
其中 I I I为指示函数, w , h w,h w,h为原始图片的宽度和高度, f f f为定义空间分布的函数。

通常来说 f ( i , j ) f(i,j) f(i,j)会设置为 ( i , j + 1 ) , ( i − 1 , j + 1 ) , ( i − 1 , j ) , ( i − 1 , j − 1 ) (i,j+1),(i-1,j+1),(i-1,j),(i-1,j-1) (i,j+1),(i1,j+1),(i1,j),(i1,j1)其中一个,也就分别对应于原图中 ( i , j ) (i,j) (i,j)元素的0°、45°、90°、135°方向,更进一步的的,有时候也认为这一空间分布应当是双向的,也就是类似 f ( i , j ) = ( i , j + 1 ) o r ( i , j − 1 ) f(i,j)=(i,j+1) or (i,j-1) f(i,j)=(i,j+1)or(i,j1)
给出当 f ( i , j ) = ( i , j + 1 ) o r ( i , j − 1 ) f(i,j)=(i,j+1)or (i,j-1) f(i,j)=(i,j+1)or(i,j1)时的示例图如下, P P P中(1,2)位置的为4,对应原图中灰度值对(1,2)、(2,1)的出现次数为4次。图像纹理特征(灰度共生矩阵等)解析和编程调用_第1张图片图像纹理特征(灰度共生矩阵等)解析和编程调用_第2张图片细节:统计灰度值对的时候并不考虑循环填充的情况,即并不认为最右边一行和左边一行是连接的。矩阵的大小为:灰度阶数*灰度阶数。

灰度游程矩阵

 灰度游程矩阵,Gray-Level run-length matrix (GLRLM)用于描述沿某一方向的延续灰度值序列出现的频率,矩阵 ( x , y ) (x,y) (x,y)处的值即表示原图中沿某一方向连续出现 y y y个灰度值为 x x x的像素点频次,用公式描述为:
p ( x , y ) = ∑ I { ( i , j )   ∣   ∀ k ∈ [ 0 , 1 , . . , y − 1 ] , i m g ( f ( i , j , k ) ) = x , i = 1 , 2... h , j = 1 , 2 , . . , w } p(x,y)=\sum I\{(i,j)\ |\ \forall k\in[0,1,..,y-1],img(f(i,j,k))=x ,i=1,2...h,j=1,2,..,w\} p(x,y)=I{(i,j)  k[0,1,..,y1],img(f(i,j,k))=x,i=1,2...h,j=1,2,..,w}
其中 I I I为指示函数, w , h w,h w,h为原始图片的宽度和高度, f f f为定义方向的函数,值得注意的是参与了一次较长游程计算的元素不会再参与下一次较短游程的计算,如连续的4个1值不会再被认定为存在2组连续2个1值。
通常而言 f ( i , j , k ) f(i,j,k) f(i,j,k)会设置为 ( i , j + k ) , ( i − k , j + k ) , ( i − k , j ) , ( i − k , j − k ) (i,j+k),(i-k,j+k),(i-k,j),(i-k,j-k) (i,j+k),(ik,j+k),(ik,j),(ik,jk),同样是表征0°、45°、90°、135°方向,给出0°方向案例如下:
图像纹理特征(灰度共生矩阵等)解析和编程调用_第3张图片图像纹理特征(灰度共生矩阵等)解析和编程调用_第4张图片

原图 I I I中灰阶3在水平方向上最长的延续长度为3个,出现过1次;延续长度为2的出现过1次,延续长度为1的出现过4次,对应 P P P中第三行为[4,1,1,0,0]。
细节:同样不认为是循环填充的。矩阵大小为:灰度阶数* m a x ( w , h ) max(w,h) max(w,h)

灰度尺寸区域矩阵

 灰度尺寸区域矩阵,Gray-Levle size zone martrix (GLSZM),用于描述平面上相连延续灰度值序列的出现频次。这个定义非常类似于灰度游程矩阵,但灰度游程矩阵要求延续序列是在某一方向上排布的,是一种一维的概念;而灰度尺寸区域矩阵则只要求延续序列见构成连通域即可,是一种二维的概念。其数学公式同样为:
p ( x , y ) = ∑ I { ( i , j )   ∣   ∀ k ∈ [ 0 , 1 , . . , y − 1 ] , i m g ( f ( i , j , k ) ) = x , i = 1 , 2... h , j = 1 , 2 , . . , w } p(x,y)=\sum I\{(i,j)\ |\ \forall k\in[0,1,..,y-1],img(f(i,j,k))=x ,i=1,2...h,j=1,2,..,w\} p(x,y)=I{(i,j)  k[0,1,..,y1],img(f(i,j,k))=x,i=1,2...h,j=1,2,..,w}
只不过 f ( i , j , k ) f(i,j,k) f(i,j,k)现在描述了一个面积为 y y y的二维连通域而非一维的线段(连通域的概念可参见opencvn中的漫水填充算法),给出案例如下:
图像纹理特征(灰度共生矩阵等)解析和编程调用_第5张图片图像纹理特征(灰度共生矩阵等)解析和编程调用_第6张图片
原图中 I I I中由灰阶3组成的连通域有3个,大小分别为3,5,1(这里的连通域认定是8连通域,因此右侧斜向和竖向的3共同构成大小为5的连通域),对应 P P P中第三行为[1,0,1,0,1]。
细节:矩阵的大小为:灰度阶数*最大连通域大小

灰度依赖矩阵

 灰度依赖矩阵,Gray-Level dependence matrix (GLDM) ,用于描述某一灰阶的周边区域某类灰度值分布的出现频次,矩阵 ( x , y ) (x,y) (x,y)处的值表示原图中灰度值为 x x x的点满足:以该点为中心一定范围内灰度值与 x x x的差小于阈值 δ \delta δ的点有 y y y个,这一条件的出现频次。用数学公式表示如下:
p ( x , y ) = ∑ I { ( i , j )   ∣   δ ≥ ∣ i m g ( f ( i , j ) ) − i m g ( i , j ) ∣ , i = 1 , 2... h , j = 1 , 2 , . . , w } p(x,y)=\sum I\{(i,j)\ |\ \delta\geq |img(f(i,j))-img(i,j)| ,i=1,2...h,j=1,2,..,w\} p(x,y)=I{(i,j)  δimg(f(i,j))img(i,j),i=1,2...h,j=1,2,..,w}
其中 f ( i , j ) f(i,j) f(i,j)用于定义这一范围,通常就是八领域,而 δ \delta δ则是可以容忍的差异阈值。给出 δ = 0 \delta=0 δ=0时案例如下:
图像纹理特征(灰度共生矩阵等)解析和编程调用_第7张图片
图像纹理特征(灰度共生矩阵等)解析和编程调用_第8张图片

原图中灰度值为3的点共有9个,八邻域范围内拥有1个灰度值为3的邻居的点有4个,拥有2个灰度值为3的邻居的点有4个,没有灰度值为3的邻居的点有1个,则 P P P中第三行为[1,4,4,0]。
细节:矩阵大小为:灰度阶数*最大邻居数+1。加1是因为存在邻居数为0的情况。

相邻灰度差分矩阵

 相邻灰度差分矩阵,Neighboring gray tone difference matrix (NGTDM),用于描述某灰阶和它周边范围内平均灰度值差异,和前面几个矩阵不同,相邻灰度差分矩阵的每列所代表的含义并不相同,先给出案例再分别叙述:
图像纹理特征(灰度共生矩阵等)解析和编程调用_第9张图片图像纹理特征(灰度共生矩阵等)解析和编程调用_第10张图片

第一张为原图,第二张给出对应NGTDM。NGTDM有三列,第一列给出了不同灰阶在原图中出现频次,第二列给出不同灰阶在原图中的出现频率,第三列最为重要,给出某个灰阶在原图所有位置与其周边范围内平均灰度差异之和。通常周边范围就定义为八邻域,以 s 5 s_5 s5为例,原图中共有4个5, ( 0 , 2 ) (0,2) (0,2)处的5八邻域范围内均值为 2 + 5 + 1 + 3 + 2 5 = 2.6 \frac{2+5+1+3+2}{5}=2.6 52+5+1+3+2=2.6,与5的差异为 ∣ 5 − 2.6 ∣ = 2.4 |5-2.6|=2.4 52.6=2.4,同理得到其他位置处的差异为2.375、2.5、2.8,共计10.075。

灰度特征矩阵分析归纳

 统一起来看的的话,其实灰度尺寸区域矩阵可以看作是灰度游程矩阵的整合延申,将多个一维层面的的统计量扩张到了二位层面,都是在描述某个灰阶值的延续情况;而相邻灰度差分矩阵和灰度依赖矩阵则是一体两面得刻画了某个灰阶与它领域的关系,前者描述相似性,后者描述相异性;灰度共生矩阵则意图描述图中灰阶的分布状况。这些值都是在描述图像的纹理特征,如果原始图像的纹理越粗糙则越趋近于出现大块的延续灰度值,从而灰度共生矩阵非零值出现在对角线附近;灰度游程矩阵和灰度尺寸区域矩阵的非零元素大都集中在右侧;灰度依赖矩阵的非零元素主要分布在矩阵右侧;相邻灰度差分矩阵的最后一列的值会较小。
 值得注意的是,所有的灰度特征矩阵的大小和灰度阶数有关,通常我们使用的图片大小都是256阶的,再加上矩阵计算时的复杂程度于输入图片的大小成正比,直接在原始图像上计算将是极其耗费时间,储存结果也是极其耗费资源的。

  • 针对计算耗时问题,我们可以调整原图的量化等级,降低灰度阶数,通过np.digitize()函数实现3
  • 针对计算结果过大的问题,我们通常不直接使用计算出的灰度特征矩阵当作最终的特征,而是依此计算出一系列统计量来描述,此处不再展开,详见pyrandiomics4的文档。

编程实现

 目前囊括了这些纹理特征的python库较少,skimage中包含了计算灰度共生矩阵和相关特征的函数,但没有其他矩阵的计算方式;pyradiomics包含计算上述所有特征的方法,并且注释中拥有详细的理论解释,但它只针对于医学图像,常规输入图片的特征无法进行求取(也可能是我没找到方法)。以下给出灰度游程矩阵代码,改写自5

def getGrayLevelRumatrix( array, theta):
    '''
    计算给定图像的灰度游程矩阵
    参数:
    array: 输入,需要计算的图像
    theta: 输入,计算灰度游程矩阵时采用的角度,list类型,可包含字段:['deg0', 'deg45', 'deg90', 'deg135']
    glrlm: 输出,灰度游程矩阵的计算结果
    '''
    P = array
    x, y = P.shape
    min_pixels = np.min(P)   # 图像中最小的像素值
    run_length = max(x, y)   # 像素的最大游行长度
    num_level = np.max(P) - np.min(P) + 1   # 图像的灰度级数

    deg0 = [val.tolist() for sublist in np.vsplit(P, x) for val in sublist]   # 原图分解按水平方向分解为多个序列
    deg90 = [val.tolist() for sublist in np.split(np.transpose(P), y) for val in sublist]   # 原图分解按竖直方向分解为多个序列
    diags = [P[::-1, :].diagonal(i) for i in range(-P.shape[0]+1, P.shape[1])]   # 使用diag函数获取45°方向序列
    deg45 = [n.tolist() for n in diags]
    Pt = np.rot90(P, 3)   # 旋转后重复前一操作获取135°序列
    diags = [Pt[::-1, :].diagonal(i) for i in range(-Pt.shape[0]+1, Pt.shape[1])]
    deg135 = [n.tolist() for n in diags]

    seqs={'deg0':deg0,'deg45':deg45,'deg90':deg90,'deg135':deg135}
    glrlm = np.zeros((num_level, run_length, len(theta)))  
    for angle in theta:
        for splitvec in range(0, len(seqs)):
            flattened =seqs[angle][splitvec] # 获取某一方向上的某个序列
            answer = []
            for key, iter in groupby(flattened):   # 使用itertools.groupby()获取延续灰度值长度
                answer.append((key, len(list(iter))))
            for ansIndex in range(0, len(answer)):
                glrlm[int(answer[ansIndex][0]-min_pixels), int(answer[ansIndex][1]-1), theta.index(angle)] += 1   # 每次将统计像素值减去最小值就可以填入GLRLM矩阵中
    return glrlm

更新:在github上找到一个非常强大的包叫做pyfeat6,里面囊括了大部分基于上述灰度特征矩阵计算的统计量的函数,如果有需要的话也可以直接导入源文件计算原始的灰度特征矩阵。以灰度共生矩阵为例,调用pyfeats.glcm_features(img)就可以输出原图在0°、45°、90°、135°方向上的灰度共生矩阵计算出的14个统计量的均值。但pyfeat默认是不计算灰度值为0对应矩阵元素,并且有时候这一设置不能在features计算时显式修改,比如计算基于GLRLM特征时就没有给出可选项,需要自行去源文件pyfeats\textural\glrm.py中修改.

参考


  1. 图解医学影像纹理特征 ↩︎

  2. 基于Python探究灰度共生矩阵(GLCM)那点事儿 ↩︎

  3. 灰度共生矩阵 ↩︎

  4. Radiomic Features ↩︎

  5. 特征提取之灰度游程(行程)矩阵-GLRLM ↩︎

  6. pyfeats 0.0.11 ↩︎

你可能感兴趣的:(图像处理,pyhon,计算机视觉,算法,python,图像处理)