灰度共生矩阵(GLDM)的统计方法是20世纪70年代初由R.Haralick等人提出的,它是在假定图像中各像素间的空间分布关系包含了图像纹理信息的前提下,提出的具有广泛性的纹理分析方法。
度共生矩阵被定义为从灰度为i的像素点出发,离开某个固定位置(相隔距离为d,方位为)的点上灰度值为的概率,即,所有估计的值可以表示成一个矩阵的形式,以此被称为灰度共生矩阵。对于纹理变化缓慢的图像,其灰度共生矩阵对角线上的数值较大;而对于纹理变化较快的图像,其灰度共生矩阵对角线上的数值较小,对角线两侧的值较大。由于灰度共生矩阵的数据量较大,一般不直接作为区分纹理的特征,而是基于它构建的一些统计量作为纹理分类特征。Haralick曾提出了14种基于灰度共生矩阵计算出来的统计量:即:能量、熵、对比度、均匀性、相关性、方差、和平均、和方差、和熵、差方差、差平均、差熵、相关信息测度以及最大相关系数。
本文是借用一篇文章的例子讲解灰度共生矩阵,用文字说明感觉说不清,自己之前用该方法做过实验,还是会忘,所以干脆用例子的方式介绍,下一次再看也容易理解。
在图像中任意一点(x,y)及偏离它的一点(x+a,y+b)(其中a,b为整数,认为定义)构成点对。设该点对的灰度值为(f1,f2),假设图像的最大灰度级为L,则f1与f2的组合共有L*L种。对于整福图像,统计每一种(f1,f2)值出现的次数,然后排列成一个方阵,再用(f1,f2)出现的总次数将它们归一化为出现的概率P(f1,f2),由此产生的矩阵为灰度共生矩阵。
下图为一个简单的例子:
图a为原图像,最大灰度级为16。为表示方便,这里将灰度级数减小为4级,图a变为图b的形式。这样(f1,f2)取值范围便为[0,3]。取不同的间隔,将(f1,f2)各种组合出现的次数排列起来,就可得到图e~g所示的灰度共生矩阵。
图e表示图b中(x,y)与偏离它的(x+1,y+0)构成点对时,(f1,f2)取值的情况(填充黄色部分为f1取0,f2取1时的情况,由图b填充易知共10种)。同理,f,g分别表示图c,d中(x,y)分别于点(x+1,y+1),(x+2,y+0)构成的点对(f1,f2)出现的情况(图c填充黄色部分表示f1取0,f2取0时,对角线点对(0,0)出现的情况,共8种:图d填充黄色部分表示f1取0,f2取2时水平点对(0,2)出现的情况,共9种)。例如,对于a=1,b=0,点对中(0,1)的组合共出现了10次。对比可以看出,(0,1),(1,2),(2,3)和(3,0)均有较高的出现频数。图b表明,图像中存在明显的左上右下方向的纹理。
距离(a,b)的取值不同,灰度共生矩阵中的值不同。a和b的取值要根据纹理周期分布的特征来选择,对于较细的纹理,选取(1,0),(1,1),(2,0)等这样的值是有必要的。a,b取值较小对应于变化缓慢的纹理图像,其灰度共生矩阵对角线上的数值较大。纹理的变化越快,则对角线上的数值越小,而对角线两侧的值增大。
共生矩阵实际上是两个像素点的联合直方图,对于图像中细而规则的纹理,成对像素点的二维直方图倾向于均匀分布;对于粗而规则的纹理,则倾向于最对角分布。
度量 矩阵的值是如何分布和图像中局部变化的多少,反应了图像的清晰度和纹理的沟纹深浅。纹理的沟纹越深,反差越大,效果越清晰;反之,对比值小,则沟纹浅,效果模糊。
能量变换反映了图像灰度分布均匀程度和纹理粗细度。若灰度共生矩阵的元素值相近,则能量较小,表示纹理细致;若其中一些值大,而其它值小,则能量值较大。能量值大表明一种较均一和规则变化的纹理模式。
图像包含信息量的随机性度量。当共生矩阵中所有值均相等或者像素值表现出最大的随机性时,熵最大;因此熵值表明了图像灰度分布的复杂程度,熵值越大,图像越复杂。
逆方差反映了图像纹理局部变化的大小,若图像纹理的不同区域间较均匀,变化缓慢,逆方差会较大,反之较小。
用来度量图像的灰度级在行或列方向上的相似程度,因此值得大小反应了局部灰度相关性,值越大,相关性也越大。
#define GLCM_DIS 3 //灰度共生矩阵的统计距离
#define GLCM_CLASS 16 //计算灰度共生矩阵的图像灰度值等级化
typedef enum GLCM_ANGLE
{
GLCM_ANGLE_HORIZATION,
GLCM_ANGLE_VERTICAL,
GLCM_ANGLE_DIGONAL_45,
GLCM_ANGLE_DIGONAL_135
}GLCM_ANGLE;
int CalGlCM(unsigned char* pImage,GLCM_ANGLE angleDirection,double* featureVector)
{
int i,j;
if(NULL == pImage)
return 1;
int * glcm = new int[GLCM_CLASS * GLCM_CLASS];
int * histImage = new int[width * height];
if(NULL == glcm || NULL == histImage)
return 2;
//灰度等级化---分GLCM_CLASS个等级
for(i = 0;i < height;i++)
{
for(j = 0;j < width; j++)
{
histImage[i * width + j] = (int)(data[width*i+j] * GLCM_CLASS/256);
}
}
//初始化共生矩阵
for (i = 0;i < GLCM_CLASS;i++)
for (j = 0;j < GLCM_CLASS;j++)
glcm[i * GLCM_CLASS + j] = 0;
//计算灰度共生矩阵
int w,k,l;
//水平方向
if(angleDirection == GLCM_ANGLE_HORIZATION)
{
for (i = 0;i < height;i++)
{
for (j = 0;j < width;j++)
{
l = histImage[i * width + j];
if(j + GLCM_DIS >= 0 && j + GLCM_DIS < width)
{
k = histImage[i * width + j + GLCM_DIS];
glcm[l * GLCM_CLASS + k]++;
}
if(j - GLCM_DIS >= 0 && j - GLCM_DIS < width)
{
k = histImage[i * width + j - GLCM_DIS];
glcm[l * GLCM_CLASS + k]++;
}
}
}
}
//垂直方向
else if(angleDirection == GLCM_ANGLE_VERTICAL)
{
for (i = 0;i < height;i++)
{
for (j = 0;j < width;j++)
{
l = histImage[i * width + j];
if(i + GLCM_DIS >= 0 && i + GLCM_DIS < height)
{
k = histImage[(i + GLCM_DIS) * width + j];
glcm[l * GLCM_CLASS + k]++;
}
if(i - GLCM_DIS >= 0 && i - GLCM_DIS < height)
{
k = histImage[(i - GLCM_DIS) * width + j];
glcm[l * GLCM_CLASS + k]++;
}
}
}
}
//对角方向
else if(angleDirection == GLCM_ANGLE_DIGONAL)
{
for (i = 0;i < height;i++)
{
for (j = 0;j < width;j++)
{
l = histImage[i * width + j];
if(j + GLCM_DIS >= 0 && j + GLCM_DIS < width && i + GLCM_DIS >= 0 && i + GLCM_DIS < height)
{
k = histImage[(i + GLCM_DIS) * width + j + GLCM_DIS];
glcm[l * GLCM_CLASS + k]++;
}
if(j - GLCM_DIS >= 0 && j - GLCM_DIS < width && i - GLCM_DIS >= 0 && i - GLCM_DIS < height)
{
k = histImage[(i - GLCM_DIS) * width + j - GLCM_DIS];
glcm[l * GLCM_CLASS + k]++;
}
}
}
}
//计算特征值
double entropy = 0,energy = 0,contrast = 0,homogenity = 0;
for (i = 0;i < GLCM_CLASS;i++)
{
for (j = 0;j < GLCM_CLASS;j++)
{
//熵
if(glcm[i * GLCM_CLASS + j] > 0)
entropy -= glcm[i * GLCM_CLASS + j] * log10(double(glcm[i * GLCM_CLASS + j]));
//能量
energy += glcm[i * GLCM_CLASS + j] * glcm[i * GLCM_CLASS + j];
//对比度
contrast += (i - j) * (i - j) * glcm[i * GLCM_CLASS + j];
//一致性
homogenity += 1.0 / (1 + (i - j) * (i - j)) * glcm[i * GLCM_CLASS + j];
}
}
//返回特征值
i = 0;
featureVector[i++] = entropy;
featureVector[i++] = energy;
featureVector[i++] = contrast;
featureVector[i++] = homogenity;
delete[] glcm;
delete[] histImage;
return 0;
}