图像的特征提取是图像的识别和分类、基于内容的图像检索、图像数据挖掘等研究内容的基础性工作,其中图像的纹理特征对描述图像内容具有重要意义,纹理特征提取己成为目前图像领域研究的热点。
图像的纹理特征描述图像景物的表面性质,是从图像中计算出的一个值,反应图像对应物品的质地,如粗糙度、颗粒度、随机性和规范性等。图像纹理常被应用于卫星遥感地表图像分析,图像分类、模式识别等。
GLCM 纹理提取方法具有较强的适应能力和稳健性,近年来已越来越多地用于图像的检测和分类。
GLCM名为灰度共生矩阵,指的是一种通过研究灰度的空间相关特性来描述纹理的常用方法。假设原图的灰度级为L,那么灰度共生矩阵是L*L大小的计数矩阵。GLCM表其实就是所有像素可能的组合。
图示例子
灰度共生矩阵元素所表示的含义,以(1,1)点为例,GLCM(1,1)值为1说明左侧原图只有一对灰度为1的像素水平相邻。GLCM(1,2)值为2,是因为原图有两对灰度为1和2的像素水平相邻。
注:f(x,y),f(x+a,y+b)相邻,就是只有x相隔a的单位,y相隔b个单位,我们认为是相邻的。
a=1,b=0 时我们就说水平相邻:也就是0度的时候
a=1,b=1 时我们就说对角相邻,也就是45度的时候
a=-1,b=1 时 即135度……
因此对于灰度共生矩阵,需要确定以下几个参数:
常用的glcm特征
对于纹理变换缓慢的图像,灰度共生矩阵对角线上的数值越大;图像纹理在局部变换较大,则偏离矩阵对角线的元素值较大。但是由于灰度共生矩阵的数据量较大,一般不直接作为区分纹理特征的依据。常用基于灰度共生矩阵计算出来的统计标量。信息熵、对比度、同质性(逆差距)、相关性、能量五个较常用的特征信息进行图像描述。
设f(x,y)为一幅二维数字图象,其大小为M×N,灰度级别为Ng,则满足一定空间关系的灰度共生矩阵为:
P(i,j)= #{(x1,y1),(x2,y2)∈M×N|f(x1,y1)=i,f(x2,y2)=j}
1.能量(ASM):ASM=∑i∑j(P(i,j))2
反映了图像灰度分布均匀程度和纹理粗细度。ASM值大表明一种较均一和规则变化的纹理模式。
2.对比度(Contrast):CON=∑i∑j(i−j)2P(i,j)
表现纹理的沟纹深,反差大,效果清晰。
3.同质性(Homogeneity):IDM=∑i∑j(P(i,j)/(1+(i-j)2)
测量图像的局部均匀性,非均匀图像的值较低,均匀图像的值较高。与对比度或相异性相反,同质性的权重随着元素值与对角线的距离而减小,其减小方式是指数形式的。
4.相关性(Corrln):CORRLN=[∑i∑j((ij)P(i,j))−μxμy]/σxσy
它度量空间灰度共生矩阵元素在行或列方向上的相似程度,因此,相关值大小反映了图像中局部灰度相关性。当矩阵元素值均匀相等时,相关值就大;相反,如果矩阵像元值相差很大则相关值小。如果图像中有水平方向纹理。
5.熵(Entropy):ENT=−∑i∑jP(i,j)logP(i,j)
表现图像灰度分布的复杂程度,熵值越大,图像越复杂。
其中信息熵、对比度、能量越大表示该超像素块的纹理越复杂,颜色跳跃越大;同质性和相关性数值越大,其对应的超像素块越纹理平滑,颜色均匀。
1.将原图灰度量化
原图的灰度级为256时,当分成N个灰度级时,直接将像素点的灰度值除以(256/N)取整。比如,选择4灰度级,就将像素点灰度值除以64即可。
2.计算一个矩阵窗口中,按照某个方向统计的灰度共生矩阵
d=1,求0°,45°,90°,135°方向矩阵的共生矩阵
3.矩阵的归一化
将矩阵所有元素与矩阵中所有元素之和作除运算,得到概率矩阵。
4.计算单窗口灰度共生矩阵特征值
一般采用五个最常用的特征来提取图像的纹理特征:能量、对比度、同质性,相关度、熵。
5.计算单窗口所有统计方向对应的特征值后平均化
一个滑动窗口计算结束后,该窗口就可以移动一个像素点,形成另一个小窗口图像,重复进行上一步的计算,生成新窗口图像的共生矩阵和纹理特征值;以此类推,滑动窗口遍历完所有的图像像素点后,整个图像就形成了一个由纹理特征值构成的一个纹理特征值矩阵。
附
1.fast_glcm.py
#!--*--coding: utf-8--*--
import numpy as np
import cv2
def fast_glcm(img, vmin=0, vmax=255, nbit=8, kernel_size=5):
mi, ma = vmin, vmax
ks = kernel_size
h,w = img.shape
# digitize
bins = np.linspace(mi, ma+1, nbit+1)
gl1 = np.digitize(img, bins) - 1
gl2 = np.append(gl1[:,1:], gl1[:,-1:], axis=1)
# make glcm
glcm = np.zeros((nbit, nbit, h, w), dtype=np.uint8)
for i in range(nbit):
for j in range(nbit):
mask = ((gl1==i) & (gl2==j))
glcm[i,j, mask] = 1
kernel = np.ones((ks, ks), dtype=np.uint8)
for i in range(nbit):
for j in range(nbit):
glcm[i,j] = cv2.filter2D(glcm[i,j], -1, kernel)
glcm = glcm.astype(np.float32)
return glcm
def fast_glcm_mean(img, vmin=0, vmax=255, nbit=8, ks=5):
'''
calc glcm mean
'''
h,w = img.shape
glcm = fast_glcm(img, vmin, vmax, nbit, ks)
mean = np.zeros((h,w), dtype=np.float32)
for i in range(nbit):
for j in range(nbit):
mean += glcm[i,j] * i / (nbit)**2
return mean
def fast_glcm_std(img, vmin=0, vmax=255, nbit=8, ks=5):
'''
calc glcm std
'''
h,w = img.shape
glcm = fast_glcm(img, vmin, vmax, nbit, ks)
mean = np.zeros((h,w), dtype=np.float32)
for i in range(nbit):
for j in range(nbit):
mean += glcm[i,j] * i / (nbit)**2
std2 = np.zeros((h,w), dtype=np.float32)
for i in range(nbit):
for j in range(nbit):
std2 += (glcm[i,j] * i - mean)**2
std = np.sqrt(std2)
return std
def fast_glcm_contrast(img, vmin=0, vmax=255, nbit=8, ks=5):
'''
calc glcm contrast
'''
h,w = img.shape
glcm = fast_glcm(img, vmin, vmax, nbit, ks)
cont = np.zeros((h,w), dtype=np.float32)
for i in range(nbit):
for j in range(nbit):
cont += glcm[i,j] * (i-j)**2
return cont
def fast_glcm_dissimilarity(img, vmin=0, vmax=255, nbit=8, ks=5):
'''
calc glcm dissimilarity
'''
h,w = img.shape
glcm = fast_glcm(img, vmin, vmax, nbit, ks)
diss = np.zeros((h,w), dtype=np.float32)
for i in range(nbit):
for j in range(nbit):
diss += glcm[i,j] * np.abs(i-j)
return diss
def fast_glcm_homogeneity(img, vmin=0, vmax=255, nbit=8, ks=5):
'''
calc glcm homogeneity
'''
h,w = img.shape
glcm = fast_glcm(img, vmin, vmax, nbit, ks)
homo = np.zeros((h,w), dtype=np.float32)
for i in range(nbit):
for j in range(nbit):
homo += glcm[i,j] / (1.+(i-j)**2)
return homo
def fast_glcm_ASM(img, vmin=0, vmax=255, nbit=8, ks=5):
'''
calc glcm asm, energy
'''
h,w = img.shape
glcm = fast_glcm(img, vmin, vmax, nbit, ks)
asm = np.zeros((h,w), dtype=np.float32)
for i in range(nbit):
for j in range(nbit):
asm += glcm[i,j]**2
ene = np.sqrt(asm)
return asm, ene
def fast_glcm_max(img, vmin=0, vmax=255, nbit=8, ks=5):
'''
calc glcm max
'''
glcm = fast_glcm(img, vmin, vmax, nbit, ks)
max_ = np.max(glcm, axis=(0,1))
return max_
def fast_glcm_entropy(img, vmin=0, vmax=255, nbit=8, ks=5):
'''
calc glcm entropy
'''
glcm = fast_glcm(img, vmin, vmax, nbit, ks)
pnorm = glcm / np.sum(glcm, axis=(0,1)) + 1./ks**2
ent = np.sum(-pnorm * np.log(pnorm), axis=(0,1))
return ent
if __name__ == '__main__':
from skimage import data
img = data.camera()
h,w = img.shape
img[:,:w//2] = img[:,:w//2]//2+127
nbit = 8
ks = 5
mi, ma = 0, 255
glcm_mean = fast_glcm_mean(img, mi, ma, nbit, ks)
2.glcm example
#!--*--coding: utf-8--*--
import numpy as np
from skimage import data
from matplotlib import pyplot as plt
import fast_glcm
if __name__ == '__main__':
img = data.camera()
h,w = img.shape
glcm_mean = fast_glcm.fast_glcm_mean(img)
plt.imshow(glcm_mean)
plt.tight_layout()
plt.show()
3.plot example
#!--*--coding: utf-8--*--
import numpy as np
from skimage import data
from matplotlib import pyplot as plt
import fast_glcm
from PIL import Image
def main():
pass
if __name__ == '__main__':
img_file = "test.jpg"
img=np.array(Image.open(img_file).convert('L'))
h,w = img.shape
mean = fast_glcm.fast_glcm_mean(img)
std = fast_glcm.fast_glcm_std(img)
cont = fast_glcm.fast_glcm_contrast(img)
diss = fast_glcm.fast_glcm_dissimilarity(img)
homo = fast_glcm.fast_glcm_homogeneity(img)
asm, ene = fast_glcm.fast_glcm_ASM(img)
ma = fast_glcm.fast_glcm_max(img)
ent = fast_glcm.fast_glcm_entropy(img)
plt.figure(figsize=(10,4.5))
fs = 15
plt.subplot(2,5,1)
plt.tick_params(labelbottom=False, labelleft=False)
plt.imshow(img)
plt.title('original', fontsize=fs)
plt.subplot(2,5,2)
plt.tick_params(labelbottom=False, labelleft=False)
plt.imshow(mean)
plt.title('mean', fontsize=fs)
plt.subplot(2,5,3)
plt.tick_params(labelbottom=False, labelleft=False)
plt.imshow(std)
plt.title('std', fontsize=fs)
plt.subplot(2,5,4)
plt.tick_params(labelbottom=False, labelleft=False)
plt.imshow(cont)
plt.title('contrast', fontsize=fs)
plt.subplot(2,5,5)
plt.tick_params(labelbottom=False, labelleft=False)
plt.imshow(diss)
plt.title('dissimilarity', fontsize=fs)
plt.subplot(2,5,6)
plt.tick_params(labelbottom=False, labelleft=False)
plt.imshow(homo)
plt.title('homogeneity', fontsize=fs)
plt.subplot(2,5,7)
plt.tick_params(labelbottom=False, labelleft=False)
plt.imshow(asm)
plt.title('ASM', fontsize=fs)
plt.subplot(2,5,8)
plt.tick_params(labelbottom=False, labelleft=False)
plt.imshow(ene)
plt.title('energy', fontsize=fs)
plt.subplot(2,5,9)
plt.tick_params(labelbottom=False, labelleft=False)
plt.imshow(ma)
plt.title('max', fontsize=fs)
plt.subplot(2,5,10)
plt.tick_params(labelbottom=False, labelleft=False)
plt.imshow(ent)
plt.title('entropy', fontsize=fs)
plt.tight_layout(pad=0.5)
plt.savefig('output.jpg')
plt.show()