灰度共生矩阵,Gray Level Co-occurrence Matrix,简写为GLCM
由于纹理是由灰度分布在空间位置上反复出现而形成的,因而在图像空间中相隔某距离的两象素之间会存在一定的灰度关系,即图像中灰度的空间相关特性。灰度共生矩阵就是一种通过研究灰度的空间相关特性来描述纹理的常用方法。
取图像(N×N)中任意一点 (x,y)及偏离它的另一点 (x+a,y+b),设该点对的灰度值为 (g1,g2)。令点(x,y) 在整个画面上移动,则会得到各种 (g1,g2)值,设灰度值的级数为 k,则(g1,g2) 的组合共有 k 的平方种。对于整个画面,统计出每一种 (g1,g2)值出现的次数,然后排列成一个方阵,再用(g1,g2) 出现的总次数将它们归一化为出现的概率P(g1,g2) ,这样的方阵称为灰度共生矩阵。
下图显示了如何求解灰度共生矩阵,以(1,1)点为例,GLCM(1,1)值为1说明只有一对灰度为1的像素水平相邻。GLCM(1,2)值为2,是因为有两对灰度为1和2的像素水平相邻。
![](http://hi.csdn.net/attachment/201007/9/0_1278669891plPJ.gif)
设f(x,y)为一幅数字图像,其大小为M×N,灰度级别为Ng,则满足一定空间关系的灰度共生矩阵为:
![](https://img-my.csdn.net/uploads/201302/07/1360205488_7580.gif)
其中#(x)表示集合x中的元素个数,显然P为Ng×Ng的矩阵,若(x1,y1)与(x2,y2)间距离为d,两者与坐标横轴的夹角为θ,则可以得到各种间距及角度的灰度共生矩阵(i,j,d,θ)。其中元素(i,j)的值表示一个灰度为i,另一个灰度为j的两个相距为d的像素对在角的方向上出现的次数。结合上面的图会更容易理解。
在计算得到共生矩阵之后,往往不是直接应用计算的灰度共生矩阵,而是在此基础上计算纹理特征量,我们经常用对比度、能量、熵、相关性等特征量来表示纹理特征。
(1) 对比度:又称为反差,度量矩阵的值是如何分布和图像中局部变化的多少,反应了图像的清晰度和纹理的沟纹深浅。纹理的沟纹越深,反差越大,效果清晰;反之,对比值小,则沟纹浅,效果模糊。
![](https://img-my.csdn.net/uploads/201302/07/1360205775_8290.gif)
(2) 能量:是灰度共生矩阵各元素值的平方和,是对图像纹理的灰度变化稳定程度的度量,反应了图像灰度分布均匀程度和纹理粗细度。能量值大表明当前纹理是一种规则变化较为稳定的纹理。
![](https://img-my.csdn.net/uploads/201302/07/1360205806_5194.gif)
(3) 熵:是图像包含信息量的随机性度量。当共生矩阵中所有值均相等或者像素值表现出最大的随机性时,熵最大;因此熵值表明了图像灰度分布的复杂程度,熵值越大,图像越复杂。
![](https://img-my.csdn.net/uploads/201302/07/1360205863_1033.gif)
(4) 相关性:也称为同质性,用来度量图像的灰度级在行或列方向上的相似程度,因此值的大小反应了局部灰度相关性,值越大,相关性也越大。
![](https://img-my.csdn.net/uploads/201302/07/1360205869_5491.gif)
下面是代码的实现
- #define GLCM_DIS 2 //灰度共生矩阵的统计距离
- #define GLCM_CLASS 8 //计算灰度共生矩阵的图像灰度值等级化
- #define GLCM_ANGLE_HORIZATION 0 //水平
- #define GLCM_ANGLE_VERTICAL 1 //垂直
- #define GLCM_ANGLE_DIGONAL_45 2 //45度对角
- #define GLCM_ANGLE_DIGONAL_135 3 //135度对角
- int calGLCM(CvMat* bWavelet,int angleDirection,double* featureVector)
- {
- int i,j;
- int width,height;
- int min,max;
- if(NULL == bWavelet)
- return 1;
- width = bWavelet->width;
- height = bWavelet->height;
-
- int * glcm = new int[GLCM_CLASS * GLCM_CLASS];
- int * histImage = new int[width * height];
-
- if(NULL == glcm || NULL == histImage)
- return 2;
-
-
- int relative_value = 0;
- for(i = 0;i < height;i++){
- for(j = 0;j < width;j++){
- histImage[i * width + j] = (int)(CV_MAT_ELEM(*bWavelet,float,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_135)
- {
- 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]++;
- }
- }
- }
- }
-
- else if(angleDirection == GLCM_ANGLE_DIGONAL_45)
- {
- 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;
- }
Reference:
http://blog.csdn.NET/weiyuweizhi/article/details/5724050
http://blog.csdn.Net/cxf7394373/article/details/6988229