纹理特征提取(1):LBP

最近在处理图片分类,想用纹理特征作输入。关于这方面的整理已经有很多,不过还是系统列一下,会掌握深刻一点。

LBP(Local Binary Patterns):

基本算法就是,对于一个像素值的邻域上的值,比中心像素值小的,置0;比中心像素值大的,置1.这样再根据邻域的0、1值,生成二进制数。这样我们最后会得到一张纹理图。但往往不直接用这张图片作为训练输入,而是使用灰度直方图。统计每个灰度的值之后,用统计后的图作为输入。在实现上,还会将纹理图分成不同的grid,对每一个grid进行统计。假如x、y方向分了3、4份,则有12份grids。假如灰度值有256个,则最后统计的直方图大小为12*256(rows*cols)。

实现时往往使用圆形邻域。但圆形邻域的像素位置上可能并没有像素值,因此需要用到双线性插值计算。代码:

// 圆形邻域LBP
Mat Pre::circleNeighbor() {
    Mat result;
    result.create(img.rows - radius * 2, img.cols - radius * 2, img.type());
    result.setTo(0);

    for (int n = 0; n(radius * cos(2.0*CV_PI*n / static_cast(neighbors)));//这一步没有细看 找采样点坐标
        float y = static_cast(-radius * sin(2.0*CV_PI*n / static_cast(neighbors)));
        // relative indices 下面是双线性插值操作
        int fx = static_cast(floor(x));
        int fy = static_cast(floor(y));
        int cx = static_cast(ceil(x));
        int cy = static_cast(ceil(y));
        // fractional part
        float ty = y - fy;
        float tx = x - fx;
        // set interpolation weights
        float w1 = (1 - tx) * (1 - ty);
        float w2 = tx  * (1 - ty);
        float w3 = (1 - tx) *      ty;
        float w4 = tx  *      ty;
        // iterate through your data
        for (int i = radius; i < img.rows - radius; i++)
        {
            for (int j = radius; j < img.cols - radius; j++)
            {
                // calculate interpolated value
                float t = static_cast(w1*img.at(i + fy, j + fx) + \
                w2*img.at(i + fy, j + cx) + \
                w3*img.at(i + cy, j + fx) + \
                w4*img.at(i + cy, j + cx));
                // floating point precision, so check some machine-dependent epsilon
                result.at(i - radius, j - radius) += \
                ((t > img.at(i, j)) || (std::abs(t - img.at(i, j)) < std::numeric_limits::epsilon())) << n;
            }
        }
    }
    return result;
}


很明显,这并不是旋转不变的。如果是旋转不变LBP,则在代码实现上:将二进制数循环右移(>>),得到最小值作为中心像素值。代码:

// 将圆形邻域LBP应用到旋转不变
void Pre::RILBP() {
    imgLbp = circleNeighbor();

    int val=0, temp=0;
    numPatterns = pow(2, neighbors);//灰度值的个数,与邻域中采样点的个数有关,8则为256
    uchar RITable[numPatterns];
    for (int i = 0; i> 1;//循环右移,直到找到最小值
            if (val>temp)
            {
                val = temp;
            }
        }
        RITable[i] = val;//将新的LBP存在一个数组里面
    }

    for (int i = 1; i(i, j) = RITable[imgLbp.at(i, j)];
        }
    }
    return;
}

另外,还有等价模式LBP。由于8位二进制的灰度值数量都能达到256,实在是太多了。用等价模式,可以降低到58种。算法是计算跳变次数,包括从最后一位到第一位。两次以内,算作一种模式,总共有P(P-1)+
2种,P为采样点数。为什么是这个式子呢?

“Ojala等认为,在实际图像中,绝大多数LBP模式最多只包含两次从10或从01的跳变。因此,Ojala将“等价模式”定义为:当某个LBP所对应的循环二进制数从01或从10最多有两次跳变时,该LBP所对应的二进制就称为一个等价模式类。000000000次跳变),00000111(含一次从01的跳变,由于循环的关系最后一位从1跳到0又是一次跳变)10001111(先由1跳到0,再由0跳到1,共两次跳变)都是等价模式类。除等价模式类以外的模式都归为另一类,称为混合模式类,例如10010111(共四次跳变)”。


你可能感兴趣的:(DIP,DIP-文档识别)