如何使用具有面部特征的 openCV 训练支持向量机(svm)分类器?

Posted

技术标签:

【中文标题】如何使用具有面部特征的 openCV 训练支持向量机(svm)分类器?【英文标题】:How to train a Support Vector Machine(svm) classifier with openCV with facial features? 【发布时间】:2014-11-21 05:45:28 【问题描述】:

我想使用 svm 分类器进行面部表情检测。我知道 opencv 有一个 svm api,但我不知道训练分类器的输入应该是什么。到目前为止,我已经阅读了很多论文,所有论文都说在面部特征检测训练分类器之后。

到目前为止,我做了什么,

    人脸检测, 每帧计算 16 个面部点。下面是人脸特征检测的输出![输入图片描述 保存特征点像素地址的向量

注意:我知道如何只用正面和负面图像训练SVM,我看到了这个代码here,但我不知道如何将面部特征信息与之结合。

谁能帮我用 svm 开始分类。

一个。训练分类器的样本输入应该是什么?

b.如何用这个面部特征点训练分类器?

问候,

【问题讨论】:

嘿,把脸上的点带回来;)(你用的是哪个opencv版本?) 【参考方案1】:

opencv 中的机器学习算法都带有类似的界面。为了训练它,你传递了一个 NxM Mat 的特征(N 行,每个特征一行,长度为 M)和一个带有类标签的 Nx1 Mat。像这样:

//traindata      //trainlabels

f e a t u r e    1 
f e a t u r e    -1
f e a t u r e    1
f e a t u r e    1
f e a t u r e    -1

对于预测,你以同样的方式用 1 行填充一个 Mat,它将返回预测的标签

所以,假设你的 16 个面部点存储在一个向量中,你会这样做:

Mat trainData; // start empty
Mat labels;

for all facial_point_vecs:

    for( size_t i=0; i<16; i++ )
    
        trainData.push_back(point[i]);
    
    labels.push_back(label); // 1 or -1

// now here comes the magic:
// reshape it, so it has N rows, each being a flat float, x,y,x,y,x,y,x,y... 32 element array
trainData = trainData.reshape(1, 16*2); // numpoints*2 for x,y

// we have to convert to float:
trainData.convertTo(trainData,CV_32F);

SVM svm; // params omitted for simplicity (but that's where the *real* work starts..)
svm.train( trainData, labels );


//later predict:
vector<Point> points;
Mat testData = Mat(points).reshape(1,32); // flattened to 1 row
testData.convertTo(testData ,CV_32F);
float p = svm.predict( testData );

【讨论】:

Hi Break 感谢您的回答,但我有一个问题——如何同时提供图像和特征点?意思是,假设我有 50 个正图像和 20 个负图像,每个图像有 16 个特征点,那么如何插入哪些特征属于哪个图像的信息?在这种情况下,我应该在 trainData 中 push_back 什么? - 为什么我在“重塑”行中将 16 与 2 相乘? 嗯,当我开始在这里输入时,它看起来就像你想做情绪检测,比如快乐/悲伤。现在您对其进行了多次编辑,似乎更多的是您想要人脸识别/人员识别,这是一双不同的鞋子。你能澄清一下吗? 哦!我只想做情绪检测。现在只有快乐和悲伤。 啊,好的。请注意,与图像没有任何联系。 (它不知道图像,它只知道你的地标点)它最后说的是快乐还是不快乐。 好的,我明白,但对我来说不是很清楚。假设 image1 在 (xi,yi) 上有特征,而 image2 在 (Xi2,yi2) 上有特征,那么要做 SVM 我们只插入 (Xi,Yi) 和 (Xi2,Yi2)?【参考方案2】:

面部手势识别是一个被广泛研究的问题,通过对现有文献的深入研究可以找到您需要使用的适当功能。一旦你有了你认为好的特征描述符,你就可以继续用这些来训练 SVM。一旦你用最优参数(通过交叉验证找到)训练了 SVM,你就开始在看不见的数据上测试 SVM 模型,并报告准确性。一般来说,这就是管道。

现在是关于 SVM 的部分:

SVM 是一个二元分类器——它可以区分两个类(尽管它也可以扩展到多个类)。 OpenCV 在 ML 库中有一个用于 SVM 的内置模块。 SVM 类有两个开头的函数:train(..)predict(..)。要训​​练分类器,您需要在输入中提供大量样本特征描述符,以及它们的类标签(通常为 -1 和 +1)。请记住 OpenCV 支持的格式:每个训练样本都必须是行向量。并且每一行在标签向量中都有一个对应的类标签。因此,如果您有一个长度为n 的描述符,并且您有m 这样的样本描述符,那么您的训练矩阵将为m x nm 行,每个长度为n),标签向量将为长度m。还有一个 SVMParams 对象,其中包含您必须指定的 SVM-type 等属性和 C 等参数的值。

训练完成后,您从图像中提取特征,将其转换为单行格式,并提供给 predict(),它会告诉您它属于哪个类(+1 或 -1)。

还有一个 train_auto() 具有相似的参数,具有相似的格式,可为您提供 SVM 参数的最佳值。

还可以查看detailed SO answer 以查看示例。

编辑: 假设您有一个返回特征向量的特征描述符,算法将类似于:

Mat trainingMat, labelsMat;
for each image in training database:
  feature = extractFeatures( image[i] );
  Mat feature_row = alignAsRow( feature );
  trainingMat.push_back( feature_row );
  labelsMat.push_back( -1 or 1 );  //depending upon class.
mySvmObject.train( trainingMat, labelsMat, Mat(), Mat(), mySvmParams );

我不认为extractFeatures()alignAsRow() 是现有函数,您可能需要自己编写它们。

【讨论】:

感谢您的回复。正如我在问题中提到的那样,我理论上知道我需要做什么。我知道在特征提取之后我将不得不训练 SVM 分类器。我也知道训练后我可以使用 predict() 来预测面部表情。所以我的主要问题是如何使用这些特征点来训练 svm 分类器?如果你能提供一些代码片段也会有所帮助。 再次感谢,但我只提供功能吗?没有相关的图片?那么它将如何关联哪些特征属于哪个图像? 没有非图像(除非原始图像本身是一个特征,但很少如此)。您必须从图像中提取特征进行训练,并且在测试时再次提取图像特征。训练和测试的不是图像,而是相应的特征。 如何保存训练有素的 svm "mySvmObject",我做了 SvmObject.save("abc.xml");,它不起作用:'( 它有没有给你一些错误信息?它是mySvmObject.save(..)

以上是关于如何使用具有面部特征的 openCV 训练支持向量机(svm)分类器?的主要内容,如果未能解决你的问题,请参考以下文章

使用多个特征的支持向量机 (SVM) 训练

训练模型以实现 DLib 的面部特征点,例如手的特征点及其地标

使用阈值进行面部识别的理解困难

如何选择特征并使用支持向量机算法进行训练?

OpenCV支持向量机(SVM)介绍

具有分类数据的一类支持向量机