本章我们学习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。

用公式表示就是:

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

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

 

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

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

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

下面的代码中,我们分别实现了通常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);
}

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

 

 

程序代码:

FirstOpenCV36

OpenCV学习(39) OpenCV中的LBP图像的更多相关文章

  1. OpenCV学习(22) opencv中使用kmeans算法

    kmeans算法的原理参考:http://www.cnblogs.com/mikewolf2002/p/3368118.html 下面学习一下opencv中kmeans函数的使用.      首先我们 ...

  2. OpenCV学习笔记:resize函数改变图像的大小

    OpenCV提供了resize函数来改变图像的大小,函数原型如下: , , int interpolation=INTER_LINEAR ); 参数解释: src:输入,原图像,即待改变大小的图像: ...

  3. OpenCV学习笔记——OpenCV安装

    关于OpenCV安装 1.下载和安装OpenCV SDK 在官网:http://opencv.org/上找到OpenCV windows版下载 . 后得到一个 opencv-2.X.X.exe的文件, ...

  4. OpenCV学习2-----使用inpaint函数进行图像修复

    安装opencv时,在opencv的安装路径下, sources\samples\cpp\  路径里面提供了好多经典的例子,很值得学习. 这次的例子是利用inpaint函数进行图像修复. CV_EXP ...

  5. OpenCV学习(35) OpenCV中的PCA算法

    PCA算法的基本原理可以参考:http://www.cnblogs.com/mikewolf2002/p/3429711.html     对一副宽p.高q的二维灰度图,要完整表示该图像,需要m = ...

  6. 【OpenCV学习笔记】之六 手写图像旋转函数---万丈高楼平地起

    话说,平凡之处显真格,这一点也没错!  比如,对旋转图像进行双线性插值,很简单吧?  可,对我,折腾了大半天,也没有达到预期效果!  尤其是三个误区让我抓瞎好久: 1,坐标旋转公式.   这东西,要用 ...

  7. opencv学习笔记(03)——遍历图像(迭代器法)

    #include <opencv2\highgui\highgui.hpp> #include <opencv2\imgproc\imgproc.hpp> #include & ...

  8. opencv学习笔记(01)——操作图像的像素

    #include <opencv2\core\core.hpp> #include <opencv2\highgui\highgui.hpp> #include <ope ...

  9. opencv学习笔记(02)——遍历图像(指针法)

    #include <opencv2\core\core.hpp> #include <opencv2\highgui\highgui.hpp> #include <ope ...

随机推荐

  1. 全文搜索引擎 Elasticsearch (二) 使用场景

    1.场景—:使用Elasticsearch作为主要的后端 传统项目中,搜索引擎是部署在成熟的数据存储的顶部,以提供快速且相关的搜索能力.这是因为早期的搜索引擎不能提供耐用的​​存储或其他经常需要的功能 ...

  2. mysql 存储过程详解

    MySQL 存储过程是从 MySQL 5.0 开始增加的新功能.存储过程的优点有一箩筐.不过最主要的还是执行效率和SQL 代码封装.特别是 SQL 代码封装功能,如果没有存储过程,在外部程序访问数据库 ...

  3. thinkphp结合ajax实现统计页面pv的浏览量

    统计pv量很常用,下面的代码用ajax实现的,使用ajax可以避免页面缓存造成的影响,只要客户端的js代码执行了就可以统计流量. 一共就两部 将下面代码放在要统计的html页面中,测试时把地址换成自己 ...

  4. java 代理设计模式

    首先代理(deleration)是什么,在日常生活中我们有很多这种的例子,比如你上个QQ,各种空间被什么代理刷屏,对的,代理不是生产产品的商家,也不是进购产品的卖家,他们只是帮别人卖东西,这就相当于一 ...

  5. python入门4(冒泡排序)

    在学习了最基本的python语法后,我们来实践一个最简单的冒泡排序,检验一下自己是否入门. def bubble_sort(lists): # 冒泡排序 count = len(lists) for ...

  6. Python 学习经历分享

    如果说 Java 是亲儿子的话,那么 Python 应该就是干儿子了.看了一下所有关于 Python 的笔记,我发现原来我在 4 月份的时候就已经涉足 Python 了,但是到目前为止才真正算做出了一 ...

  7. Python中 *args 和 **kwargs 的区别

    先来看个例子: def foo(*args, **kwargs): print 'args = ', args print 'kwargs = ', kwargs print '----------- ...

  8. django定时任务

    1.celery流程图: Celery的架构由三部分组成,消息中间件(message broker),任务执行单元(worker)和任务执行结果存储(task result store)组成 2.使用 ...

  9. 洛谷.2619.[国家集训队2]Tree I(带权二分 Kruskal)

    题目链接 \(Description\) 给定一个无向带权连通图,每条边是黑色或白色.求一棵最小权的恰好有K条白边的生成树. \(Solution\) Kruskal是选取最小的n-1条边.而白边数有 ...

  10. [BZOJ2669] [cqoi2012]局部极小值

    [BZOJ2669] [cqoi2012]局部极小值 Description 有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次.如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点) ...