灰度共生矩陣(GLCM,Gray-Level Co-occurrence Matrix)
阿新 • • 發佈:2018-11-09
概念
由於紋理是由灰度分佈在空間位置上反覆出現而形成的,因而在影象空間中相隔某距離的兩畫素之間會存在一定的灰度關係,即影象中灰度的空間相關特性。灰度共生矩陣就是一種通過研究灰度的空間相關特性來描述紋理的常用方法。
灰度共生矩陣是涉及畫素距離和角度的矩陣函式,它通過計算影象中一定距離和一定方向的兩點灰度之間的相關性,來反映影象在方向、間隔、變化幅度及快慢上的綜合資訊。
灰度直方圖是對影象上單個畫素具有某個灰度進行統計的結果,而灰度共生矩陣是對影象上保持某距離的兩畫素分別具有某灰度的狀況進行統計得到的。
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