您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# C++ OpenCV中如何实现扩展LBP特征提取
## 1. LBP特征基础概念
### 1.1 LBP特征简介
局部二值模式(Local Binary Pattern, LBP)是一种用于图像局部纹理分析的特征描述子。由T. Ojala等人在1994年首次提出,因其计算简单、对光照变化不敏感等优点,被广泛应用于人脸识别、纹理分类等领域。
基本LBP算子工作原理:
1. 以中心像素为阈值
2. 将3×3邻域内像素值与之比较
3. 大于等于阈值的置1,否则置0
4. 按固定顺序排列二进制位形成特征值
### 1.2 基本LBP的数学表达
对于中心点$(x_c,y_c)$,其LBP值可表示为:
$$
LBP(x_c,y_c) = \sum_{p=0}^{7} s(g_p - g_c) \times 2^p
$$
其中$s(x)$为符号函数:
$$
s(x) =
\begin{cases}
1, & x \geq 0 \\
0, & x < 0
\end{cases}
$$
## 2. OpenCV中的LBP实现
### 2.1 基本LBP实现
```cpp
#include <opencv2/opencv.hpp>
cv::Mat computeLBP(const cv::Mat &src) {
CV_Assert(src.type() == CV_8UC1);
cv::Mat dst = cv::Mat::zeros(src.size(), src.type());
for(int i=1; i<src.rows-1; i++) {
for(int j=1; j<src.cols-1; j++) {
uchar center = src.at<uchar>(i,j);
uchar code = 0;
code |= (src.at<uchar>(i-1,j-1) >= center) << 7;
code |= (src.at<uchar>(i-1,j ) >= center) << 6;
code |= (src.at<uchar>(i-1,j+1) >= center) << 5;
code |= (src.at<uchar>(i ,j+1) >= center) << 4;
code |= (src.at<uchar>(i+1,j+1) >= center) << 3;
code |= (src.at<uchar>(i+1,j ) >= center) << 2;
code |= (src.at<uchar>(i+1,j-1) >= center) << 1;
code |= (src.at<uchar>(i ,j-1) >= center) << 0;
dst.at<uchar>(i,j) = code;
}
}
return dst;
}
基本LBP的3×3邻域限制了特征尺度。圆形LBP(Circular LBP)通过以下改进:
cv::Mat circularLBP(const cv::Mat &src, int radius=1, int neighbors=8) {
CV_Assert(src.type() == CV_8UC1);
cv::Mat dst = cv::Mat::zeros(src.size(), src.type());
for(int n=0; n<neighbors; n++) {
// 计算采样点坐标
float x = radius * cos(2.0*CV_PI*n/neighbors);
float y = radius * sin(2.0*CV_PI*n/neighbors);
// 整数和小数部分
int fx = floor(x);
int fy = floor(y);
int cx = ceil(x);
int cy = 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 = 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,j) |= ((t > src.at<uchar>(i,j)) << n);
}
}
}
return dst;
}
为解决旋转带来的特征变化,定义旋转不变LBP:
\[ LBP^{ri}_{P,R} = \min\{ ROR(LBP_{P,R}, i) | i=0,1,...,P-1 \} \]
实现代码:
uchar rotateMin(uchar val, int neighbors) {
uchar minVal = val;
uchar temp = val;
for(int i=0; i<neighbors; i++) {
// 循环右移
uchar lsb = temp & 1;
temp = temp >> 1;
temp |= (lsb << (neighbors-1));
if(temp < minVal) {
minVal = temp;
}
}
return minVal;
}
cv::Mat rotationInvariantLBP(const cv::Mat &src, int radius=1, int neighbors=8) {
cv::Mat lbp = circularLBP(src, radius, neighbors);
cv::Mat dst = cv::Mat::zeros(src.size(), src.type());
for(int i=0; i<lbp.rows; i++) {
for(int j=0; j<lbp.cols; j++) {
dst.at<uchar>(i,j) = rotateMin(lbp.at<uchar>(i,j), neighbors);
}
}
return dst;
}
定义均匀模式(Uniform Pattern)为二进制序列跳变不超过2次:
\[ U(LBP_{P,R}) = |s(g_{P-1}-g_c)-s(g_0-g_c)| + \sum_{p=1}^{P-1}|s(g_p-g_c)-s(g_{p-1}-g_c)| \]
实现代码:
int getUniformPattern(uchar val, int neighbors) {
int count = 0;
uchar last = val & 1;
for(int i=1; i<=neighbors; i++) {
uchar current = (val >> i) & 1;
if(current != last) {
count++;
last = current;
}
if(count > 2) {
return neighbors + 1; // 非均匀模式
}
}
return count;
}
cv::Mat uniformLBP(const cv::Mat &src, int radius=1, int neighbors=8) {
cv::Mat lbp = circularLBP(src, radius, neighbors);
cv::Mat dst = cv::Mat::zeros(src.size(), src.type());
// 预先计算均匀模式映射表
uchar table[256];
for(int i=0; i<256; i++) {
table[i] = getUniformPattern(i, neighbors) <= 2 ? i : neighbors+1;
}
for(int i=0; i<lbp.rows; i++) {
for(int j=0; j<lbp.cols; j++) {
dst.at<uchar>(i,j) = table[lbp.at<uchar>(i,j)];
}
}
return dst;
}
cv::Mat multiScaleLBP(const cv::Mat &src,
const std::vector<int> &radii = {1,2,3},
const std::vector<int> &neighbors = {8,16,24}) {
CV_Assert(radii.size() == neighbors.size());
std::vector<cv::Mat> lbpFeatures;
for(size_t i=0; i<radii.size(); i++) {
lbpFeatures.push_back(uniformLBP(src, radii[i], neighbors[i]));
}
// 特征拼接
cv::Mat combined;
cv::hconcat(lbpFeatures, combined);
return combined;
}
void textureClassification() {
// 1. 加载图像数据集
std::vector<cv::Mat> images = loadTextureImages();
// 2. 提取LBP特征
cv::Mat trainingData;
std::vector<int> labels;
for(size_t i=0; i<images.size(); i++) {
cv::Mat gray;
cv::cvtColor(images[i], gray, cv::COLOR_BGR2GRAY);
// 提取多尺度LBP特征
cv::Mat lbp = multiScaleLBP(gray);
// 计算直方图
cv::Mat hist = computeLBPHistogram(lbp);
trainingData.push_back(hist.reshape(1,1));
labels.push_back(getImageLabel(images[i]));
}
// 3. 训练分类器
cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::create();
svm->train(trainingData, cv::ml::ROW_SAMPLE, labels);
// 4. 测试评估
// ...
}
void faceRecognition() {
// 加载人脸检测器
cv::CascadeClassifier faceDetector;
faceDetector.load("haarcascade_frontalface_default.xml");
// 初始化LBPH人脸识别器
cv::Ptr<cv::face::LBPHFaceRecognizer> recognizer =
cv::face::LBPHFaceRecognizer::create(1, 8, 8, 8, 123.0);
// 训练识别器
std::vector<cv::Mat> faces = loadFaceImages();
std::vector<int> labels = loadFaceLabels();
recognizer->train(faces, labels);
// 实时识别
cv::VideoCapture cap(0);
while(true) {
cv::Mat frame;
cap >> frame;
// 人脸检测
std::vector<cv::Rect> faces;
faceDetector.detectMultiScale(frame, faces);
for(auto &face : faces) {
cv::Mat faceROI = frame(face).clone();
cv::cvtColor(faceROI, faceROI, cv::COLOR_BGR2GRAY);
cv::resize(faceROI, faceROI, cv::Size(100,100));
// 识别
int label = -1;
double confidence = 0;
recognizer->predict(faceROI, label, confidence);
if(confidence < 70) {
cv::putText(frame, "Person "+std::to_string(label),
face.tl(), cv::FONT_HERSHEY_SIMPLEX, 1.0,
cv::Scalar(0,255,0), 2);
}
}
}
}
本文详细介绍了在C++ OpenCV中实现扩展LBP特征的各种方法,包括: - 基本LBP和圆形LBP实现 - 旋转不变LBP改进 - 均匀模式LBP优化 - 多尺度LBP特征融合 - 实际应用示例
扩展LBP特征通过改进原始算法,显著提升了特征的判别能力和鲁棒性,使其成为计算机视觉领域重要的纹理分析工具。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。