[转]灰度共生矩阵(超简单理解)
1.灰度共生矩阵生成原理
灰度共生矩阵(GLDM)的统计方法是20世纪70年代初由R.Haralick等人提出的,它是在假定图像中各像素间的空间分布关系包含了图像纹理信息的前提下,提出的具有广泛性的纹理分析方法。
灰度共生矩阵被定义为从灰度为i的像素点出发,离开某个固定位置(相隔距离为d,方位为)的点上灰度值为的概率,即,所有估计的值可以表示成一个矩阵的形式,以此被称为灰度共生矩阵。对于纹理变化缓慢的图像,其灰度共生矩阵对角线上的数值较大;而对于纹理变化较快的图像,其灰度共生矩阵对角线上的数值较小,对角线两侧的值较大。由于灰度共生矩阵的数据量较大,一般不直接作为区分纹理的特征,而是基于它构建的一些统计量作为纹理分类特征。Haralick曾提出了14种基于灰度共生矩阵计算出来的统计量:即:能量、熵、对比度、均匀性、相关性、方差、和平均、和方差、和熵、差方差、差平均、差熵、相关信息测度以及最大相关系数。
在网上看了很多灰度共生矩阵生成的例子感觉都没有说明白,要不就直接上结果要不就给一堆看不懂的代码和公式,后来看了matlab中的介绍就明白了,其实很简单,仔细把下面的看三遍就理解怎么来的了!(我是第三篇看明白的,当时很紧张,相信你们没问题)
下图显示了如何求解灰度共生矩阵,以(1,1)点为例,GLCM(1,1)值为1说明只有一对灰度为1的像素水平相邻。GLCM(1,2)值为2,是因为有两对灰度为1和2的像素水平相邻。(MatLab说明文档)
GLCM表其实就是所有像素可能的组合,比如,GLCM(1,1)就是I中像素值为1和1的组合,GLCM(4,5)就是I中像素4和像素5的组合,GLCM(i,j)的值呢就是I中像素为i,像素为j的有有多少和相邻的成对点。这个相邻有个规则:就是f(x,y),f(x+a,y+b)相邻,就是只有x相隔a的单位,y相隔b个单位,我们认为是相邻的。
平时我们说相邻:B点在A点右边,其实就是这里的a=1,b=0,也就是f(x,y)和f(x+1,y+0)相邻。
于是就有了:
a=1,b=0 时我们就说水平相邻:也就是0度的时候
a=1,b=1 时我们就说对角相邻,也就是45度的时候
a=-1,b=1时 即135度
其他角度类似。
在a=1,b=0时:GLCM(1,1)=1;其实就是I中有几个1和1相邻(1个)(按上面的规则)GLCM(1,2)=2,几个1和2相邻(2个)。ok!
后面好多的性质,都是在把这个矩阵计算出来之后再在这个基础上运算的,那些就不难了!
附加理解2:
共生矩阵用两个位置的像素的联合概率密度来定义,它不仅反映亮度的分布特征,也反映具有同样亮度或者接近亮度的像素之间的位置分布特性,是有关图像亮度变化的二阶统计特征。它是定义一组纹理特征的基础。
由于纹理是由灰度在空间位置上反复出现而形成的,因而在图像空间中像个某距离的两像素之间会存在一定的灰度关系,即图像中灰度的空间相关特性。灰度共生矩阵就是一种通过研究灰度的空间相关特性来描述纹理的常用方法。
灰度直方图是对图像上单个像素具有某个灰度进行统计的结果,
而灰度共生矩阵是对图像上保持某距离的两像素分别具有某灰度的状况进行统计得到的。
取图像(N×N)中任意一点 (x,y)及偏离它的另一点 (x+a,y+b),设该点对的灰度值为(g1,g2)。令点(x,y) 在整个画面上移动,则会得到各种 (g1,g2)值,设灰度值的级数为 k,则(g1,g2) 的组合共有 k^2;种。对于整个画面,统计出每一种(g1,g2)值出现的次数,然后排列成一个方阵,在用(g1,g2) 出现的总次数将它们归一化为出现的概率P(g1,g2),这样的方阵称为灰度共生矩阵。距离差分值(a,b) 取不同的数值组合,可以得到不同情况下的联合概率矩阵。(a,b)取值要根据纹理周期分布的特性来选择,对于较细的纹理,选取(1,0)、(1,1)、(2,0)等小的差分值。 当 a=1,b=0时,像素对是水平的,即0度扫描;当a=0,b=1 时,像素对是垂直的,即90度扫描;当 a=1,b=1时,像素对是右对角线的,即45度扫描;当 a=-1,b=-1时,像素对是左对角线,即135度扫描。
这样,两个象素灰度级同时发生的概率,就将 (x,y)的空间坐标转化为“灰度对” (g1,g2)的描述,形成了灰度共生矩阵。(百度百科)
一幅图象的灰度共生矩阵能反映出图象灰度关于方向、相邻间隔、变化幅度的综合信息,它是分析图象的局部模式和它们排列规则的基础。
感觉差不多了吧!
2.灰度共生矩阵特征量
灰度共生矩阵特征量
2.1对比度
度量 矩阵的值是如何分布和图像中局部变化的多少,反应了图像的清晰度和纹理的沟纹深浅。纹理的沟纹越深,反差越大,效果越清晰;反之,对比值小,则沟纹浅,效果模糊。
2.2 能量
能量变换反映了图像灰度分布均匀程度和纹理粗细度。若灰度共生矩阵的元素值相近,则能量较小,表示纹理细致;若其中一些值大,而其它值小,则能量值较大。能量值大表明一种较均一和规则变化的纹理模式。
2.3 熵
图像包含信息量的随机性度量。当共生矩阵中所有值均相等或者像素值表现出最大的随机性时,熵最大;因此熵值表明了图像灰度分布的复杂程度,熵值越大,图像越复杂。
2.4 逆方差
逆方差反映了图像纹理局部变化的大小,若图像纹理的不同区域间较均匀,变化缓慢,逆方差会较大,反之较小。
2.5相关性
用来度量图像的灰度级在行或列方向上的相似程度,因此值得大小反应了局部灰度相关性,值越大,相关性也越大。
————————————————
版权声明:本文为CSDN博主「sunny_develop」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/guanyuqiu/article/details/53117507
3.代码
GLCM.h
#include<iostream>
#include <cassert>
#include <vector>
#include <iterator>
#include <functional>
#include <algorithm>
#include <opencv2/opencv.hpp>using namespace std;
using namespace cv;typedef vector<vector<int> > VecGLCM;typedef struct _GLCMFeatures
{_GLCMFeatures(): energy(0.0), entropy(0.0), contrast(0.0), idMoment(0.0){}double energy; // 能量 double entropy; // 熵double contrast; // 对比度double idMoment; // 逆差分矩, inverse difference moment} GLCMFeatures;class GLCM
{
public:GLCM();~GLCM();public:// 枚举灰度共生矩阵的方向enum {GLCM_HORIZATION = 0, // 水平GLCM_VERTICAL = 1, // 垂直GLCM_ANGLE45 = 2, // 45度角GLCM_ANGLE135 = 3 // 135度角};public:// 计算灰度共生矩阵void calGLCM(IplImage* inputImg, VecGLCM& vecGLCM, int angle);// 计算特征值void getGLCMFeatures(VecGLCM& vecGLCM, GLCMFeatures& features);
public:// 初始化灰度共生矩阵void initGLCM(VecGLCM& vecGLCM, int size = 16);// 设置灰度划分等级,默认值为 16void setGrayLevel(int grayLevel) { m_grayLevel = grayLevel; }// 获取灰度等级int getGrayLevel() const { return m_grayLevel; }
private:// 计算水平灰度共生矩阵void getHorisonGLCM(VecGLCM &src, VecGLCM &dst, int imgWidth, int imgHeight);// 计算垂直灰度共生矩阵void getVertialGLCM(VecGLCM &src, VecGLCM &dst, int imgWidth, int imgHeight);// 计算 45 度灰度共生矩阵void getGLCM45(VecGLCM &src, VecGLCM &dst, int imgWidth, int imgHeight);// 计算 135 度灰度共生矩阵void getGLCM135(VecGLCM &src, VecGLCM &dst, int imgWidth, int imgHeight);private:int m_grayLevel; // 将灰度共生矩阵划分为 grayLevel 个等级};
//GLCM.cpp
#include "GLCM.h"GLCM::GLCM() : m_grayLevel(16)
{}GLCM::~GLCM()
{}//==============================================================================
// 函数名称: initGLCM
// 参数说明: vecGLCM,要进行初始化的共生矩阵,为二维方阵
// size, 二维矩阵的大小,必须与图像划分的灰度等级相等
// 函数功能: 初始化二维矩阵
//==============================================================================void GLCM::initGLCM(VecGLCM& vecGLCM, int size)
{assert(size == m_grayLevel);vecGLCM.resize(size);for (int i = 0; i < size; ++i){vecGLCM[i].resize(size);}for (int i = 0; i < size; ++i){for (int j = 0; j < size; ++j){vecGLCM[i][j] = 0;}}
}//==============================================================================
// 函数名称: getHorisonGLCM
// 参数说明: src,要进行处理的矩阵,源数据
// dst,输出矩阵,计算后的矩阵,即要求的灰度共生矩阵
// imgWidth, 图像宽度
// imgHeight, 图像高度
// 函数功能: 计算水平方向的灰度共生矩阵
//==============================================================================void GLCM::getHorisonGLCM(VecGLCM &src, VecGLCM &dst, int imgWidth, int imgHeight)
{int height = imgHeight;int width = imgWidth;for (int i = 0; i < height; ++i){for (int j = 0; j < width - 1; ++j){int rows = src[i][j];int cols = src[i][j + 1];dst[rows][cols]++;}}}//==============================================================================
// 函数名称: getVertialGLCM
// 参数说明: src,要进行处理的矩阵,源数据
// dst,输出矩阵,计算后的矩阵,即要求的灰度共生矩阵
// imgWidth, 图像宽度
// imgHeight, 图像高度
// 函数功能: 计算垂直方向的灰度共生矩阵
//==============================================================================void GLCM::getVertialGLCM(VecGLCM &src, VecGLCM &dst, int imgWidth, int imgHeight)
{int height = imgHeight;int width = imgWidth;for (int i = 0; i < height - 1; ++i){for (int j = 0; j < width; ++j){int rows = src[i][j];int cols = src[i + 1][j];dst[rows][cols]++;}}
}//==============================================================================
// 函数名称: getGLCM45
// 参数说明: src,要进行处理的矩阵,源数据
// dst,输出矩阵,计算后的矩阵,即要求的灰度共生矩阵
// imgWidth, 图像宽度
// imgHeight, 图像高度
// 函数功能: 计算45度的灰度共生矩阵
//==============================================================================void GLCM::getGLCM45(VecGLCM &src, VecGLCM &dst, int imgWidth, int imgHeight)
{int height = imgHeight;int width = imgWidth;for (int i = 0; i < height - 1; ++i){for (int j = 0; j < width - 1; ++j){int rows = src[i][j];int cols = src[i + 1][j + 1];dst[rows][cols]++;}}
}//==============================================================================
// 函数名称: getGLCM135
// 参数说明: src,要进行处理的矩阵,源数据
// dst,输出矩阵,计算后的矩阵,即要求的灰度共生矩阵
// imgWidth, 图像宽度
// imgHeight, 图像高度
// 函数功能: 计算 135 度的灰度共生矩阵
//==============================================================================void GLCM::getGLCM135(VecGLCM& src, VecGLCM& dst, int imgWidth, int imgHeight)
{int height = imgHeight;int width = imgWidth;for (int i = 0; i < height - 1; ++i){for (int j = 1; j < width; ++j){int rows = src[i][j];int cols = src[i + 1][j - 1];dst[rows][cols]++;}}
}//==============================================================================
// 函数名称: calGLCM
// 参数说明: inputImg,要进行纹理特征计算的图像,为灰度图像
// vecGLCM, 输出矩阵,根据灰度图像计算出的灰度共生阵
// angle,灰度共生矩阵的方向,有水平、垂直、45度、135度四个方向
// 函数功能: 计算灰度共生矩阵
//==============================================================================void GLCM::calGLCM(IplImage* inputImg, VecGLCM& vecGLCM, int angle)
{assert(inputImg->nChannels == 1);IplImage* src = NULL;src = cvCreateImage(cvGetSize(inputImg), IPL_DEPTH_32S, inputImg->nChannels);cvConvert(inputImg, src);int height = src->height;int width = src->width;int maxGrayLevel = 0;// 寻找最大像素灰度最大值for (int i = 0; i < height; ++i){for (int j = 0; j < width; ++j){int grayVal = cvGetReal2D(src, i, j);if (grayVal > maxGrayLevel){maxGrayLevel = grayVal;}}}// end for i++maxGrayLevel;VecGLCM tempVec;// 初始化动态数组tempVec.resize(height);for (int i = 0; i < height; ++i){tempVec[i].resize(width);}if (maxGrayLevel > 16)//若灰度级数大于16,则将图像的灰度级缩小至16级,减小灰度共生矩阵的大小。{for (int i = 0; i < height; ++i){for (int j = 0; j < width; ++j){int tmpVal = cvGetReal2D(src, i, j);tmpVal /= m_grayLevel;tempVec[i][j] = tmpVal;}}if (angle == GLCM_HORIZATION) // 水平方向getHorisonGLCM(tempVec, vecGLCM, width, height);if (angle == GLCM_VERTICAL) // 垂直方向getVertialGLCM(tempVec, vecGLCM, width, height);if (angle == GLCM_ANGLE45) // 45 度灰度共生阵getGLCM45(tempVec, vecGLCM, width, height);if (angle == GLCM_ANGLE135) // 135 度灰度共生阵getGLCM135(tempVec, vecGLCM, width, height);}else//若灰度级数小于16,则生成相应的灰度共生矩阵{for (int i = 0; i < height; ++i){for (int j = 1; j < width; ++j){int tmpVal = cvGetReal2D(src, i, j);tempVec[i][j] = tmpVal;}}if (angle == GLCM_HORIZATION) // 水平方向getHorisonGLCM(tempVec, vecGLCM, width, height);if (angle == GLCM_VERTICAL) // 垂直方向getVertialGLCM(tempVec, vecGLCM, width, height);if (angle == GLCM_ANGLE45) // 45 度灰度共生阵getGLCM45(tempVec, vecGLCM, width, height);if (angle == GLCM_ANGLE135) // 135 度灰度共生阵getGLCM135(tempVec, vecGLCM, width, height);}cvReleaseImage(&src);
}//==============================================================================
// 函数名称: getGLCMFeatures
// 参数说明: vecGLCM, 输入矩阵,灰度共生阵
// features,灰度共生矩阵计算的特征值,主要包含了能量、熵、对比度、逆差分矩
// 函数功能: 根据灰度共生矩阵计算的特征值
//==============================================================================void GLCM::getGLCMFeatures(VecGLCM& vecGLCM, GLCMFeatures& features)
{int total = 0;for (int i = 0; i < m_grayLevel; ++i){for (int j = 0; j < m_grayLevel; ++j){total += vecGLCM[i][j]; // 求所有图像的灰度值的和}}vector<vector<double> > temp;temp.resize(m_grayLevel);for (int i = 0; i < m_grayLevel; ++i){temp[i].resize(m_grayLevel);}// 归一化for (int i = 0; i < m_grayLevel; ++i){for (int j = 0; j < m_grayLevel; ++j){temp[i][j] = (double)vecGLCM[i][j] / (double)total;}}for (int i = 0; i < m_grayLevel; ++i){for (int j = 0; j < m_grayLevel; ++j){features.energy += temp[i][j] * temp[i][j];if (temp[i][j]>0)features.entropy -= temp[i][j] * log(temp[i][j]); //熵 features.contrast += (double)(i - j)*(double)(i - j)*temp[i][j]; //对比度features.idMoment += temp[i][j] / (1 + (double)(i - j)*(double)(i - j));//逆差矩}}
}
main.cpp
#include "GLCM.h"
#include <string>void getFileName();
string names[2000];
char data[20];
const string filename = "C:\\Users\\ltc\\Desktop\\data5\\Sobel\\数值处理\\背景\\";int main()
{fstream finout1("data.txt", ios::in | ios::out|ios::trunc);getFileName();int i = 0;char data1[20];while (names[i].length() > 5){strcpy_s(data1, names[i].c_str());string imagename = data1;//灰度共生矩阵IplImage* img = cvLoadImage(data1, 0);cvSetImageROI(img, cvRect(1453, 1149,557, 557));/*cvNamedWindow("ShowSRC"); cvShowImage("ShowSRC",img); cvWaitKey(0); */GLCM glcm;VecGLCM vec;GLCMFeatures features;glcm.initGLCM(vec);// 水平glcm.calGLCM(img, vec, GLCM::GLCM_HORIZATION);glcm.getGLCMFeatures(vec, features);double energy_hor = features.energy;double entropy_hor = features.entropy;double contrast_hor = features.contrast;double idMoment_hor = features.idMoment;// 垂直glcm.calGLCM(img, vec, GLCM::GLCM_VERTICAL);glcm.getGLCMFeatures(vec, features);double energy_vetical = features.energy;double entropy_vetical = features.entropy;double contrast_vetical = features.contrast;double idMoment_vetical = features.idMoment;// 45 度glcm.calGLCM(img, vec, GLCM::GLCM_ANGLE45);glcm.getGLCMFeatures(vec, features);double energy_45 = features.energy;double entropy_45 = features.entropy;double contrast_45 = features.contrast;double idMoment_45 = features.idMoment;// 135 度glcm.calGLCM(img, vec, GLCM::GLCM_ANGLE135);glcm.getGLCMFeatures(vec, features);double energy_135 = features.energy;double entropy_135 = features.entropy;double contrast_135 = features.contrast;double idMoment_135 = features.idMoment;double energy_average = (energy_135 + energy_45 + energy_hor + energy_vetical) / 4;double entropy_average = (entropy_135 + entropy_45 + entropy_hor + entropy_vetical) / 4;double contrast_average = (contrast_135 + contrast_45 + contrast_hor + contrast_vetical) / 4;double idMoment_average = (idMoment_135 + idMoment_45 + idMoment_hor + idMoment_vetical) / 4;cout<< energy_average<<" " <<entropy_average <<" "<< contrast_average<<" " << idMoment_average << endl;finout1 << energy_average<<" " <<entropy_average <<" "<< contrast_average<<" " << idMoment_average << endl;i++;}system("pause");return 0;
}void getFileName(){fstream finout("C:\\Users\\ltc\\Desktop\\data5\\FILENAME.TXT", ios::in | ios::out);ostringstream outstr;if (finout.is_open()){finout.seekg(0);int i = 0;while (finout.getline(data, 19)){outstr << data;names[i] = outstr.str();//cout <<setw(30)<<i<<setw(30)<<names[i]<<'\n';i++;outstr.str("");}}elsecout << "failed" << endl;
}
————————————————
版权声明:本文为CSDN博主「青雲-吾道乐途」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37059483/article/details/78292869
---------------------
作者:hello~bye~
来源:CSDN
原文:https://blog.csdn.net/qq_36654309/article/details/106473599
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件
[转]灰度共生矩阵(超简单理解)相关推荐
- 灰度共生矩阵(超简单理解)
1.灰度共生矩阵生成原理 灰度共生矩阵(GLDM)的统计方法是20世纪70年代初由R.Haralick等人提出的,它是在假定图像中各像素间的空间分布关系包含了图像纹理信息的前提下,提出的具有广泛 ...
- P、NP、NP-hard、NPC问题超简单理解
查了好多资料,现在网上的资料都不说人话,简单的问题故意写得让别人看懂不以显示自己的水平很高深?真正的大师难道不是把复杂问题说得很简单的人?把简单问题说得让别人看不懂显得自己很高深的就是煞笔. 多项式定 ...
- 超简单理解L0、L1、L2范数原理及作用
L0,L1,L2范数在机器学习中的应用个人理解 博文针对L0.L1.L2范数原理及在机器学习中作用进行了非常通俗易懂的解释,为博主了解相关概念后自我理解,相信对于看完本篇分析的读者来说对理解这几个范数 ...
- 操作系统基础:进程逻辑思维导图,超简单理解进程管理
...
- 超简单理解自平衡二叉查找树的 旋转 是什么?
首先给大家科普下基础知识 (双旋转的时候,LR左右,RL右左,且首转以尾根节点为旋转中心,第二次旋转以尾根节点的父节点为旋转中心) 一:什么情况下二叉查找树不平衡? 答:一个节点的左子树与右子树的高度 ...
- 灰度共生矩阵:Gray-Level Co-occurrence Matrix
定义 灰度共生矩阵一开始是为了解决图像处理中的问题的.具体定义如下:用图片上两个位置的像素的联合概率分布进行定义,不仅能反应亮度的分布特征,也反应具有同样亮度或者接近亮度像素之间的位置分布特性,是有关 ...
- 灰度共生矩阵的生成和理解
在网上看了很多灰度共生矩阵生成的例子感觉都没有说明白,要不就直接上结果要不就给一堆看不懂的代码和公式,后来看了matlab中的介绍就明白了,其实很简单,仔细把下面的看三遍就理解怎么来的了! GLCM表 ...
- 怎么把word里面的彩色图转化为灰度图,直接在word里面操作,无需转其他软件,超简单!(位图和矢量图都可以)
怎么把word里面的彩色图转化为灰度图,直接在word里面操作,无需转其他软件,超简单!(位图和矢量图都可以) Microsoft Office Word是微软公司的一个文字处理器应用程序.它最初是由 ...
- 灰度共生矩阵(GLCM)理解
灰度共生矩阵 灰度共生矩阵法,顾名思义,就是通过计算灰度图像得到它的共生矩阵,然后透过计算这个共生矩阵得到矩阵的部分特征值,来分别代表图像的某些纹理特征(纹理的定义仍是难点).灰度共生矩阵能反映图像灰 ...
最新文章
- 平时工作事项太多,有哪些好用的事项管理软件?
- 【Linux命令大全】
- Of course, Huawei has brought more than just
- debug跳出循环_Java基础-第04章:循环结构「云图智联」
- .NET:枚举的默认值
- L2-029 特立独行的幸福 (25 分)-PAT 团体程序设计天梯赛 GPLT
- mex2 Inputs and Outputs
- JVM性能调优监控工具专题一:JVM自带性能调优工具(jps,jstack,jmap,jhat,jstat,hprof)...
- CTF 内存取证 USB流量分析
- (Mac) Mac上如何修改本地的hostname
- oracle数据库教程ppt,Oracle 数据库入门教程 PPT
- 微软输入法和搜狗输入法中的双拼
- 深入浅出Zookeeper集群搭建
- 《小窗幽记》全文 陈继儒
- smartBi调整参数排版
- 系统架构师设计培训心得之二——架构设计
- 为什么黑客不攻击支付宝?
- 蜘蛛池的作用与工作原理(公羊优链蜘蛛池)
- Javascript特效之可翻阅上一条下一条的动态文字
- 这些网站,你应该知道(一)