概念
由于紋理是由灰階分布在空間位置上反複出現而形成的,因而在圖像空間中相隔某距離的兩像素之間會存在一定的灰階關系,即圖像中灰階的空間相關特性。灰階共生矩陣就是一種通過研究灰階的空間相關特性來描述紋理的常用方法。
灰階共生矩陣是涉及像素距離和角度的矩陣函數,它通過計算圖像中一定距離和一定方向的兩點灰階之間的相關性,來反映圖像在方向、間隔、變化幅度及快慢上的綜合資訊。
灰階直方圖是對圖像上單個像素具有某個灰階進行統計的結果,而灰階共生矩陣是對圖像上保持某距離的兩像素分别具有某灰階的狀況進行統計得到的。
GLCM 所代表的含義
灰階共生矩陣元素所表示的含義,以(1,1)點為例,GLCM(1,1)值為1說明左側原圖隻有一對灰階為1的像素水準相鄰。GLCM(1,2)值為2,是因為原圖有兩對灰階為1和2的像素水準相鄰。
灰階共生矩陣的特征
1) 角二階矩(Angular Second Moment, ASM)
公式:ASM = sum(p(i,j).^2),其中 p(i,j) 表示歸一後的灰階共生矩陣
意義:角二階矩是圖像灰階分布均勻程度和紋理粗細的一個度量,當圖像紋理絞細緻、灰階分布均勻時,能量值較大,反之,較小。
2) 熵(Entropy, ENT)
公式:ENT=sum(p(i,j)*(-log(p(i,j)))
意義:描述圖像具有的資訊量的度量,表明圖像的複雜程度,當複雜程度高時,熵值較大,反之則較小。
3) 反差分矩陣(Inverse Differential Moment, IDM)
公式:IDM=sum(p(i,j)/(1+(i-j)^2))
意義:反映了紋理的清晰程度和規則程度,紋理清晰、規律性較強、易于描述的,值較大;雜亂無章的,難于描述的,值較小。
OpenCV 代碼
// 0°灰階共生矩陣
void getGLCM0(Mat& src, Mat& dst, int gray_level)// 0度灰階共生矩陣
{
CV_Assert(1 == src.channels());
int height = src.rows;
int width = src.cols;
dst.create(gray_level, gray_level, CV_32SC1);
dst = Scalar::all(0);
for (int i = 0; i < height; i++)
{
int*srcdata = src.ptr<int>(i);
for (int j = 0; j < width - 1; j++)
{
// 同樣的像素對,水準相鄰
int rows = srcdata[j];
int cols = srcdata[j + 1];
dst.ptr<int>(rows)[cols]++;
}
}
}
// 90°灰階共生矩陣
void getGLCM90(Mat& src, Mat& dst, int gray_level)
{
CV_Assert(1 == src.channels());
int height = src.rows;
int width = src.cols;
dst = Mat(gray_level, gray_level, CV_32SC1, Scalar(0));
for (int i = 0; i < height - 1; i++)
{
int*srcdata = src.ptr<int>(i);
int*srcdata1 = src.ptr<int>(i + 1);
for (int j = 0; j < width; j++)
{
// 同樣的像素對,垂直相鄰
int rows = srcdata[j];
int cols = srcdata1[j];
dst.ptr<int>(rows)[cols]++;
}
}
}
// 45°灰階共生矩陣
void getGLCM45(Mat& src, Mat& dst, int gray_level)
{
CV_Assert(1 == src.channels());
int height = src.rows;
int width = src.cols;
dst = Mat(gray_level, gray_level, CV_32SC1, Scalar(0));
for (int i = 0; i < height - 1; i++)
{
int*srcdata = src.ptr<int>(i);
int*srcdata1 = src.ptr<int>(i + 1);
for (int j = 0; j < width - 1; j++)
{
// 同樣的像素對,45°相鄰
int rows = srcdata[j];
int cols = srcdata1[j + 1];
dst.ptr<int>(rows)[cols]++;
}
}
}
// 135°灰階共生矩陣
void getGLCM135(Mat& src, Mat& dst, int gray_level)
{
CV_Assert(1 == src.channels());
int height = src.rows;
int width = src.cols;
dst = Mat(gray_level, gray_level, CV_32SC1, Scalar(0));
for (int i = 0; i < height - 1; i++)
{
int*srcdata = src.ptr<int>(i);
int*srcdata1 = src.ptr<int>(i + 1);
for (int j = 1; j < width; j++)
{
// 同樣的像素對,135°相鄰
int rows = srcdata[j];
int cols = srcdata1[j - 1];
dst.ptr<int>(rows)[cols]++;
}
}
}
// 計算特征值
void featureGLCM(Mat&src, double& Asm, double& Ent, double& Con, double& Idm)
{
CV_Assert(src.channels() == 1);
int height = src.rows;
int width = src.cols;
int total = 0;
//求圖像所有像素的灰階值的和
for (int i = 0; i < height; i++)
{
int*srcdata = src.ptr<int>(i);
for (int j = 0; j < width; j++)
{
total += srcdata[j];
}
}
//圖像每一個像素的的值除以像素總和
Mat mean;
mean.create(height, width, CV_64FC1);
for (int i = 0; i < height; i++)
{
int*srcdata = src.ptr<int>(i);
double*copydata = mean.ptr<double>(i);
for (int j = 0; j < width; j++)
{
copydata[j] = (double)srcdata[j] / (double)total;
}
}
for (int i = 0; i < height; i++)
{
double*srcdata = mean.ptr<double>(i);
for (int j = 0; j < width; j++)
{
// 能量
Asm += srcdata[j] * srcdata[j];
// 熵(Entropy)
if (srcdata[j]>0)
Ent -= srcdata[j] * log(srcdata[j]);
// 對比度
Con += (double)(i - j)*(double)(i - j)*srcdata[j];
// 逆差矩
Idm += srcdata[j] / (1 + (double)(i - j)*(double)(i - j));
}
}
}
注:本代碼以 offset = 1 為例
參考自:
http://baike.baidu.com/link?url=3cuLq2FM6QHWNxgMaswYbKBacMCQ1ptYU6H-T1c8YpcFxmnMEuCtYC9hvCAScZcnxEQDl9a8TXrNntgkoEFliL5tuWapiC3Ovf_vabsEFa1_CouZwLTUByMUhUqLaExrt1KAdEr9ralX-LQKLCj_qq
http://blog.csdn.net/weiyuweizhi/article/details/5724050 http://blog.csdn.net/yanxiaopan/article/details/52356777 http://blog.csdn.net/u014488388/article/details/52877710