OpenCV學習(39) OpenCV中的LBP圖像

本章咱們學習LBP圖像的原理和使用,由於接下來教程咱們要使用LBP圖像的直方圖來進行臉部識別。html

參考資料:ios

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

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

      LBP的基本思想是以圖像中某個像素爲中心,對相鄰像素進行閾值比較。若是中心像素的亮度大於等於它的相鄰像素,把相鄰像素標記爲1,不然標記爲0。咱們能夠用二進制數字來表示LBP圖中的每一個像素的LBP編碼,好比下圖中的中心像素,它的LBP編碼爲:00010011,其十進制值爲19。函數

image

用公式表示就是:學習

image

其中(xc,yc)是中心像素,ic是灰度值,in是相鄰像素的灰度值,s是一個符號函數:ui

image

在OpenCV的LBP算法中,使用圓形的LBP算子:編碼

 

對於一個點image, 它的近鄰點 image用如下公式計算:spa

image

其中R是半徑,p是樣本點的個數。3d

若是就算的結果不在像素座標上,咱們則使用雙線性插值進行近似處理。

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

相關文章
相關標籤/搜索