学习记录,不当之处多多指教,在此感谢以下博主
灰度共生矩阵的原理及实现(特征提取)-OpenCV
灰度共生矩阵的生成和理解
灰度共生矩阵原理
以水平相邻为例:
GLCM(1,1)=1表示I图中左右相邻都为1的只有一对
GLCM(1,2)=2表示I图中左右分别为1,2的有两对,如上图的红线所示
通常我们假设有两个点f(x,y)与f(x+a,y+b)相邻:x方向相隔a,y方向相隔b
a=1,b=0:水平相邻,0度
a=1,b=1:对角相邻,45度
a=-1,b=1:对角相邻,135度
1,灰度共生矩阵定义为:从灰度为i的像素点出发,统计保持一定距离的两具有某灰度分布的像素。统计"灰度对"同时发生的概率,形成了灰度共生矩阵。
2,共生矩阵用两个位置的像素的联合概率密度来定义,它不仅反应亮度的分布特征,也反映具有相同亮度或者接近亮度像素之间的位置分布特性,是有关图像亮度变换的二阶统计特征。
3,一般不直接作为区分纹理特征(数据量大),一般采用如下统计量:能量,熵,对比度,均匀性,相关性,方差,和平均,和方差,和熵,差方差,差平均,差熵,相关信息测度,最大相关系数。
能量:角二阶矩阵(Angular Second Moment,ASM),Energy,uniformity,uniformity of energy
公式: ASM=sum(p(i,j).^2)
p(i,j)是归一化的灰度共生矩阵。反应了图像灰度分布均匀程度和纹理粗细度,图像均匀,纹理较细,反应在共生矩阵就是大量集中在某一部分,因此ASM值大。
熵:(Entropy,ENT)
公式: ENT = sum(p(i,j)*(-log(p(i,j))))
p(i,j)是归一化的灰度共生矩阵。描述图像具有的信息量的度量,表明图像的复杂度,和复杂度成正比。
反差分矩阵:(Inverse Differential Moment,IDM)
公式: IDM = sum(p(i,j)/(1+(i-j)^2))
反应了纹理的清晰程度和规则程度,纹理清晰,规律性强,易于描述,值较大,反之较小。
对比度:(Contrast)
公式: contrast= sum(p(i,j)*(i-j)^2)
返回图像中某个像素与它的邻居之间的对比度。反映了图像的清晰度和纹理沟纹深浅的程度
代码源自: 传送门
GLCM.h
#include
#include
#include
#include
#include
#include
#include
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; // 能量ASM:angular second moment
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);
// 设置灰度划分等级,默认值为 16
void 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 "stdafx.h"
#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 = (tmpVal*m_grayLevel)/maxGrayLevel;
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]; //ASM
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));//逆差矩
}
}
}
调用:
//src为输入图像IplImage,自己load一张图像即可
IplImage* img = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
cvCopy(src,img);
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;
原作者灰度分级
//GLCM.cpp Line187
tmpVal /= m_grayLevel);
改为
tmpVal = (tmpVal*m_grayLevel)/maxGrayLevel;
灰度梯度共生矩阵纹理特征
灰度梯度共生矩阵Python
1,灰度梯度共生矩阵不仅反应了灰度之间的关系,还反映了梯度之间的关系。灰度是构建图像的基础,梯度是构建图像边缘的要素。
2,描绘了图像内各像素点灰度与梯度的分布规律,给出了像点与其领域内像点的空间关系,能很好的描绘纹理。对于方向性的纹理也可以从梯度方向上反应出来。
3,由之前相邻的像素点组成的共生矩阵变成灰度度和梯度图对应点组成的共生矩阵。
4, 与GLCM的区别,GLCM是灰度级nGray*nGray组成的矩阵,GGCM是灰度级nGray与梯度级nGrad组成的矩阵。GLCM统计的是灰度对(相邻或其他方式)的个数,GGCM统计的是灰度-梯度对(灰度图像,梯度图像相同位置对应)的个数。