第一步,准备数据。
原始数据采用FDDB人脸检测测评数据集,FDDB是全世界最具权威的人脸检测评测平台之一,包含2845张图片,共有5171个人脸作为测试集。测试集范围包括:不同姿势、不同分辨率、旋转和遮挡等图片,同时包括灰度图和彩色图,标准的人脸标注区域为椭圆形。
当然,为了简单起见,我们不直接使用这个数据集。我的做法是,自己做一些正样本和负样本数据集。正样本,即人脸,从FDDB数据集中选择一些图片,然后手动裁剪出人脸部分的图片,大概裁剪了100张。部分人脸如下图:
负样本,即非人脸,采用程序,每隔一定的间隔滑动裁剪。当然,可能会裁剪出一些人脸,这些需要手动除去。其中,裁剪图像的大小有几种,分别是64*64,100*100,128*128,144*144,160*160,总共截取了大概500张图片。部分图像结果如下:
训练数据集,从上述的正样本中拿出90张,负样本中拿出400张,作为训练集。将剩下的正负样本作为测试集。
第二步,提取特征。此处特征采用HOG特征。
具体步骤如下:
1)读取训练的图片
2)将训练图片缩放至64*64大小
3)将图像转换为灰度图像
4)对灰度图像求出HOG特征。
得到的HOG为1*144大小的Mat类型的数据。由于下一步SVM训练中,送入SVM的训练数据为Mat类型的矩阵,其中每一行表示一个训练数据,故SVM训练数据Mat大小为n*144,n表示训练集数量。因此,需要先创建一个n*144的Mat类型数据,然后将每个图像的HOG特征复制到刚才产生的Mat数据,每个图像的HOG特征为刚才产生的Mat数据的一行。
第三步,训练SVM。opencv3自带SVM,只需要简单几步设置即可。
函数如下:
1)创建SVM
cv::Ptr svm = cv::ml::SVM::create();
2)设置SVM类型
svm->setType(cv::ml::SVM::Types::C_SVC);
3)设置核函数为线性核函数
svm->setKernel(cv::ml::SVM::KernelTypes::LINEAR);
4)设置迭代终止条件
svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER, 100, 1e-6));
5)开始训练
svm->train(sampleFeatureMat, cv::ml::SampleTypes::ROW_SAMPLE, sampleLabelMat);
6)保存训练后的SVM参数
svm->save("svm_save.xml");
注:一些参数说明
svm_type –指定SVM的类型,下面是可能的取值:
CvSVM::C_SVC C类支持向量分类机。 n类分组 (n \geq 2),允许用异常值惩罚因子C进行不完全分类。
CvSVM::NU_SVC \nu类支持向量分类机。n类似然不完全分类的分类器。参数为 \nu 取代C(其值在区间【0,1】中,nu越大,决策边界越平滑)。
CvSVM::ONE_CLASS 单分类器,所有的训练数据提取自同一个类里,然后SVM建立了一个分界线以分割该类在特征空间中所占区域和其它类在特征空间中所占区域。
CvSVM::EPS_SVR \epsilon类支持向量回归机。训练集中的特征向量和拟合出来的超平面的距离需要小于p。异常值惩罚因子C被采用。
CvSVM::NU_SVR \nu类支持向量回归机。 \nu 代替了 p。
kernel_type –SVM的内核类型,下面是可能的取值:
CvSVM::LINEAR 线性内核。没有任何向映射至高维空间,线性区分(或回归)在原始特征空间中被完成,这是最快的选择。K(x_i, x_j) = x_i^T x_j.
CvSVM::POLY 多项式内核: K(x_i, x_j) = (\gamma x_i^T x_j + coef0)^{degree},\gamma > 0.
CvSVM::RBF 基于径向的函数,对于大多数情况都是一个较好的选择: K(x_i, x_j) = e^{-\gamma ||x_i - x_j||^2},\gamma > 0.
CvSVM::SIGMOID Sigmoid函数内核:K(x_i, x_j) = \tanh(\gamma x_i^T x_j +coef0).
degree –内核函数(POLY)的参数degree。
gamma –内核函数(POLY/ RBF/ SIGMOID)的参数\gamma。
coef0 –内核函数(POLY/ SIGMOID)的参数coef0。
Cvalue – SVM类型(C_SVC/ EPS_SVR/ NU_SVR)的参数C。
nu – SVM类型(NU_SVC/ ONE_CLASS/ NU_SVR)的参数 \nu。
p – SVM类型(EPS_SVR)的参数 \epsilon。
class_weights – C_SVC中的可选权重,赋给指定的类,乘以C以后变成 class\_weights_i * C。所以这些权重影响不同类别的错误分类惩罚项。权重越大,某一类别的误分类数据的惩罚项就越大。
term_crit – SVM的迭代训练过程的中止条件,解决部分受约束二次最优问题。您可以指定的公差和/或最大迭代次数。
第四步,测试。将新的图片送入SVM中,让SVM预测结果。
总体程序如下:
(测试环境:Win7 64位+ Visual Studio 2015 + Opencv310)
#include
#include
#include
#include
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/ml.hpp"
using namespace std;
using namespace cv;
//Parameters
#define N_BINS 16 //Number of bins
#define N_DIVS 3 //Number of cells = N_DIVS*N_DIVS
#define N_PHOG N_DIVS*N_DIVS*N_BINS
#define BIN_RANGE (2*CV_PI)/N_BINS
//Haar Cascade Path
//Input: Grayscale image
//Output: HOG features
Mat hog(const Mat &Img);
#define PosSamNO 90 //正样本个数
#define NegSamNO 400 //负样本个数
#define HardExampleNO 0
#define TRAIN true //是否进行训练,true表示重新训练,false表示读取xml文件中的SVM模型
int main()
{
// initial SVM
cv::Ptr svm = cv::ml::SVM::create();
int DescriptorDim;//HOG描述子的维数,由图片大小、检测窗口大小、块大小、细胞单元中直方图bin个数决定
Mat sampleFeatureMat;//所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于HOG描述子维数
Mat sampleLabelMat;//训练样本的类别向量,行数等于所有样本的个数,列数等于1;1表示有人,-1表示无人
if (TRAIN)
{
//依次读取正样本图片,生成HOG特征
for (int i = 1; i
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?