紧接上一篇未完成的工作,实现LBPH!!!
介绍其实上篇博客已经介绍了一些LBP的实现:
https://blog.csdn.net/zqx951102/article/details/100713614
LBPH的概念这篇博客有介绍,
https://blog.csdn.net/guo1988kui/article/details/79976202
LBPH,Local Binary Patterns Histograms,即LBP特征的统计直方图,LBPH将LBP特征与图像的空间信息结合在一起。这种表示方法由Ahonen等人在论文[3]中提出,他们将LBP特征图像分成m个局部块,并提取每个局部块的直方图,然后将这些直方图依次连接在一起形成LBP特征的统计直方图,即LBPH。
一幅图像具体的计算LBPH的过程(以Opencv中的人脸识别为例):
- 计算图像的LBP特征图像,在上面已经讲过了。
- 将LBP特征图像进行分块,Opencv中默认将LBP特征图像分成8行8列64块区域
- 计算每块区域特征图像的直方图cell_LBPH,将直方图进行归一化,直方图大小为1*numPatterns
- 将上面计算的每块区域特征图像的直方图按分块的空间顺序依次排列成一行,形成LBP特征向量,大小为1*(numPatterns*64)
- 用机器学习的方法对LBP特征向量进行训练,用来检测和识别目标
举例说明LBPH的维度:
采样点为8个,如果用的是原始的LBP或Extended LBP特征,其LBP特征值的模式为256种,则一幅图像的LBP特征向量维度为:64256=16384维,
而如果使用的UniformPatternLBP特征,其LBP值的模式为59种,其特征向量维度为:6459=3776维,可以看出,使用等价模式特征,其特征向量的维度大大减少,
这意味着使用机器学习方法进行学习的时间将大大减少,而性能上没有受到很大影响。
Opencv的人脸识别使用的是Extended LBP
这篇博客也介绍了lbph不过代码不全,计算直方图没写!!
https://blog.csdn.net/heli200482128/article/details/79204008
他就是用了elbp。然后在用lbph计算得出直方图矩阵。
本人综合了一下:然后代码贴出:
#include "opencv2/core/core.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <bitset>
using namespace cv;
using namespace std;
//计算一个LBP特征图像块的直方图
Mat getLocalRegionLBPH(const Mat& src,int minValue,int maxValue,bool normed)
{
//定义存储直方图的矩阵
Mat result;
//计算得到直方图bin的数目,直方图数组的大小
int histSize = maxValue - minValue + 1;
//定义直方图每一维的bin的变化范围
float range[] = { static_cast<float>(minValue),static_cast<float>(maxValue + 1) };
//定义直方图所有bin的变化范围
const float* ranges = { range };
//计算直方图,src是要计算直方图的图像,1是要计算直方图的图像数目,0是计算直方图所用的图像的通道序号,从0索引
//Mat()是要用的掩模,result为输出的直方图,1为输出的直方图的维度,histSize直方图在每一维的变化范围
//ranges,所有直方图的变化范围(起点和终点)
calcHist(&src,1,0,Mat(),result,1,&histSize,&ranges,true,false);
//归一化
if(normed)
{
result /= (int)src.total();
}
//结果表示成只有1行的矩阵
return result.reshape(1,1);
}
//计算LBP特征图像的直方图LBPH
Mat getLBPH(Mat src,int numPatterns,int grid_x,int grid_y)
{
int width = src.cols / grid_x;
int height = src.rows / grid_y;
//定义LBPH的行和列,grid_x*grid_y表示将图像分割成这么些块,numPatterns表示LBP值的模式种类
Mat result = Mat::zeros(grid_x * grid_y,numPatterns,CV_32FC1);
if(src.empty())
{
return result.reshape(1,1);
}
int resultRowIndex = 0;
//对图像进行分割,分割成grid_x*grid_y块,grid_x,grid_y默认为8
for(int i=0;i<grid_x;i++)
{
for(int j=0;j<grid_y;j++)
{
//图像分块
Mat src_cell = Mat(src,Range(i*height,(i+1)*height),Range(j*width,(j+1)*width));
//计算直方图
Mat hist_cell = getLocalRegionLBPH(src_cell,0,(numPatterns-1),true);
//将直方图放到result中
Mat rowResult = result.row(resultRowIndex);
hist_cell.reshape(1,1).convertTo(rowResult,CV_32FC1);
resultRowIndex++;
}
}
return result.reshape(1,1);
}
//2.圆形算子LBP函数
void elbp(Mat& src, Mat &dst, int radius, int neighbors)
{
for(int n=0; n<neighbors; n++)
{
// 采样点的计算
float x = static_cast<float>(radius * cos(2.0*CV_PI*n/static_cast<float>(neighbors)));
float y = static_cast<float>(-radius * sin(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;
}
}
}
}
int main()
{
//显示原图
Mat img = imread("F://ZQX//32x256.bmp", 0);
namedWindow("image");
imshow("image", img);
int radius, neighbors;
//假设
radius = 1; //半径越小 图像越清晰 精细
neighbors =8; //领域数目越小,图像亮度越低,合理,4太小了比较黑 设置8比较合理
Mat dst1 = Mat(img.rows-2*radius, img.cols-2*radius,CV_8UC1, Scalar(0)); //2
elbp(img,dst1,1,8);
namedWindow("圆形LBP");
imshow("圆形LBP", dst1);
//lbph是先生成lbp然后再统计局部的直方图,具体步骤https://blog.csdn.net/guo1988kui/article/details/79976202,第三部分LBPH,看一下步骤就明白了!!
Mat m=getLBPH(dst1,2,8,8);
cout<<m<<endl;
while(1)
waitKey(0);
}
图像使用的是一张32*256虹膜图像
效果图:
直方图矩阵的数值和圆形LBP处理的结果,上一篇处理的结果都没贴,就贴了代码。
最近看了一篇基于python的博客代码:
https://blog.csdn.net/lk3030/article/details/84034963
链接在这 都能实现 挺不错的