图像特征提取之LBP特征

来源:互联网 发布:考试经文知乎 编辑:程序博客网 时间:2024/05/29 09:55

局部二值模式(Loal Binary Pattern,LBP)是一种有效的纹理描述算子,它具有旋转不变性和灰度不变性等显著的优点,广泛应用于纹理分类、纹理分割、

人脸图像分析等领域。  

LBP特征的描述原始的LBP算子定义在3*3的窗口内,以窗口中心的像素值为阈值,将周围相邻的8个像素值

与之比较,若周围像素值大于该中心值,则标记为1,否则标记为0。这样,在该点就能产生8位二进制值(通常转换为

十进制,即LBP码0~255),即得到该窗口中心点的LBP值,它描述了该图像局部的纹理信息。如下图所示:

LBP的改进版本:基本的LBP算子的最大缺陷在于它只覆盖了一个固定半径范围内的小区域,这显然不能满足

不同尺寸和频率纹理的需要。为了适应不同尺度的纹理特征,并达到灰度和旋转不变性的要求,随后,Ojala等人

对LBP算子进行了发展和改进,将3*3邻域扩展到任意邻域,并用圆形邻域代替了正方形邻域,改进后的LBP算子

允许在半径为R的圆形邻域内有任意多个像素点。从而得到了半径为R采样点数为P的LBP算子:

在OpenCV中的LBP算子这样处理这种情况:对于一个点它的近邻点可以用以下公式计算:

        就算得到的结果不是整数(不是像素坐标值),也可以通过双线性差值法进行近似处理:

       下面是从OpenCV中摘录的LBP算法实现代码,具体在 opencv\sources\modules\contrib\src\facerec.cpp下:

template <typename _Tp> staticvoid olbp_(InputArray _src, OutputArray _dst) {    // get matrices    Mat src = _src.getMat();    // allocate memory for result    _dst.create(src.rows-2, src.cols-2, CV_8UC1);    Mat dst = _dst.getMat();    // zero the result matrix    dst.setTo(0);    // calculate patterns    for(int i=1;i<src.rows-1;i++) {        for(int j=1;j<src.cols-1;j++) {            _Tp center = src.at<_Tp>(i,j);            unsigned char code = 0;            code |= (src.at<_Tp>(i-1,j-1) >= center) << 7;            code |= (src.at<_Tp>(i-1,j) >= center) << 6;            code |= (src.at<_Tp>(i-1,j+1) >= center) << 5;            code |= (src.at<_Tp>(i,j+1) >= center) << 4;            code |= (src.at<_Tp>(i+1,j+1) >= center) << 3;            code |= (src.at<_Tp>(i+1,j) >= center) << 2;            code |= (src.at<_Tp>(i+1,j-1) >= center) << 1;            code |= (src.at<_Tp>(i,j-1) >= center) << 0;            dst.at<unsigned char>(i-1,j-1) = code;        }    }}//------------------------------------------------------------------------------// cv::elbp//------------------------------------------------------------------------------template <typename _Tp> staticinline void elbp_(InputArray _src, OutputArray _dst, int radius, int neighbors) {    //get matrices    Mat src = _src.getMat();    // allocate memory for result    _dst.create(src.rows-2*radius, src.cols-2*radius, CV_32SC1);    Mat dst = _dst.getMat();    // zero    dst.setTo(0);    for(int n=0; n<neighbors; n++) {        // sample points        float x = static_cast<float>(radius * cos(2.0*CV_PI*n/static_cast<float>(neighbors)));        float y = static_cast<float>(-radius * sin(2.0*CV_PI*n/static_cast<float>(neighbors)));        // relative indices        int fx = static_cast<int>(floor(x));        int fy = static_cast<int>(floor(y));        int cx = static_cast<int>(ceil(x));        int cy = static_cast<int>(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 < src.rows-radius;i++) {            for(int j=radius;j < src.cols-radius;j++) {                // calculate interpolated value                float t = static_cast<float>(w1*src.at<_Tp>(i+fy,j+fx) + w2*src.at<_Tp>(i+fy,j+cx) + w3*src.at<_Tp>(i+cy,j+fx) + w4*src.at<_Tp>(i+cy,j+cx));                // floating point precision, so check some machine-dependent epsilon                dst.at<int>(i-radius,j-radius) += ((t > src.at<_Tp>(i,j)) || (std::abs(t-src.at<_Tp>(i,j)) < std::numeric_limits<float>::epsilon())) << n;            }        }    }}static void elbp(InputArray src, OutputArray dst, int radius, int neighbors){    int type = src.type();    switch (type) {    case CV_8SC1:   elbp_<char>(src,dst, radius, neighbors); break;    case CV_8UC1:   elbp_<unsigned char>(src, dst, radius, neighbors); break;    case CV_16SC1:  elbp_<short>(src,dst, radius, neighbors); break;    case CV_16UC1:  elbp_<unsigned short>(src,dst, radius, neighbors); break;    case CV_32SC1:  elbp_<int>(src,dst, radius, neighbors); break;    case CV_32FC1:  elbp_<float>(src,dst, radius, neighbors); break;    case CV_64FC1:  elbp_<double>(src,dst, radius, neighbors); break;    default:        string error_msg = format("Using Original Local Binary Patterns for feature extraction only works on single-channel images (given %d). Please pass the image data as a grayscale image!", type);        CV_Error(CV_StsNotImplemented, error_msg);        break;    }}


下面是我用上述代码跑出来的结果:


      


原创粉丝点击