灰度共生矩阵及特征提取—OpenCV

因为OpenCV中自带的灰度共生矩阵的计算使用过程中,经常出现问题;之前在项目中使用了别人基于OpenCV重新编写cl_texture的灰度共生矩阵,但该代码只能在MFC环境下使用,且不能释放内存;现有的网上流行的基于OpenCV的灰度共生矩阵的计算,都是基于C++接口实现的;因为,本人使用的是OpenCV的C接口,所以,在结合前人的代码的基础上,实现了基于OpenCV的C接口的灰度共生矩阵的计算;并实现了水平、垂直、45度、135度四个方向的灰度共生矩阵;提取了能量、熵、对比度以及逆差分矩等四个特征;主要实现代码如下所示:

头文件 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);
	// 设置灰度划分等级,默认值为 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 "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"<span style="color:#009900;">
</span>
int main()
{

	IplImage* img = cvLoadImage("1.jpg", 0);
	GLCM glcm;
	VecGLCM vec;
	GLCMFeatures features;
	glcm.initGLCM(vec);
	// 水平
	glcm.calGLCM(img, vec, GLCM::GLCM_HORIZATION);
	glcm.getGLCMFeatures(vec, features);
	// 垂直
	glcm.calGLCM(img, vec, GLCM::GLCM_VERTICAL);
	glcm.getGLCMFeatures(vec, features);
	// 45 度
	glcm.calGLCM(img, vec, GLCM::GLCM_ANGLE45);
	glcm.getGLCMFeatures(vec, features);
	// 135 度
	glcm.calGLCM(img, vec, GLCM::GLCM_ANGLE135);
	glcm.getGLCMFeatures(vec, features);

	cout << "asm = " << features.energy << endl;
	cout << "eng = " << features.entropy << endl;
	cout << "Con = " << features.contrast << endl;
	cout << "Idm = " << features.idMoment << endl;
	system("pause");
	return 0;
}



评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值