图像显著性区域提取[2]-特征提取

1.颜色特征

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.纹理特征

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算子滤波后得到。特征值包括:
图像显著性区域提取[2]-特征提取_第1张图片

//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个。
图像显著性区域提取[2]-特征提取_第2张图片

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;

}

2.6 LBP灰度特征
图像显著性区域提取[2]-特征提取_第3张图片

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;
}

3.角点

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);
}

你可能感兴趣的:(图像显著性区域提取[2]-特征提取)