如何使用具有面部特征的 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 n
(m
行,每个长度为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)分类器?的主要内容,如果未能解决你的问题,请参考以下文章