1.1Lab颜色空间
CIELab颜色空间是由国际照明委员会(CIE)于1976年定义的一种近似均匀彩色空间。它是一种基于生理特征的颜色系统,与设备无关。其中的L表示亮度,a表示红绿拮抗,b表示蓝黄拮抗。
int calRGB(int width, int height, int *klabels, int l, UINT *img, float &ssr, float &ssg, float &ssb, float &lval, float &aval, float &bval)
{
int R = 0;
int G = 0;
int B = 0;
int q = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int ind = i*width + j;
if (klabels[ind] == l)
{
R = R + (img[ind] >> 16 & 0xFF);
G = G + (img[ind] >> 8 & 0xFF);
B = B + (img[ind] & 0xFF);
q++;
}
}
}
float r = R / q;
float g = G / q;
float b = B / q;
//转换到Lab空间
ssr = round((r / 255.0)*100)/100.0;
ssg = round((g / 255.0) * 100) / 100.0;
ssb = round((b / 255.0)*100)/100.0;
double sR = r / 255.0;
double sG = g / 255.0;
double sB= b / 255.0;
double gR, gG, gB;
sR > 0.04045 ? (gR = pow((sR + 0.055) / 1.055, 2.4)) : (gR = sR / 12.92);
sG > 0.04045 ? (gG = pow((sG + 0.055) / 1.055, 2.4)) : (gG = sG / 12.92);
sB > 0.04045 ? (gB = pow((sB + 0.055) / 1.055, 2.4)) : (gB = sB / 12.92);
double X = gR*0.4124564 + gG*0.3575761 + gB*0.1804375;
double Y = gR*0.2126729 + gG*0.7151522 + gB*0.0721750;
double Z = gR*0.0193339 + gG*0.1191920 + gB*0.9503041;
double epsilon = 0.008856; //actual CIE standard
double kappa = 903.3; //actual CIE standard
double Xr = 0.950456; //reference white
double Yr = 1.0; //reference white
double Zr = 1.088754; //reference white
double xr = X / Xr;
double yr = Y / Yr;
double zr = Z / Zr;
double fx, fy, fz;
if (xr > epsilon) fx = pow(xr, 1.0 / 3.0);
else fx = (kappa*xr + 16.0) / 116.0;
if (yr > epsilon) fy = pow(yr, 1.0 / 3.0);
else fy = (kappa*yr + 16.0) / 116.0;
if (zr > epsilon) fz = pow(zr, 1.0 / 3.0);
else fz = (kappa*zr + 16.0) / 116.0;
lval = (round(116.0*fy - 16.0)/100.0);
aval = (round(500.0*(fx - fy)+128.0)/256.0);
bval = (round(200.0*(fy - fz)+128.0)/256.0);
return 0;
}
1.2HSV颜色空间
HSV颜色空间能够很好的适应实际上人解释的颜色,主要包括三个元素:色调(H),饱和度(S),亮度(V)。如图2.3所示,HSV颜色空间可以表示为倒圆锥。色调(H)用角度度量,取值范围为[0, ],其中红色 ,黄色 ,绿色 ,青色 ,蓝色 ,品红 。饱和度(S)饱和度高,颜色深而艳,取值范围[0,100]。亮度(V)表示明亮程度取值范围[0,100],0表示黑色,100表示白色。
void RGBtoHSV(float R, float G, float B, float&H, float&S, float&V)
{
float max = 0.0, min = 0.0;
if ((R >= G) && (R >= B))
{
max = R;
G >= B ? min = B : min = G;
H = (G - B) / (max - min);
}
if ((G >= R) && (G >= B))
{
max = G;
R >= B ? min = B : min = R;
H = 2 + (B - R) / (max - min);
}
if ((B >= G) && (B >= R))
{
max = B;
R >= G ? min = G: min = R;
H = 4 + (R - G) / (max - min);
}
H = H * 60;
if (H < 0) H = H + 360;
V = max;
S = (max - min) / max;
if (max == min){ H = 0; S = 0; }
}
2.1灰度共生矩阵(GLCM)
灰度共生矩阵有利于反应图像纹理的方向性,定义为从灰度级为i的点按照一个固定的位置关系 到达灰度级为j的概率,d表示两个像素点之间的欧式距离,θ表示像素点之间的方向角。通常 d=1,2,3,4;θ=0,45,90,135 。为了减少计算量,通常会将[0,255]分为特定个数的灰度级,使得具有相似灰度值的像素点具有相同的灰度级,以降低灰度共生矩阵的维数。计算各个区域的能量,对比度,相关性,熵。(就算了水平、竖直、对角三组)
#define GLCM_DIS 3 //灰度共生矩阵的统计距离
#define GLCM_CLASS 16 //计算灰度共生矩阵的图像灰度值等级化
#define GLCM_ANGLE_HORIZATION 0 //水平
#define GLCM_ANGLE_VERTICAL 1 //垂直
#define GLCM_ANGLE_DIGONAL 2 //对角
int calGLCM(Mat& bWavelet, int* klabels, int l, int angleDirection, float* featureVector)
{
int i, j;
int width, height;
if (bWavelet.empty())
return 1;
width = bWavelet.cols;
height = bWavelet.rows;
int * glcm = new int[GLCM_CLASS * GLCM_CLASS];
int * histImage = new int[width * height];
if (NULL == glcm || NULL == histImage)
return 2;
//灰度等级化---分GLCM_CLASS个等级
for (i = 0; i < height; i++)
{
uchar *data = bWavelet.ptr(i);
for (j = 0; j < width; j++)
{
histImage[i * width + j] = (int)(data[j] * GLCM_CLASS / 256);
}
}
//初始化共生矩阵
for (i = 0; i < GLCM_CLASS; i++)
for (j = 0; j < GLCM_CLASS; j++)
glcm[i * GLCM_CLASS + j] = 0;
//计算灰度共生矩阵
int e, r;
float sum = 0.0;
//水平方向
if (angleDirection == GLCM_ANGLE_HORIZATION)
{
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
int ind = i*width + j;
if (klabels[ind] == l)
{
sum++;
r = histImage[i * width + j];
if (j + GLCM_DIS >= 0 && j + GLCM_DIS < width)
{
e = histImage[i * width + j + GLCM_DIS];
glcm[r * GLCM_CLASS + e]++;
}
if (j - GLCM_DIS >= 0 && j - GLCM_DIS < width)
{
e = histImage[i * width + j - GLCM_DIS];
glcm[r * GLCM_CLASS + e]++;
}
}
}
}
}
//垂直方向
else if (angleDirection == GLCM_ANGLE_VERTICAL)
{
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
int ind = i*width + j;
if (klabels[ind] == l)
{
sum++;
r = histImage[i * width + j];
if (i + GLCM_DIS >= 0 && i + GLCM_DIS < height)
{
e = histImage[(i + GLCM_DIS) * width + j];
glcm[r * GLCM_CLASS + e]++;
}
if (i - GLCM_DIS >= 0 && i - GLCM_DIS < height)
{
e = histImage[(i - GLCM_DIS) * width + j];
glcm[r * GLCM_CLASS + e]++;
}
}
}
}
}
//对角方向
else if (angleDirection == GLCM_ANGLE_DIGONAL)
{
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
int ind = i*width + j;
if (klabels[ind] == l)
{
sum++;
r = histImage[i * width + j];
if (j + GLCM_DIS >= 0 && j + GLCM_DIS < width && i + GLCM_DIS >= 0 && i + GLCM_DIS < height)
{
e = histImage[(i + GLCM_DIS) * width + j + GLCM_DIS];
glcm[r * GLCM_CLASS + e]++;
}
if (j - GLCM_DIS >= 0 && j - GLCM_DIS < width && i - GLCM_DIS >= 0 && i - GLCM_DIS < height)
{
e = histImage[(i - GLCM_DIS) * width + j - GLCM_DIS];
glcm[r * GLCM_CLASS + e]++;
}
}
}
}
}
//归一化灰度共生矩阵
vector<float>glcmval(256, 0);
for (i = 0; i < 256; i++) { glcmval[i] = glcm[i] / (sum*2); }
//计算特征值
float entropy = 0, energy = 0, contrast = 0;
float homogenity = 0,homogenitytemp=0.0;
for (i = 0; i < GLCM_CLASS; i++)
{
for (j = 0; j < GLCM_CLASS; j++)
{
//熵
if (glcmval[i * GLCM_CLASS + j] > 0) { entropy = entropy - glcmval[i * GLCM_CLASS + j] * log(glcmval[i * GLCM_CLASS + j]); }
//能量
energy = energy + glcmval[i * GLCM_CLASS + j] * glcmval[i * GLCM_CLASS + j];
//对比度
contrast = contrast + (i - j) * (i - j) * glcmval[i * GLCM_CLASS + j]/256;
}
}
float u1 = 0, u2 = 0, o1 = 0, o2 = 0;
float u1temp = 0,u2temp=0,o1temp=0,o2temp=0;
for (i = 0; i < 16; i++)
{
u1 = u1 + i*u1temp;
for (j = 0; j < 16; j++)
{
u1temp = u1temp+glcmval[i * GLCM_CLASS + j];
}
}
for (j = 0; j < 16; j++)
{
u2 = u2 + j*u2temp;
for (i = 0; i< 16; i++)
{
u2temp = u2temp + glcmval[i * GLCM_CLASS + j];
}
}
for (i = 0; i < 16; i++)
{
o1 = o1 + (i-u1)*(i-u1)*u1temp;
for (j = 0; j < 16; j++)
{
o1temp = o1temp + glcmval[i * GLCM_CLASS + j];
}
}
o1 = sqrt(o1);
for (j = 0; j < 16; j++)
{
o2 = o2 + j*o2temp;
for (i = 0; i< 16; i++)
{
o2temp = o2temp + glcmval[i * GLCM_CLASS + j];
}
}
o2 = sqrt(o2);
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 16; j++)
{
homogenitytemp = homogenitytemp + (i - u1)*(j - u2)*glcmval[i * 16 + j];
}
}
if (o1*o2 == 0) { homogenity = 100.0; }
else{ homogenity = homogenitytemp / (o1*o2); }
featureVector[0] = entropy;
featureVector[1] = energy;
featureVector[2] = contrast;
featureVector[3] = homogenity;
delete[] glcm;
delete[] histImage;
return 0;
}
2.2灰度梯度共生矩阵
灰度梯度共生矩阵反映了图像中两种基本要素灰度和梯度(边缘)信息,有利于刻画图像较细的纹理,对旋转不敏感。图像的梯度图由灰度图经过Sobel算子滤波后得到。特征值包括:
//Sobel算子实现
int calSobel(Mat gray, vector<int>&sobel)
{
int i, j;
int width = gray.cols;
int height = gray.rows;
int sz = width*height;
if (gray.empty())
return 1;
for (i = 1; i < height-1; i++)
{
uchar*p = gray.ptr(i);
uchar*p1 = gray.ptr(i - 1);
uchar*p2 = gray.ptr(i + 1);
for (j = 1; j < width - 1; j++)
{
int gx = p2[j - 1] + 2 * p2[j] + p2[j + 1] - p1[j - 1] - 2 * p1[j] - p1[j + 1];
int gy = p1[j + 1] + 2 * p[j + 1] + p2[j + 1] - p1[j - 1] - 2 * p[j - 1] - p2[j - 1];
sobel[i*width + j] = round(sqrt(gx*gx + gy*gy));
}
}
return 0;
}
void calggfeature(Mat gray, vector<int>grayclass,vector<int> sobel, int*klabels, int l, float*T)
{
int height = gray.rows;
int width = gray.cols;
int sz = height*width;
int Ng = 16;
int Nh = 16;
//计算最大梯度 gm
int gm = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int ind = i*width + j;
if (sobel[ind]>gm) { gm = sobel[ind]; }
}
}
//归一化梯度向量G
float q = 0;
vector<int>G(sz, 0);
for (int i = 0; i < sz; i++)
{
if (klabels[i] == l)
{
G[i] = round(sobel[i] * Ng / gm) + 1;
if (G[i]>16){ G[i] = 16; }
q++;
}
}
//统计梯度-灰度共生向量gradient-grayval
vector<int>gradient_grayval(256, 0);
for (int i = 0; i < sz; i++)
{
int ind = (grayclass[i] - 1) * 16 + G[i] - 1;
if (ind >= 0)
{
if (klabels[i] == l)
{
gradient_grayval[ind] = gradient_grayval[ind] + 1;
}
}
}
//归一化梯度-灰度共生矩阵gradient-gray
vector<float>gradient_gray(256, 0);
for (int i = 0; i < 256; i++)
{
gradient_gray[i] = gradient_grayval[i]/ q;
}
//计算特征
float T1 = 0.0;
float T2 = 0.0;
float T3 = 0.0; float T3p = 0.0;
float T4 = 0.0; float T4p = 0.0;
float T5 = 0.0;
float T6 = 0.0; float T6p = 0.0;
float T7 = 0.0; float T7p = 0.0;
float T8 = 0.0; float T8p = 0.0;
float T9 = 0.0; float T9p = 0.0;
float T10 = 0.0; float T10p = 0.0;
float T11 = 0.0;
float T12 = 0.0;
float T13 = 0.0;
float T14 = 0.0;
float T15 = 0.0;
for (int i = 1; i < 17; i++)
{
T3 = T3 + T3p*T3p; //灰度分布不均匀性T3
T6 = T6 + i*T6p; //灰度均值 T6
if (T6p>0){ T11 = T11 - T6p*log(T6p); } //灰度熵 T11
T3p = 0.0; T6p = 0.0;
for (int j = 1; j < 17; j++)
{
T1 = T1 + gradient_gray[(i - 1)*16 + j - 1] / (j*j); //小梯度优势T1
T2 = T2 + gradient_gray[(i - 1)*16 + j - 1] * j*j; //大梯度优势T2
T3p = T3p + gradient_gray[(i - 1)*16 + j - 1];
T5 = T5 + gradient_gray[(i - 1)*16 + j - 1] * gradient_gray[(i - 1)*16 + j - 1]; //能量T5
T6p = T6p + gradient_gray[(i - 1)*16 + j - 1];
if (gradient_gray[(i - 1)*16 + j - 1]>0){ T13 = T13 - gradient_gray[(i - 1)*16 + j - 1] * log(gradient_gray[(i - 1)*16 + j - 1]); } //混合熵T13
T14 = T14 + (i - j)*gradient_gray[(i - 1)*16 + j - 1]; //差分矩T14
T15 = T15 + gradient_gray[(i - 1)*16 + j - 1] / (1 + (i - j)*(i - j)); //逆差分矩T15
}
}
for (int j = 1; j < 17; j++)
{
T4 = T4 + T4p*T4p; //梯度分布不均匀性T4
T7 = T7 + j*T7p; //梯度均值 T7
if (T7p>0){ T12 = T12 - T7p*log(T7p); } //梯度熵T12
T4p = 0.0; T7p = 0.0;
for (int i = 1; i < 17; i++)
{
T4p = T4p + gradient_gray[(i-1)*16 + j-1];
T7p = T7p + gradient_gray[(i-1)*16 + j-1];
}
}
for (int i = 1; i < 17; i++)
{
T8 = T8 + (i - T6)*(i - T6)*T8p;
T8p = 0.0;
for (int j = 1; j < 17; j++)
{
T8p = T8p + gradient_gray[(i-1)*Ng + j-1];
}
}
T8 = sqrt(T8); //灰度标准差T8
for (int j = 1; j < 17; j++)
{
T9 = T9 + (j - T7)*(j - T7)*T9p;
T9p = 0.0;
for (int i = 1; i < 17; i++)
{
T9p = T9p + gradient_gray[(i-1)*Ng + j-1];
}
}
T9 = sqrt(T9); //梯度标准差T9
for (int i = 1; i < 17; i++)
{
for (int j = 1; j < 17; j++)
{
T10p = T10p + (i - T6)*(j - T7)*gradient_gray[(i-1)*Ng + j-1];
}
}
if (T8*T9 == 0) { T10 = 100; }
else{ T10 = T10p / (T8*T9); } //相关性 T10
T[0] = T1;
T[1] = T2;
T[2] = T3;
T[3] = T4;
T[4] = T5;
T[5] = T6;
T[6] = T7;
T[7] = T8;
T[8] = T9;
T[9] = T10;
T[10] = T11;
T[11] = T12;
T[12] = T13;
T[13] = T14;
T[14] = T15;
}
2.3灰度平滑共生矩阵
灰度平滑共生矩阵用于描述频域中频率较低的部分,对应于较粗糙的纹理。通常使用3*3或5*5的Gaussian模板平滑处理图像。计算能量、相关、熵、对比度四个特征值描述矩阵。
void calgray_smooth(Mat gray, vector<int>grayclass, int*klabels, int l, float*GS)
{
int height = gray.rows;
int width = gray.cols;
int sz = height*width;
Mat Gaussian;
GaussianBlur(gray, Gaussian, Size(5, 5), 0, 0);
int M = 16;
//vectorgrayClass(sz, 0);
vector<int>GaussianClass(sz, 0);
vector<int>gray_smoothval(256, 0);
vector<float>gray_smooth(256, 0);
//原图计算区域最大灰度值 gm 平滑后图像最大灰度值 sm
//int gm = 0;
int sm = 0;
float z = 0;
for (int i = 0; i < height; i++)
{
uchar*q = Gaussian.ptr(i);
for (int j = 0; j < width; j++)
{
if (q[j]>sm) { sm = q[j]; }
}
}
//原图归一化灰度向量 grayClass 平滑后图像归一化灰度向量GaussianClass
for (int i = 0; i < height; i++)
{
uchar*q = Gaussian.ptr(i);
for (int j = 0; j < width; j++)
{
int ind = i*width + j;
GaussianClass[ind] = round(q[j]*M / sm) + 1;
if (GaussianClass[ind] > 16) { GaussianClass[ind] = 16; }
}
}
//统计灰度-平滑共生矩阵gray_smoothval
for (int i = 0; i < sz; i++)
{
if (klabels[i] == l)
{
int ind = (grayclass[i] - 1)*M + GaussianClass[i] - 1;
if (ind >= 0) { gray_smoothval[ind] = gray_smoothval[ind] + 1; }
z++;
}
}
//归一化灰度-平滑共生矩阵gray_smooth
for (int i = 0; i < 256; i++)
{
gray_smooth[i] = gray_smoothval[i]/ z;
}
//计算特征
float GS1 = 0.0; //熵
float GS2 = 0.0; //能量
float GS3 = 0.0; //对比度
float GS4 = 0.0, GS4temp = 0.0;; //相关
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 16; j++)
{
int ind = i * 16 + j;
if (gray_smooth[ind]>0){ GS1 = GS1 - gray_smooth[ind] * log(gray_smooth[ind]); }
GS2 = GS2 + gray_smooth[ind] * gray_smooth[ind];
GS3 = GS3 + (i - j)*(i - j)*gray_smooth[ind];
}
}
float u1 = 0.0, u2 = 0.0, o1 = 0.0, o2 = 0.0;
float u1temp = 0, u2temp = 0, o1temp = 0, o2temp = 0;
for (int i = 1; i < 17; i++)
{
u1 = u1 + i*u1temp;
for (int j = 1; j < 17; j++)
{
u1temp = u1temp + gray_smooth[(i-1) * 16 + j-1];
}
}
for (int j = 1; j < 17; j++)
{
u2 = u2 + j*u2temp;
for ( int i = 1; i< 17; i++)
{
u2temp = u2temp + gray_smooth[(i-1) * 16 + j-1];
}
}
for (int i = 1; i < 17; i++)
{
o1 = o1 + (i - u1)*(i - u1)*u1temp;
for (int j = 1; j < 17; j++)
{
o1temp = o1temp + gray_smooth[(i-1) * 16 + j-1];
}
}
o1 = sqrt(o1);
for (int j = 1; j < 17; j++)
{
o2 = o2 + j*o2temp;
for (int i = 1; i< 17; i++)
{
o2temp = o2temp + gray_smooth[(i-1) * 16 + j-1];
}
}
o2 = sqrt(o2);
for (int i = 1; i < 17; i++)
{
for (int j = 1; j < 17; j++)
{
GS4temp = GS4temp + (i - u1)*(j - u2)*gray_smooth[(i-1) * 16 + j-1];
}
}
if (o1*o2 == 0) { GS4 = 100; }
else{ GS4 = GS4temp / (o1*o2); }
GS[0] = GS1; //熵
GS[1] = GS2; //能量
GS[2] = GS3; //对比度
GS[3] = GS4; //相关
}
2.4灰度差分统计
图像中的点(x,y)对应点(x+x’,y+y’)的灰度差值,改变x’,y’的值统计不同方向,一般0,45,90,135四个方向,用于描述图像中能量的变换情况。特征:能量(二阶矩),熵,均值,对比度。
void calgraydifference(Mat gray, vector<int>grayclass, int* klabels, int l, float*GD)
{
int height = gray.rows;
int width = gray.cols;
int sz = height*width;
int i, j;
float z = 0;
//计算灰度差值向量
vector<int>graydval1(17, 0); //135
vector<int>graydval2(17, 0); //0
vector<int>graydval3(17, 0); //90
vector<int>graydval4(17, 0); //45
for (i = 1; i < height-1; i++)
{
for (j = 1; j < width-1; j++)
{
int ind = i*width + j;
if (klabels[ind] == l)
{
int ond1 = (i + 1)*width + j + 1;
int ond2 = (i - 1)*width + j;
int ond3 = i*width + j + 1;
int ond4 = (i - 1)*width + j + 1;
graydval1[abs(grayclass[ind] - grayclass[ond1]) ]++;
graydval2[abs(grayclass[ind] - grayclass[ond2]) ]++;
graydval3[abs(grayclass[ind] - grayclass[ond3]) ]++;
graydval4[abs(grayclass[ind] - grayclass[ond3]) ]++;
z++;
}
}
}
//归一化灰度差值向量
vector<float>grayd1(17, 0);
vector<float>grayd2(17, 0);
vector<float>grayd3(17, 0);
vector<float>grayd4(17, 0);
for (i = 0; i < 17; i++)
{
grayd1[i] = graydval1[i] / z;
grayd2[i] = graydval2[i] / z;
grayd3[i] = graydval3[i] / z;
grayd4[i] = graydval4[i] / z;
}
//计算特征值
float GD1 = 0.0, GD2 = 0.0, GD3 = 0.0, GD4 = 0.0;
float GD5 = 0.0, GD6 = 0.0, GD7 = 0.0, GD8 = 0.0;
float GD9 = 0.0, GD10 = 0.0, GD11 = 0.0, GD12 = 0.0;
float GD13 = 0.0, GD14 = 0.0, GD15 = 0.0, GD16 = 0.0;
for (i = 0; i < 17; i++)
{
GD1 = GD1 + i*i*grayd1[i]; //对比度
GD2 = GD2 + grayd1[i] * grayd1[i]; //角度方向二阶矩
if (grayd1[i]>0){ GD3 = GD3 - grayd1[i] * log(grayd1[i]); } //熵
GD4 = GD4 + i*grayd1[i]; //平均值
}
for (i = 0; i < 17; i++)
{
GD5 = GD5 + i*i*grayd2[i]; //对比度
GD6 = GD6 + grayd2[i] * grayd2[i]; //角度方向二阶矩
if (grayd2[i]>0){ GD7 = GD7 - grayd2[i] * log(grayd2[i]); } //熵
GD8 = GD8 + i*grayd2[i]; //平均值
}
for (i = 0; i < 17; i++)
{
GD9 = GD9 + i*i*grayd3[i]; //对比度
GD10 = GD10 + grayd3[i] * grayd3[i]; //角度方向二阶矩
if (grayd3[i]>0){ GD11 = GD11 - grayd3[i] * log(grayd3[i]); } //熵
GD12 = GD12 + i*grayd3[i]; //平均值
}
for (i = 0; i < 17; i++)
{
GD13 = GD13 + i*i*grayd4[i]; //对比度
GD14 = GD14 + grayd4[i] * grayd4[i]; //角度方向二阶矩
if (grayd4[i]>0){ GD15 = GD15 - grayd4[i] * log(grayd4[i]); } //熵
GD16 = GD16 + i*grayd4[i]; //平均值
}
GD[0] = GD1;//135 对比度
GD[1] = GD2;//135 角度方向二阶矩
GD[2] = GD3;//135 熵
GD[3] = GD4;//135 平均值
GD[4] = GD5;//0 对比度
GD[5] = GD6;//0 角度方向二阶矩
GD[6] = GD7;//0 熵
GD[7] = GD8;//0 平均值
GD[8] = GD9;//90 对比度
GD[9] = GD10;//90 角度方向二阶矩
GD[10] = GD11;//90 熵
GD[11] = GD12;//90 平均值
GD[12] = GD13;//45 对比度
GD[13] = GD14;//45 角度方向二阶矩
GD[14] = GD15;//45 熵
GD[15] = GD16;//45 平均值
}
2.5 灰度行程长度统计
统计沿着某一方向具有相同灰度值的像素点个数,0,45,90,135四个方向,归一化每个方向统计11个特征值,共计44个。
void calgrayrunlength(Mat gray, vector<int>grayclass, int*klabels, int l, float*GRL)
{
int height = gray.rows;
int width = gray.cols;
int sz = height*width;
float number = 0.0;
//确定各点四个方向的行程长度 并写入相应的runlength
vector<int>runlength0(sz, 0);
vector<int>runlength45(sz, 0);
vector<int>runlength90(sz, 0);
vector<int>runlength135(sz, 0);
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int ind = i*width + j;
if (klabels[ind] == l)
{
number++;
for (int p = 1; p < height; p++)
{
int ond = (i - p)*width + j;
if ((i - p) >= 0)
{
if ((klabels[ond] == l) && (grayclass[ind] == grayclass[ond])) { runlength0[ind]++; } //0 行程数
else { break; }
}
}
for (int q = 1; q < width; q++)
{
if ((j + q) < width)
{
int ond = i*width + j + q;
if ((klabels[ond] == l) && (grayclass[ind] == grayclass[ond])) { runlength90[ind]++; } //90 行程数
else{ break; }
}
}
for (int x = 1; x < min(height, width); x++)
{
if (((i - x) >= 0) && ((j + x) < width))
{
int ond = (i - x)*width + j + x;
if ((klabels[ond] == l) && (grayclass[ind] == grayclass[ond])) { runlength45[ind]++; } //45 行程数
else{ break; }
}
}
for (int y = 1; y < min(height, width); y++)
{
if (((i + y) < height) && ((j + y) < width))
{
int ond = (i + y)*width + j + y;
if ((klabels[ond] == l) && (grayclass[ind] == grayclass[ond])) { runlength135[ind]++; } //135 行程数
else{ break; }
}
}
}
}
}
//确定最大行程长度
int l1 = 0, l2 = 0, l3 = 0, l4 = 0;
for (int i = 0; i < sz; i++)
{
if (klabels[i] == l)
{
if (runlength0[i]>l1) { l1 = runlength0[i]; }
if (runlength45[i] > l2) { l2 = runlength45[i]; }
if (runlength90[i] > l3) { l3 = runlength90[i]; }
if (runlength135[i] > l4) { l4 = runlength135[i]; }
}
}
//统计灰度行程长度向量 grunlengthval
vector<int>grunlength0val(16*l1+16, 0);
vector<int>grunlength45val(16*l2+16, 0);
vector<int>grunlength90val(16*l3+16, 0);
vector<int>grunlength135val(16*l4+16, 0);
for (int i = 0; i < sz; i++)
{
if (klabels[i] == l)
{
int ind = (grayclass[i] - 1) * (l1 + 1) + runlength0[i];
grunlength0val[ind]++;
}
}
for (int i = 0; i < sz; i++)
{
if (klabels[i] == l)
{
int ind = (grayclass[i] - 1) * (l2 + 1) + runlength45[i];
grunlength45val[ind]++;
}
}
for (int i = 0; i < sz; i++)
{
if (klabels[i] == l)
{
int ind = (grayclass[i] - 1) * (l3 + 1) + runlength90[i];
grunlength90val[ind]++;
}
}
for (int i = 0; i < sz; i++)
{
if (klabels[i] == l)
{
int ind = (grayclass[i] - 1) * (l4 + 1) + runlength135[i];
grunlength135val[ind]++;
}
}
//归一化行程长度向量 grunlength
vector<float>grunlength0(16 * l1 + 16, 0);
vector<float>grunlength45(16 * l2 + 16, 0);
vector<float>grunlength90(16 * l3 + 16, 0);
vector<float>grunlength135(16 * l4 + 16, 0);
for (int i = 0; i < 16 * l1 + 16; i++) { grunlength0[i] = grunlength0val[i] / number; }
for (int i = 0; i < 16 * l2 + 16; i++) { grunlength45[i] = grunlength45val[i] / number; }
for (int i = 0; i < 16 * l3 + 16; i++) { grunlength90[i] = grunlength90val[i] / number; }
for (int i = 0; i < 16 * l4 + 16; i++) { grunlength135[i] = grunlength135val[i] / number; }
float GRL01 = 0.0, GRL02 = 0.0, GRL03 = 0.0, GRL03t = 0.0, GRL04 = 0.0, GRL04t = 0.0, GRL05 = 0.0, GRL05t1 = 0.0, GRL05t2 = 0.0, GRL06 = 0.0, GRL07 = 0.0, GRL08 = 0.0, GRL09 = 0.0, GRL010 = 0.0, GRL011 = 0.0;
float GRL451 = 0.0, GRL452 = 0.0, GRL453 = 0.0, GRL453t = 0.0, GRL454 = 0.0, GRL454t = 0.0, GRL455 = 0.0, GRL455t1 = 0.0, GRL455t2 = 0.0, GRL456 = 0.0, GRL457 = 0.0, GRL458 = 0.0, GRL459 = 0.0, GRL4510 = 0.0, GRL4511 = 0.0;
float GRL901 = 0.0, GRL902 = 0.0, GRL903 = 0.0, GRL903t = 0.0, GRL904 = 0.0, GRL904t = 0.0, GRL905 = 0.0, GRL905t1 = 0.0, GRL905t2 = 0.0, GRL906 = 0.0, GRL907 = 0.0, GRL908 = 0.0, GRL909 = 0.0, GRL9010 = 0.0, GRL9011 = 0.0;
float GRL1351 = 0.0, GRL1352 = 0.0, GRL1353 = 0.0, GRL1353t = 0.0, GRL1354 = 0.0, GRL1354t = 0.0, GRL1355 = 0.0, GRL1355t1 = 0.0, GRL1355t2 = 0.0, GRL1356 = 0.0, GRL1357 = 0.0, GRL1358 = 0.0, GRL1359 = 0.0, GRL13510 = 0.0, GRL13511 = 0.0;
//0
for (int i = 0; i < 16; i++)
{
GRL03 = GRL03 + GRL03t*GRL03t;
GRL03t = 0;
for (int j = 0; j < l1 + 1; j++)
{
int ind = i*(l1 + 1)+j;
GRL01 = GRL01 + grunlength0[ind] / (j + 1) / (j + 1);
GRL02 = GRL02 + grunlength0[ind] * j *j ;
GRL03t = GRL03t + grunlength0[ind];
GRL05t1 = GRL05t1 + j*grunlength0[ind];
GRL05t2 = GRL05t2 + grunlength0[ind];
GRL06 = GRL06 + grunlength0[ind] / (i + 1) / (i + 1)/(l1+1);
GRL07 = GRL07 + (i+1)*(i+1)*grunlength0[ind] / (l1 + 1);
GRL08 = GRL08 + grunlength0[ind] / ((i+1)*(i+1)*(j + 1)*(j + 1)*(l1 + 1));
GRL09 = GRL09 + grunlength0[ind] * (i+1)*(i+1) / (j + 1) / (j + 1) / (l1 + 1);
GRL010 = GRL010 + grunlength0[ind] * j*j / ((i + 1)*(i + 1)) / (l1 + 1);
GRL011 = GRL011 + grunlength0[ind] * (i+1)*(i+1)*j*j/(l1+1);
}
}
if (GRL05t1 == 0)
{
GRL05 = 200;
}
else
{
GRL05 = GRL05t2 / GRL05t1;
}
for (int j = 0; j < l1 + 1; j++)
{
GRL04 = GRL04 + GRL04t*GRL04t;
GRL04t = 0;
for (int i = 0; i < 16; i++)
{
GRL04t = GRL04t + grunlength0[i*(l1 + 1) + j];
}
}
//45
for (int i = 0; i < 16; i++)
{
GRL453 = GRL453 + GRL453t*GRL453t;
GRL453t = 0;
for (int j = 0; j < l2 + 1; j++)
{
int ind = i*(l2 + 1) + j;
GRL451 = GRL451 + grunlength45[ind] / (j + 1) / (j + 1);
GRL452 = GRL452 + grunlength45[ind] * j *j;
GRL453t = GRL453t + grunlength45[ind];
GRL455t1 = GRL455t1 + j*grunlength45[ind];
GRL455t2 = GRL455t2 + grunlength45[ind];
GRL456 = GRL456 + grunlength45[ind] / (i + 1) / (i + 1) / (l2 + 1);
GRL457 = GRL457 + (i+1)*(i+1)*grunlength45[ind] / (l2 + 1);
GRL458 = GRL458 + grunlength45[ind] / ((i + 1)*(i + 1)*(j + 1)*(j + 1)*(l2 + 1));
GRL459 = GRL459 + grunlength45[ind] * (i+1)*(i+1) / (j + 1) / (j + 1) / (l2 + 1);
GRL4510 = GRL4510 + grunlength45[ind] * j*j / ((i + 1)*(i + 1)) / (l2 + 1);
GRL4511 = GRL4511 + grunlength45[ind] * (i+1)*(i+1)*j*j / (l2 + 1);
}
}
if (GRL455t1 == 0)
{
GRL455 = 0;
}
else
{
GRL455 = GRL455t2 / GRL455t1;
}
for (int j = 0; j < l2 + 1; j++)
{
GRL454 = GRL454 + GRL454t*GRL454t;
GRL454t = 0;
for (int i = 0; i < 16; i++)
{
GRL454t = GRL454t + grunlength45[i*(l2 + 1) + j];
}
}
//90
for (int i = 0; i < 16; i++)
{
GRL903 = GRL903 + GRL903t*GRL903t;
GRL903t = 0;
for (int j = 0; j < l3 + 1; j++)
{
int ind = i*(l3 + 1) + j;
GRL901 = GRL901 + grunlength90[ind] / (j + 1) / (j + 1);
GRL902 = GRL902 + grunlength90[ind] * j *j;
GRL903t = GRL903t + grunlength90[ind];
GRL905t1 = GRL905t1 + j*grunlength90[ind];
GRL905t2 = GRL905t2 + grunlength90[ind];
GRL906 = GRL906 + grunlength90[ind] / (i + 1) / (i + 1) / (l3 + 1);
GRL907 = GRL907 + (i+1)*(i+1)*grunlength90[ind] / (l3 + 1);
GRL908 = GRL908 + grunlength90[ind] / ((i + 1)*(i + 1)*(j + 1)*(j + 1)*(l3 + 1));
GRL909 = GRL909 + grunlength90[ind] * (i+1)*(i+1) / (j + 1) / (j + 1) / (l3 + 1);
GRL9010 = GRL9010 + grunlength90[ind] * j*j / ((i + 1)*(i + 1)) / (l3 + 1);
GRL9011 = GRL9011 + grunlength90[ind] * (i+1)*(i+1)*j*j / (l3 + 1);
}
}
if (GRL905t1 == 0)
{
GRL905 = 200;
}
else
{
GRL905 = GRL905t2 / GRL905t1;
}
for (int j = 0; j < l3 + 1; j++)
{
GRL904 = GRL904 + GRL904t*GRL904t;
GRL904t = 0;
for (int i = 0; i < 16; i++)
{
GRL904t = GRL904t + grunlength90[i*(l3 + 1) + j];
}
}
//135
for (int i = 0; i < 16; i++)
{
GRL1353 = GRL1353 + GRL1353t*GRL1353t;
GRL1353t = 0;
for (int j = 0; j < l4 + 1; j++)
{
int ind = i*(l4 + 1) + j;
GRL1351 = GRL1351 + grunlength135[ind] / (j + 1) / (j + 1);
GRL1352 = GRL1352 + grunlength135[ind] * j *j;
GRL1353t = GRL1353t + grunlength135[ind];
GRL1355t1 = GRL1355t1 + j*grunlength135[ind];
GRL1355t2 = GRL1355t2 + grunlength135[ind];
GRL1356 = GRL1356 + grunlength135[ind] / (i + 1) / (i + 1) / (l4 + 1);
GRL1357 = GRL1357 + (i+1)*(i+1)*grunlength135[ind] / (l4 + 1);
GRL1358 = GRL1358 + grunlength135[ind] / ((i + 1)*(i + 1)*(j + 1)*(j + 1)*(l4 + 1));
GRL1359 = GRL1359 + grunlength135[ind] * (i+1)*(i+1) / (j + 1) / (j + 1) / (l4 + 1);
GRL13510 = GRL13510 + grunlength135[ind] * j*j / ((i + 1)*(i + 1)) / (l4 + 1);
GRL13511 = GRL13511 + grunlength135[ind] * (i+1)*(i+1)*j*j / (l4 + 1);
}
}
if (GRL1355t1 == 0)
{
GRL1355 = 200;
}
else
{
GRL1355 = GRL1355t2 / GRL1355t1;
}
for (int j = 0; j < l4 + 1; j++)
{
GRL1354 = GRL1354 + GRL1354t*GRL1354t;
GRL1354t = 0;
for (int i = 0; i < 16; i++)
{
GRL1354t = GRL1354t + grunlength135[i*(l4 + 1) + j];
}
}
GRL[0] = GRL01;
GRL[1] = GRL02;
GRL[2] = GRL03;
GRL[3] = GRL04;
GRL[4] = GRL05;
GRL[5] = GRL06;
GRL[6] = GRL07;
GRL[7] = GRL08;
GRL[8] = GRL09;
GRL[9] = GRL010;
GRL[10] = GRL011;
GRL[11] = GRL451;
GRL[12] = GRL452;
GRL[13] = GRL453;
GRL[14] = GRL454;
GRL[15] = GRL455;
GRL[16] = GRL456;
GRL[17] = GRL457;
GRL[18] = GRL458;
GRL[19] = GRL459;
GRL[20] = GRL4510;
GRL[21] = GRL4511;
GRL[22] = GRL901;
GRL[23] = GRL902;
GRL[24] = GRL903;
GRL[25] = GRL904;
GRL[26] = GRL905;
GRL[27] = GRL906;
GRL[28] = GRL907;
GRL[29] = GRL908;
GRL[30] = GRL909;
GRL[31] = GRL9010;
GRL[32] = GRL9011;
GRL[33] = GRL1351;
GRL[34] = GRL1352;
GRL[35] = GRL1353;
GRL[36] = GRL1354;
GRL[37] = GRL1355;
GRL[38] = GRL1356;
GRL[39] = GRL1357;
GRL[40] = GRL1358;
GRL[41] = GRL1359;
GRL[42] = GRL13510;
GRL[43] = GRL13511;
}
void LBP(Mat gray, int*klabels,int l,float& LBPvalue)
{
//计算LBP
for (int i = 1; i < gray.rows - 1; i++)
{
for (int j = 1; j < gray.cols - 1; j++)
{
uchar neighbor[8] = { 0 };
neighbor[0] = gray.at<uchar>(i - 1, j - 1);
neighbor[1] = gray.at<uchar>(i, j-1);
neighbor[2] = gray.at<uchar>(i+1, j - 1);
neighbor[3] = gray.at<uchar>(i+1, j);
neighbor[4] = gray.at<uchar>(i+1, j + 1);
neighbor[5] = gray.at<uchar>(i, j+1);
neighbor[6] = gray.at<uchar>(i-1, j+1);
neighbor[7] = gray.at<uchar>(i-1,j);
uchar center = gray.at<uchar>(i,j);
uchar temp = 0;
for (int k = 0; k < 8; k++)
{
temp += (neighbor[k] >= center)* (1 << k); // 计算LBP的值
}
gray.at<uchar>(i, j) = temp;
}
}
int q = 0, sumLBP = 0;
for (int i = 0; i < gray.rows; i++)
{
uchar*p = gray.ptr<uchar>(i);
for (int j = 0; j < gray.cols; j++)
{
int ind = i*gray.cols + j;
if (klabels[ind] == l)
{
sumLBP = sumLBP + p[j];
q++;
}
}
}
LBPvalue = sumLBP*1.0 / q;
}
Fast角点检测(Features from Accelerated Segment Test),定义为:若某点的圆形邻域圆周上有超过3/4的点与该点像素值不同,那么该点就认为是角点。Opencv更为极端,以该点为圆心半径为3的圆周上,计算上下左右四个点,若有三个与该点像素值不同,就认为该点为角点。
void FastDetection(Mat org, int width, int height,int*klabels,int l, int&numberofFast)
{
Mat pic;
cvtColor(org, pic, CV_RGB2GRAY);
vector keypoints(5000);
FAST(pic, keypoints, 50);
Point2f pt;
for (int i = 0; i < keypoints.size(); i++)
{
pt = keypoints[i].pt;
int ind = pt.y*width + pt.x - width;
if (klabels[ind] == l) { numberofFast++; }
}
vector (keypoints).swap(keypoints);
}