基于 OpenCV 的 LBP + SVM 人脸识别
2016-11-27 16:35
549 查看
本文中对人脸的LBP特征的提取,采用了LBP的圆形算子,通过对ORL92112人脸库中的样本进行识别,据统计,训练集与测试集的准确率均达到了100%;
经LBP处理后的图像如下图所示:
如上图所示,左侧图像为原图像,右侧图像为提取出的LBP图像;利用LBP圆形算子,可以非常清晰描述出人脸特征;
故,可以利用LBP算子对人脸特征进行提取并识别,而且在处理过程中,不受图像的光照、旋转、角度等因素的影响;
算法的处理代码如下所述:
LBP算法头文件:
head.h:
LBP.cpp
经LBP处理后的图像如下图所示:
如上图所示,左侧图像为原图像,右侧图像为提取出的LBP图像;利用LBP圆形算子,可以非常清晰描述出人脸特征;
故,可以利用LBP算子对人脸特征进行提取并识别,而且在处理过程中,不受图像的光照、旋转、角度等因素的影响;
算法的处理代码如下所述:
LBP算法头文件:
head.h:
#ifndef _HEAD_H #define _HEAD_H #include <opencv2/opencv.hpp> #include <iostream> #include <cassert> #include <vector> #include <numeric> #include <algorithm> #include <functional> #include <iterator> #endif // _HEAD_HLBP.h
#ifndef _LBP_H #define _LBP_H #include "head.h" typedef std::vector<double> VecDouble; typedef std::vector<int> VecInt; typedef std::vector<float> VecFloat; class LBP { public: LBP(); ~LBP(); public: enum LBP_TYPE { LBP_UNIFORM = 0, // uniform LBP LBP_NORMAL = 1, // lbp LBP_CIRCLE = 2 // circular operator of lbp }; public: // 传统的 LBP 算法 void calLBP(IplImage* srcImg, IplImage* dstImg); // LBP 圆形算子算法 void calCirLBP(IplImage* srcImg, IplImage* dstImg, int radius, int neighbor); // uniform LBP 算法 void calUniformLBP(IplImage* src, IplImage* dst); public: // 设置半径 void setRadius(int radius) { m_radius = radius; } // 设置领域数 void setNeighbors(int neighbor) { m_neighbor = neighbor; } // 计算特征值 void calLBPFeatures(IplImage* srcImg, IplImage* dstImg, VecDouble& hist, LBP_TYPE lbpType); private: int m_radius; int m_neighbor; }; #endif // _LBP_H
LBP.cpp
#include "stdafx.h" #include "LBP.h" #include <iostream> using namespace std; LBP::LBP() : m_radius(0) , m_neighbor(0) { } LBP::~LBP() { } //基于旧版本的opencv的LBP算法opencv1.0 // 3 x 3 矩阵如下所示 // [ 1, 2, 3] // [ 8, ij,4] // [ 7, 6, 5] void LBP::calLBP(IplImage* srcImg, IplImage* dstImg) { // 原图像为单通道图像,目标图像为单通道图像 assert(srcImg != NULL && srcImg->nChannels == 1); assert(dstImg != NULL && dstImg->nChannels == 1); unsigned tmp[8] = { 0 }; // 遍历图像 for (int rows = 1; rows < srcImg->height - 1; ++rows) { for (int cols = 1; cols < srcImg->width - 1; ++cols) { int sum = 0; double center = cvGetReal2D(srcImg, rows, cols); // 顺时针遍历 double val = 0.0; // 左上角 val = cvGetReal2D(srcImg, rows - 1, cols - 1); val > center ? tmp[0] = 1 : tmp[0] = 0; // 正上方 val = cvGetReal2D(srcImg, rows, cols - 1); val > center ? tmp[1] = 1 : tmp[1] = 0; // 右上角 val = cvGetReal2D(srcImg, rows + 1, cols - 1); val > center ? tmp[2] = 1 : tmp[2] = 0; // 右侧 val = cvGetReal2D(srcImg, rows + 1, cols); val > center ? tmp[3] = 1 : tmp[3] = 0; // 右下角 val = cvGetReal2D(srcImg, rows + 1, cols + 1); val > center ? tmp[4] = 1 : tmp[4] = 0; // 下方 val = cvGetReal2D(srcImg, rows, cols + 1); val > center ? tmp[5] = 1 : tmp[5] = 0; // 左下角 val = cvGetReal2D(srcImg, rows - 1, cols + 1); val > center ? tmp[6] = 1 : tmp[6] = 0; // 左侧 val = cvGetReal2D(srcImg, rows - 1, cols); val > center ? tmp[7] = 1 : tmp[7] = 0; // 计算 LBP 编码 for (int i = 0; i < 8; ++i) { sum += tmp[i] * pow(2, i); } cvSetReal2D(dstImg, rows, cols, sum); } }// end for } // uniform LBP,一致局部二值模式 void LBP::calUniformLBP(IplImage *src, IplImage *dst) { assert(src != NULL && src->nChannels == 1); assert(dst != NULL && dst->nChannels == 1); int tmp[8] = { 0 }; int rows = src->height - 1; int cols = src->width - 1; for (int i = 1; i < rows; ++i) { for (int j = 1; j < cols; ++j) { int sum = 0; double center = cvGetReal2D(src, i, j); // 顺时针遍历 double val = 0.0; val = cvGetReal2D(src, i - 1, j - 1); // 左上角 val > center ? tmp[0] = 1 : tmp[0] = 0; val = cvGetReal2D(src, i, j - 1); // 正上方 val > center ? tmp[1] = 1 : tmp[1] = 0; val = cvGetReal2D(src, i + 1, j - 1); // 右上角 val > center ? tmp[2] = 1 : tmp[2] = 0; val = cvGetReal2D(src, i + 1, j); // 右侧 val > center ? tmp[3] = 1 : tmp[3] = 0; val = cvGetReal2D(src, i + 1, j + 1); // 右下角 val > center ? tmp[4] = 1 : tmp[4] = 0; val = cvGetReal2D(src, i, j + 1); // 正下方 val > center ? tmp[5] = 1 : tmp[5] = 0; val = cvGetReal2D(src, i - 1, j + 1); // 左下角 val > center ? tmp[6] = 1 : tmp[6] = 0; val = cvGetReal2D(src, i - 1, j); // 左侧 val > center ? tmp[7] = 1 : tmp[7] = 0; //计算0、1翻转次数 for (int k = 0; k < 8; k++) { if (k != 7) { sum += abs(tmp[k] - tmp[k + 1]); } else { sum += abs(tmp[k] - tmp[0]); } } //通过翻转次数判断具体特征值 if (sum <= 2) { for (int i = 0; i < 8; ++i) { sum += tmp[i] * pow(2, (7 - i)); } } else { sum = 5; //将不满足的取5 } cvSet2D(dst, i, j, cvScalar(sum)); } } } // 圆形 LBP 算子 void LBP::calCirLBP(IplImage* src, IplImage* dst, int radius, int neighbors) { // 处理的图像为单通道图像 assert(src->nChannels == 1); for (int i = 0; i < neighbors; ++i) { // 正弦弧度 double sRadian = sin(2.0 * CV_PI * i / static_cast<double>(neighbors)); // 余弦弧度 double cRadian = cos(2.0 * CV_PI * i / static_cast<double>(neighbors)); // 采样点的计算 double x = static_cast<double>(-radius * sRadian); double y = static_cast<double>(radius * cRadian); // 下取整的值 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)); // 小数部分 double tx = x - fx; double ty = y - fy; // 设置插值权重 double w1 = (1 - tx) * (1 - ty); double w2 = tx * (1 - ty); double w3 = (1 - tx) * ty; double w4 = tx * ty; // 循环处理图像数据 for (int rows = radius; rows < src->height - radius; ++rows) { for (int cols = radius; cols < src->width - radius; ++cols) { // 计算插值 double t1 = w1 * cvGetReal2D(src, rows + fy, cols + fx); double t2 = w2 * cvGetReal2D(src, rows + fy, cols + cx); double t3 = w3 * cvGetReal2D(src, rows + cy, cols + fx); double t4 = w4 * cvGetReal2D(src, rows + cy, cols + cx); double t = t1 + t2 + t3 + t4; double val = cvGetReal2D(src, rows, cols); double epsilon = std::numeric_limits<double>::epsilon(); uchar c = ((t > val) || abs(t - val) < epsilon); uchar tmp = c * pow(2, i); double v = cvGetReal2D(dst, rows - radius, cols - radius); v += tmp; cvSetReal2D(dst, rows - radius, cols - radius, v); } } } } // 计算 LPB 特征值 void LBP::calLBPFeatures(IplImage* srcImg, IplImage* dstImg, VecDouble& hist, LBP_TYPE lbpType) { assert(srcImg != NULL && srcImg->nChannels == 1); assert(dstImg != NULL && dstImg->nChannels == 1); // 计算 LBP 图像 if (lbpType == LBP_NORMAL) { calLBP(srcImg, dstImg); } else if (lbpType == LBP_UNIFORM) { calUniformLBP(srcImg, dstImg); } else if (lbpType == LBP_CIRCLE) { try { if (m_radius == 0 || m_neighbor == 0) { throw "please call setRadius() and setNeighbor() to set values."; } else { calCirLBP(srcImg, dstImg, m_radius, m_neighbor); } } catch (char* e) { cout << e << endl; } }// end if // 计算直方图 VecInt vec; vec.resize(256); for (int i = 0; i < dstImg->width; ++i) { for (int j = 0; j < dstImg->height; ++j) { CvScalar s = cvGet2D(dstImg, j, i); int val = s.val[0]; ++vec[val]; } }// end for // 将直方图归一化 int maxVal = *max_element(vec.begin(), vec.end()); int minVal = *min_element(vec.begin(), vec.end()); for (int i = 0; i < vec.size(); ++i) { double tmp = 0.0; tmp = static_cast<double>(vec[i]) / static_cast<double>(maxVal); hist.push_back(tmp); } }
相关文章推荐
- 基于OpenCV的EigenFace FisherFace LBPHFace人脸识别的实现
- Linux系统下利用OpenCV实现人脸检测和基于LBPH算法的人脸识别
- 基于OpenCV读取摄像头进行人脸检测和人脸识别
- 基于opencv的人脸性别识别
- 【OpenCV学习笔记】【教程翻译】一(基于SVM和神经网络的车牌识别概述)
- 基于QT和OpenCV的人脸检测识别系统(2)
- 基于LBP和PCA的人脸性别识别方法
- 基于 OpenCV 的人脸识别
- OpenCV自学笔记18. 基于SVM和神经网络的车牌识别(二)
- 基于MATLAB,运用PCA+SVM的特征脸方法人脸识别
- 基于OpenCV的PHP图像人脸识别技术
- 转:基于开源项目OpenCV的人脸识别Demo版整理(不仅可以识别人脸,还可以识别眼睛鼻子嘴等)【模式识别中的翘楚】
- 基于opencv2.0的haar算法以人脸识别为例的训练分类器xml的方法
- opencv 基于SVM的几何形状识别
- 基于 OpenCV 的人脸识别(强烈推荐)
- Qt+Caffe+OpenCV——【一个基于VGG网络的人脸识别考勤系统】(二)创建一个登录界面和主窗口
- 基于opencv2.0的haar算法以人脸识别为例的训练分类器xml的方法
- 基于opencv的手写数字识别(MFC,HOG,SVM)
- 人脸和性别识别(基于OpenCV)
- 基于 OpenCV 的人脸识别