GLCM特征提取
glcm会提取到五个特征值
struct GLCMFeature_t
{
float entropy;
float homogeneity;
float contrast;
float ASM;
float correlation;
int featureNum = 5;
};
可以选不同角度的值拼接成向量
int angleList[] = { 0, 45, 90, 135 };
滑动窗口提取特征
向量x角度只有20个长度的向量,需要滑动窗口收集局部图片特征增加向量长度
void slidingWindow(Mat& image, Size windowSize, int stepSize, vector<float> &hogDescriptor) {
// 获取图像的宽度和高度
int imageWidth = image.cols;
int imageHeight = image.rows;
std::vector<float> destination;
int angleList[] = { 0, 45, 90, 135 };
// 循环遍历图像,滑动窗口
for (int y = 0; y < imageHeight; y += stepSize) {
for (int x = 0; x < imageWidth; x += stepSize) {
// 计算当前窗口的 ROI 区域
Rect windowRect(x, y, windowSize.width, windowSize.height);
// 处理边界问题,确保窗口不超出图像边界
if (windowRect.x + windowSize.width > imageWidth) {
windowRect.x = imageWidth - windowSize.width;
}
if (windowRect.y + windowSize.height > imageHeight) {
windowRect.y = imageHeight - windowSize.height;
}
Mat window = image(windowRect);
// 在这里可以对窗口进行处理,比如进行某种操作或者分析
glcm.Init(window, 16);
vector<float> result = glcm.GetFeaturesByAngle(angleList, 4);
destination.insert(destination.end(), result.begin(), result.end());
}
}
//再整体来一张
Mat fullImg;
resize(image, fullImg, Size(40,40));
glcm.Init(fullImg, 16);
vector<float> result = glcm.GetFeaturesByAngle(angleList, 4);
destination.insert(destination.end(), result.begin(), result.end());
hogDescriptor = destination;
}
GLCM特征实现
cpp文件
#include "GLCM.h"
GLCM::GLCM()
{
}
GLCM::GLCM(InputArray _srcImg, int _GLCMClass)
{
srcImg = _srcImg.getMat();
minMaxIdx(srcImg, NULL, &maxPixVal);
if (_GLCMClass == -1)
GLCMClass = (int)maxPixVal + 1;
else
GLCMClass = _GLCMClass;
GLCMMat = *(new Mat(Size(GLCMClass, GLCMClass), CV_32FC1));
}
GLCM::GLCM(String path, int _GLCMClass)
{
srcImg = imread(path, CV_8UC1);
minMaxIdx(srcImg, NULL, &maxPixVal);
if (_GLCMClass == -1)
GLCMClass = (int)maxPixVal + 1;
else
GLCMClass = _GLCMClass;
GLCMMat = *(new Mat(Size(GLCMClass, GLCMClass), CV_32FC1));
}
void GLCM::Init(InputArray _srcImg, int _GLCMClass)
{
srcImg = _srcImg.getMat();
minMaxIdx(srcImg, NULL, &maxPixVal);
if (_GLCMClass == -1)
GLCMClass = (int)maxPixVal + 1;
else
GLCMClass = _GLCMClass;
GLCMMat = *(new Mat(Size(GLCMClass, GLCMClass), CV_32FC1));
}
void GLCM::Init(String path, int _GLCMClass)
{
srcImg = imread(path, CV_8UC1);
minMaxIdx(srcImg, NULL, &maxPixVal);
if (_GLCMClass == -1)
GLCMClass = (int)maxPixVal + 1;
else
GLCMClass = _GLCMClass;
GLCMMat = *(new Mat(Size(GLCMClass, GLCMClass), CV_32FC1));
}
GLCM::~GLCM()
{
}
/*
* Brief:
* The function can calculate the GLCM matrix by using origin gray image
*
* Params:
* angle: The angle for scanning, can be 0, 45, 90, 135
* offset: The stride(offset) of the scanning
* norm: Using normalization or not
*/
void GLCM::CalGLCM(int angle, int offset, bool norm)
{
Size srcSize = srcImg.size();
// using matrix temp to store the pixel in GLCM_class-gray
Mat temp(srcSize, CV_8UC1);
GLCMMat = Scalar_<float>(0);
// zip srcImg into temp
for (int h = 0; h < srcSize.height; ++h)
{
for (int w = 0; w < srcSize.width; ++w)
{
temp.at<uchar>(h, w) = (uchar)(srcImg.at<uchar>(h, w) * GLCMClass / (maxPixVal + 1));
}
}
// calculate the matrix
int row = 0, col = 0;
if (angle == 0)
{
for (int h = 0; h < srcSize.height; ++h)
{
uchar* tempLine = temp.ptr(h);
for (int w = 0; w < srcSize.width - offset; ++w)
{
row = tempLine[w];
col = tempLine[w + offset];
GLCMMat.at<float>(row, col)++;
GLCMMat.at<float>(col, row)++;
}
}
}
else if (angle == 90)
{
for (int h = 0; h < srcSize.height - offset; ++h)
{
uchar* tempLine = temp.ptr(h);
uchar* tempLineOffset = temp.ptr(h + offset);
for (int w = 0; w < srcSize.width; ++w)
{
row = tempLine[w];
col = tempLineOffset[w];
GLCMMat.at<float>(row, col)++;
GLCMMat.at<float>(col, row)++;
}
}
}
else if (angle == 45)
{
for (int h = 0; h < srcSize.height - offset; ++h)
{
uchar* tempLine = temp.ptr(h);
uchar* tempLineOffset = temp.ptr(h + offset);
for (int w = 0; w < srcSize.width - offset; ++w)
{
row = tempLine[w];
col = tempLineOffset[w + offset];
GLCMMat.at<float>(row, col)++;
GLCMMat.at<float>(col, row)++;
}
}
}
else if (angle == 135)
{
for (int h = 0; h < srcSize.height - offset; ++h)
{
uchar* tempLine = temp.ptr(h);
uchar* tempLineOffset = temp.ptr(h + offset);
for (int w = 1; w < srcSize.width; ++w)
{
row = tempLine[w];
col = tempLineOffset[w - offset];
GLCMMat.at<float>(row, col)++;
GLCMMat.at<float>(col, row)++;
}
}
}
// normalization
if (norm)
{
float sum = 0;
for (int i = 0; i < GLCMClass; ++i)
{
for (int j = 0; j < GLCMClass; ++j)
{
sum += GLCMMat.at<float>(i, j);
}
}
for (int i = 0; i < GLCMClass; ++i)
{
for (int j = 0; j < GLCMClass; ++j)
{
GLCMMat.at<float>(i, j) /= (sum * 1.0);
}
}
}
}
/*
* Brief:
* Using computed GLCMMat for caulating GLCMFeature
*/
void GLCM::CalFeature()
{
GLCMFeature.entropy = 0;
GLCMFeature.homogeneity = 0;
GLCMFeature.contrast = 0;
GLCMFeature.ASM = 0;
GLCMFeature.correlation = 0;
Size size = GLCMMat.size();
float currVal = 0;
// correlation
double mean_i = 0, mean_j = 0, var_i = 0, var_j = 0;
for (int i = 0; i < size.height; ++i)
{
float* GLCMLine = GLCMMat.ptr<float>(i);
for (int j = 0; j < size.width; ++j)
{
currVal = GLCMLine[j];
mean_i += currVal * i;
mean_j += currVal * j;
var_i += currVal * pow((i - mean_i), 2);
var_j += currVal * pow((j - mean_j), 2);
}
}
for (int h = 0; h < size.height; ++h)
{
float* GLCMLine = GLCMMat.ptr<float>(h);
for (int w = 0; w < size.width; ++w)
{
currVal = GLCMLine[w];
// Entropy
if (currVal > 0)
GLCMFeature.entropy += (pow(h - w, 2) * currVal) / (log(currVal) + 1);
// Contrast
GLCMFeature.contrast += currVal * pow(h - w, 2);
// Homogeneity
GLCMFeature.homogeneity += currVal / (1 + pow(h - w, 2));
// Angular Second Moment
GLCMFeature.ASM += pow(currVal, 2);
// correlation
GLCMFeature.correlation += currVal * (h - mean_i) * (w - mean_j);
}
}
GLCMFeature.correlation /= (sqrt(var_i*var_j) + 1);
}
/*
* Brief:
* Get feature list by using list of angles
*
* Param:
* angleList: The angles for computing GLCM and its features
* angleNum: The length of angleList
*
* Return:
* A list of features
*/
vector<float> GLCM::GetFeaturesByAngle(const int* angleList, int angleNum)
{
vector<float> features;
int angle;
for (int i = 0; i < angleNum; i++)
{
angle = angleList[i];
CalGLCM(angle);
CalFeature();
features.push_back(GLCMFeature.entropy);
features.push_back(GLCMFeature.homogeneity);
features.push_back(GLCMFeature.contrast);
features.push_back(GLCMFeature.ASM);
features.push_back(GLCMFeature.correlation);
}
return features;
}
h文件
//
// Created by Chen on 2018/1/27.
//
#ifndef GLCM_SVM_GLCM_H
#define GLCM_SVM_GLCM_H
#include <opencv2/opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
struct GLCMFeature_t
{
float entropy;
float homogeneity;
float contrast;
float ASM;
float correlation;
int featureNum = 5;
};
class GLCM
{
public:
GLCM(InputArray _srcImg, int _GLCMClass = -1);
GLCM(String path, int _GLCMClass = -1);
GLCM();
~GLCM();
Mat GLCMMat;
Mat srcImg;
int GLCMClass;
double maxPixVal;
GLCMFeature_t GLCMFeature;
void Init(InputArray _srcImg, int _GLCMClass = -1);
void Init(String path, int _GLCMClass = -1);
void CalGLCM(int angle = 0, int offset = 1, bool norm = true);
void CalFeature();
vector<float> GetFeaturesByAngle(const int *angleList, int angleNum);
};
#endif //GLCM_SVM_GLCM_H