使用C++、opencv获取图像的灰度共生矩阵,即能量、熵、对比度、逆差矩等图像特征参数
灰度共生矩阵,指的是一种通过研究灰度的空间相关特性来描述纹理的常用方法,通俗的说就是图像的一组关于纹理信息图像特征(能量、熵、对比度、逆差矩),可以将纹理数字化。
灰度共生矩阵的原理和四个特征参数的计算公式可参考博客:https://blog.csdn.net/zhangxz259/article/details/81700167及https://blog.csdn.net/qq_37059483/article/details/78292869
代码:
#include "stdafx.h"
#include <iostream>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
//灰度等级设为16
const int gray_level = 16;
//0度灰度共生矩阵
void getglcm_horison(Mat& input, Mat& dst)
{
Mat src = input;
CV_Assert(1 == src.channels());
src.convertTo(src, CV_32S);
int height = src.rows;
int width = src.cols;
int max_gray_level = 0;
for (int j = 0; j < height; j++)//寻找像素灰度最大值
{
int* srcdata = src.ptr<int>(j);
for (int i = 0; i < width; i++)
{
if (srcdata[i] > max_gray_level)
{
max_gray_level = srcdata[i];
}
}
}
max_gray_level++;//像素灰度最大值加1即为该矩阵所拥有的灰度级数
if (max_gray_level > 16)//若灰度级数大于16,则将图像的灰度级缩小至16级,减小灰度共生矩阵的大小。
{
for (int i = 0; i < height; i++)
{
int*srcdata = src.ptr<int>(i);
for (int j = 0; j < width; j++)
{
srcdata[j] = (int)srcdata[j] / gray_level;
}
}
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]++;
}
}
}
else//若灰度级数小于16,则生成相应的灰度共生矩阵
{
dst.create(max_gray_level, max_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 getglcm_vertical(Mat& input, Mat& dst)
{
Mat src = input;
CV_Assert(1 == src.channels());
src.convertTo(src, CV_32S);
int height = src.rows;
int width = src.cols;
int max_gray_level = 0;
for (int j = 0; j < height; j++)
{
int* srcdata = src.ptr<int>(j);
for (int i = 0; i < width; i++)
{
if (srcdata[i] > max_gray_level)
{
max_gray_level = srcdata[i];
}
}
}
max_gray_level++;
if (max_gray_level > 16)
{
for (int i = 0; i < height; i++)//将图像的灰度级缩小至16级,减小灰度共生矩阵的大小。
{
int*srcdata = src.ptr<int>(i);
for (int j = 0; j < width; j++)
{
srcdata[j] = (int)srcdata[j] / gray_level;
}
}
dst.create(gray_level, gray_level, CV_32SC1);
dst = Scalar::all(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]++;
}
}
}
else
{
dst.create(max_gray_level, max_gray_level, CV_32SC1);
dst = Scalar::all(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 getglcm_45(Mat& input, Mat& dst)
{
Mat src = input;
CV_Assert(1 == src.channels());
src.convertTo(src, CV_32S);
int height = src.rows;
int width = src.cols;
int max_gray_level = 0;
for (int j = 0; j < height; j++)
{
int* srcdata = src.ptr<int>(j);
for (int i = 0; i < width; i++)
{
if (srcdata[i] > max_gray_level)
{
max_gray_level = srcdata[i];
}
}
}
max_gray_level++;
if (max_gray_level > 16)
{
for (int i = 0; i < height; i++)//将图像的灰度级缩小至16级,减小灰度共生矩阵的大小。
{
int*srcdata = src.ptr<int>(i);
for (int j = 0; j < width; j++)
{
srcdata[j] = (int)srcdata[j] / gray_level;
}
}
dst.create(gray_level, gray_level, CV_32SC1);
dst = Scalar::all(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++)
{
int rows = srcdata[j];
int cols = srcdata1[j + 1];
dst.ptr<int>(rows)[cols]++;
}
}
}
else
{
dst.create(max_gray_level, max_gray_level, CV_32SC1);
dst = Scalar::all(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++)
{
int rows = srcdata[j];
int cols = srcdata1[j + 1];
dst.ptr<int>(rows)[cols]++;
}
}
}
}
//135度灰度共生矩阵
void getglcm_135(Mat& input, Mat& dst)
{
Mat src = input;
CV_Assert(1 == src.channels());
src.convertTo(src, CV_32S);
int height = src.rows;
int width = src.cols;
int max_gray_level = 0;
for (int j = 0; j < height; j++)
{
int* srcdata = src.ptr<int>(j);
for (int i = 0; i < width; i++)
{
if (srcdata[i] > max_gray_level)
{
max_gray_level = srcdata[i];
}
}
}
max_gray_level++;
if (max_gray_level > 16)
{
for (int i = 0; i < height; i++)//将图像的灰度级缩小至16级,减小灰度共生矩阵的大小。
{
int*srcdata = src.ptr<int>(i);
for (int j = 0; j < width; j++)
{
srcdata[j] = (int)srcdata[j] / gray_level;
}
}
dst.create(gray_level, gray_level, CV_32SC1);
dst = Scalar::all(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++)
{
int rows = srcdata[j];
int cols = srcdata1[j - 1];
dst.ptr<int>(rows)[cols]++;
}
}
}
else
{
dst.create(max_gray_level, max_gray_level, CV_32SC1);
dst = Scalar::all(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++)
{
int rows = srcdata[j];
int cols = srcdata1[j - 1];
dst.ptr<int>(rows)[cols]++;
}
}
}
}
//计算特征值
void feature_computer(Mat&src, double& Asm, double& Eng, double& Con, double& Idm)
{
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 copy;
copy.create(height, width, CV_64FC1);
for (int i = 0; i < height; i++)
{
int*srcdata = src.ptr<int>(i);
double*copydata = copy.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 = copy.ptr<double>(i);
for (int j = 0; j < width; j++)
{
Asm += srcdata[j] * srcdata[j];//能量
if (srcdata[j]>0)
Eng -= srcdata[j] * log(srcdata[j]);//熵
Con += (double)(i - j)*(double)(i - j)*srcdata[j];//对比度
Idm += srcdata[j] / (1 + (double)(i - j)*(double)(i - j));//逆差矩
}
}
}
int main()
{
system("color 02");
Mat dst_horison, dst_vertical, dst_45, dst_135;
//读取源图像
Mat src = imread("D:\\哀.jpg");
if (src.empty())
{
return -1;
}
namedWindow("原图", WINDOW_NORMAL);
imshow("原图", src);
Mat src_gray;
//src.create(src.size(), CV_8UC1);
//src_gray = Scalar::all(0);
cvtColor(src, src_gray, COLOR_BGR2GRAY);
namedWindow("灰度图", WINDOW_NORMAL);
imshow("灰度图", src_gray);
getglcm_horison(src_gray, dst_horison);
getglcm_vertical(src_gray, dst_vertical);
getglcm_45(src_gray, dst_45);
getglcm_135(src_gray, dst_135);
double eng_horison = 0, con_horison = 0, idm_horison = 0, asm_horison = 0;
feature_computer(dst_horison, asm_horison, eng_horison, con_horison, idm_horison);
cout << "能量asm_horison:" << asm_horison << endl;
cout << "熵eng_horison:" << eng_horison << endl;
cout << "对比度con_horison:" << con_horison << endl;
cout << "逆差矩idm_horison:" << idm_horison << endl;
double eng_vertical = 0, con_vertical = 0, idm_vertical = 0, asm_vertical = 0;
feature_computer(dst_vertical, asm_vertical, eng_vertical, con_vertical, idm_vertical);
cout << "能量asm_vertical:" << asm_vertical << endl;
cout << "熵eng_vertical:" << eng_vertical << endl;
cout << "对比度con_vertical:" << con_vertical << endl;
cout << "逆差矩idm_vertical:" << idm_vertical << endl;
double eng_45 = 0, con_45 = 0, idm_45 = 0, asm_45 = 0;
feature_computer(dst_45, asm_45, eng_45, con_45, idm_45);
cout << "能量asm_45:" << asm_45 << endl;
cout << "熵eng_45:" << eng_45 << endl;
cout << "对比度con_45:" << con_45 << endl;
cout << "逆差矩idm_45:" << idm_45 << endl;
double eng_135 = 0, con_135 = 0, idm_135 = 0, asm_135 = 0;
feature_computer(dst_135, asm_135, eng_135, con_135, idm_135);
cout << "能量asm_135:" << asm_135 << endl;
cout << "熵eng_135:" << eng_135 << endl;
cout << "对比度con_135:" << con_135 << endl;
cout << "逆差矩idm_135:" << idm_135 << endl;
//写入文件
/*FILE *fp;
fp = fopen("灰度共生矩阵数据.txt", "a");
if (fp != NULL)
fprintf(fp, "\n水平:%f\t%f\t%f\t%f\n垂直:%f\t%f\t%f\t%f\n45:%f\t%f\t%f\t%f\n135:%f\t%f\t%f\t%f\n", asm_horison, eng_horison, con_horison, idm_horison,asm_vertical, eng_vertical, con_vertical, idm_vertical, asm_45, eng_45, con_45, idm_45, asm_135, eng_135, con_135, idm_135);
fclose(fp);*/
waitKey(0);
return 0;
}
原图:
结果: