• OpenCV学习(39) OpenCV中的LBP图像


    本章我们学习LBP图像的原理和使用,因为接下来教程我们要使用LBP图像的直方图来进行脸部识别。

    参考资料:

    http://docs.opencv.org/modules/contrib/doc/facerec/facerec_tutorial.html

    http://www.cnblogs.com/mikewolf2002/p/3438166.html

          LBP的基本思想是以图像中某个像素为中心,对相邻像素进行阈值比较。如果中心像素的亮度大于等于它的相邻像素,把相邻像素标记为1,否则标记为0。我们可以用二进制数字来表示LBP图中的每个像素的LBP编码,比如下图中的中心像素,它的LBP编码为:00010011,其十进制值为19。

    image

    用公式表示就是:

    image

    其中(xc,yc)是中心像素,ic是灰度值,in是相邻像素的灰度值,s是一个符号函数:

    image

    在OpenCV的LBP算法中,使用圆形的LBP算子:

     

    对于一个点image, 它的近邻点 image用以下公式计算:

    image

    其中R是半径,p是样本点的个数。

    如果就算的结果不在像素坐标上,我们则使用双线性插值进行近似处理。

    image

    下面的代码中,我们分别实现了通常LBP图和圆形算子LBP图。

          elbp是圆形算子LBP函数,elbp1是通常LBP图,我们分别对lena的图像进行了处理,结果如下所示,从途中可以看出来,使用圆形算子的效果锐度更强。

    #include "opencv2/core/core.hpp"
    #include "opencv2/contrib/contrib.hpp"
    #include "opencv2/highgui/highgui.hpp"

    #include <iostream>
    #include <fstream>
    #include <sstream>

    using namespace cv;
    using namespace std;

    void elbp(Mat& src, Mat &dst, int radius, int neighbors)
    {

    for(int n=0; n<neighbors; n++)
    {
    // 采样点的计算
    float x = static_cast<float>(-radius * sin(2.0*CV_PI*n/static_cast<float>(neighbors)));
    float y = static_cast<float>(radius * cos(2.0*CV_PI*n/static_cast<float>(neighbors)));
    // 上取整和下取整的值
    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));
    // 小数部分
    float ty = y - fy;
    float tx = x - fx;
    // 设置插值权重
    float w1 = (1 - tx) * (1 - ty);
    float w2 = tx * (1 - ty);
    float w3 = (1 - tx) * ty;
    float w4 = tx * ty;
    // 循环处理图像数据
    for(int i=radius; i < src.rows-radius;i++)
    {
    for(int j=radius;j < src.cols-radius;j++)
    {
    // 计算插值
    float t = static_cast<float>(w1*src.at<uchar>(i+fy,j+fx) + w2*src.at<uchar>(i+fy,j+cx) + w3*src.at<uchar>(i+cy,j+fx) + w4*src.at<uchar>(i+cy,j+cx));
    // 进行编码
    dst.at<uchar>(i-radius,j-radius) += ((t > src.at<uchar>(i,j)) || (std::abs(t-src.at<uchar>(i,j)) < std::numeric_limits<float>::epsilon())) << n;
    }
    }
    }
    }

    void elbp1(Mat& src, Mat &dst)
    {

    // 循环处理图像数据
    for(int i=1; i < src.rows-1;i++)
    {
    for(int j=1;j < src.cols-1;j++)
    {
    uchar tt = 0;
    int tt1 = 0;
    uchar u = src.at<uchar>(i,j);
    if(src.at<uchar>(i-1,j-1)>u) { tt += 1 <<tt1; }
    tt1++;
    if(src.at<uchar>(i-1,j)>u) { tt += 1 <<tt1; }
    tt1++;
    if(src.at<uchar>(i-1,j+1)>u) { tt += 1 <<tt1; }
    tt1++;
    if(src.at<uchar>(i,j+1)>u) { tt += 1 <<tt1; }
    tt1++;
    if(src.at<uchar>(i+1,j+1)>u) { tt += 1 <<tt1; }
    tt1++;
    if(src.at<uchar>(i+1,j)>u) { tt += 1 <<tt1; }
    tt1++;
    if(src.at<uchar>(i+1,j-1)>u) { tt += 1 <<tt1; }
    tt1++;
    if(src.at<uchar>(i-1,j)>u) { tt += 1 <<tt1; }
    tt1++;

    dst.at<uchar>(i-1,j-1) = tt;
    }
    }
    }

    int main()
    {
    Mat img = cv::imread("../lenna.jpg", 0);
    namedWindow("image");
    imshow("image", img);

    int radius, neighbors;
    radius = 1;
    neighbors = 8;

    //创建一个LBP
    //注意为了溢出,我们行列都在原有图像上减去2个半径
    Mat dst = Mat(img.rows-2*radius, img.cols-2*radius,CV_8UC1, Scalar(0));
    elbp1(img,dst);
    namedWindow("normal");
    imshow("normal", dst);

    Mat dst1 = Mat(img.rows-2*radius, img.cols-2*radius,CV_8UC1, Scalar(0));
    elbp(img,dst1,1,8);
    namedWindow("circle");
    imshow("circle", dst1);

    while(1)
    cv::waitKey(0);
    }

    imageimageimage

    我们换另外一张图,该图包括不同光照下的四副照片,再来看看LBP图的效果:

    image

    image

    image

     

     

    程序代码:

    FirstOpenCV36

  • 相关阅读:
    话说Hibernate和ADO.NET —练习随笔小记
    二次开发WinWebMail邮件系统接口 企业邮件服务器解决方案
    一个Windows后台服务(.Net的C#版) 定时访问数据库循环发送手机短信
    SQL UPDATE 联合表更新的问题
    2009新的篇章,惠海→时代财富→广佛都市网
    在WebService中使用Session或Cookie实现WebService身份验证(客户端是Flex)
    门户网站的形成—CMS内容管理系统
    CSS实现0.5px的边框或线
    《后人诗》
    CentOS6下docker的安装和使用
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/3438698.html
Copyright © 2020-2023  润新知