本章我们学习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
时间: 2024-07-30 01:00:11