opencv_C++ LBP( Local Binary Patterns, 局部模式特征) 特征示例
理解LBP之前要先了解:
LBP的原理:https://blog.****.net/xidianzhimeng/article/details/19634573
双线性插值:https://blog.****.net/lxlclzy1130/article/details/50922867
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
#define WINDOW_NAME "ELBP"
Mat g_srcImage, g_grayImage;
int g_nRadius = 3, g_nMaxRadius = 30;
void normalLBP()
{
g_srcImage = imread("chepai.jpg");
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
int width = g_grayImage.cols;
int height = g_grayImage.rows;
// 基本LBP
Mat lbpImage = Mat::zeros(height - 2, width - 2, CV_8UC1);
uchar center;
for (size_t row = 1; row < height - 1; row++)
{
for (size_t col = 1; col < width - 1; col++)
{
center = g_grayImage.at<uchar>(row, col);
uchar code = 0;
code |= (g_grayImage.at<uchar>(row - 1, col - 1) > center) << 7;
code |= (g_grayImage.at<uchar>(row - 1, col) > center) << 6;
code |= (g_grayImage.at<uchar>(row - 1, col + 1) > center) << 5;
code |= (g_grayImage.at<uchar>(row, col + 1) > center) << 4;
code |= (g_grayImage.at<uchar>(row + 1, col + 1) > center) << 3;
code |= (g_grayImage.at<uchar>(row + 1, col) > center) << 2;
code |= (g_grayImage.at<uchar>(row + 1, col - 1) > center) << 1;
code |= (g_grayImage.at<uchar>(row, col - 1) > center) << 0;
lbpImage.at<uchar>(row - 1, col - 1) = code;
}
}
imshow("basic LBP", lbpImage);
}
void on_fOnChange_ELBP(int, void*)
{
int offset = g_nRadius * 2;
Mat elbpImage = Mat::zeros(g_grayImage.rows - offset, g_grayImage.cols - offset, CV_8UC1);
int width = g_grayImage.cols;
int height = g_grayImage.rows;
int numNeighbors = 8;
for (size_t n = 0; n < numNeighbors; n++)
{
float x = static_cast<float>(g_nRadius) * cos(2.0 * CV_PI * n / static_cast<float>(numNeighbors));
float y = static_cast<float>(g_nRadius) * -sin(2.0 * CV_PI * n / static_cast<float>(numNeighbors));
int fx = static_cast<int>(floor(x));
int fy = static_cast<int>(floor(x));
int cx = static_cast<int>(ceil(x));
int cy = static_cast<int>(ceil(x));
// U V
float tx = x - fx;
float ty = y - fy;
// 权重
float w1 = (1 - tx) * (1-ty);
float w2 = tx * (1-ty);
float w3 = (1 - tx) * ty;
float w4 = tx * ty;
for (size_t row = g_nRadius; row < height - g_nRadius; row++)
{
for (size_t col = g_nRadius; col < width - g_nRadius; col++)
{
float t = w1 * g_grayImage.at<uchar>(row + fy, col + fx) + w2 * g_grayImage.at<uchar>(row + fy, col + cx)\
+ w3 * g_grayImage.at<uchar>(row + cy, col + fx) + w4 * g_grayImage.at<uchar>(row + cy, col + cx);
// 可以错误矫正,不加也没多大影响(abs(t - gray_src.at<uchar>(row, col)) > std::numeric_limits<float>::epsilon()))
elbpImage.at<uchar>(row - g_nRadius, col - g_nRadius) += ( (t > g_grayImage.at<uchar>(row, col)) \
&& (abs(t - g_grayImage.at<uchar>(row, col)) > std::numeric_limits<float>::epsilon()) ) << n;
}
}
}
imshow(WINDOW_NAME, elbpImage);
}
int main()
{
normalLBP();
// ELBP
namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE);
createTrackbar("ELBP radius: ", WINDOW_NAME, &g_nRadius, g_nMaxRadius, on_fOnChange_ELBP);
on_fOnChange_ELBP(0, NULL);
waitKey(0);
return 0;
}
运行结果: