在OpenCV中训练自定义SVM以与HOGDescriptor一起使用

4
我正在尝试训练自己的检测器,用于OpenCV::HOGDescriptor,但我无法使现有的HOGDescriptor与我的新训练SVM配合使用。
我已经为正样本和负样本的训练图像计算了HOG特征,对它们进行了标记,并使用CvSVM进行了训练。我使用的参数是:
    CvSVMParams params;
    params.svm_type =CvSVM::EPS_SVR;
    params.kernel_type = CvSVM::LINEAR;
    params.C = 0.01;
    params.p = 0.5;

然后我计算支持向量的原始形式,这样我就只得到一个向量而不是很多个,并使用HOGDescriptor.setSVMDetector(vector)设置计算出来的支持向量。

这是原始形式

当我使用CvSVM.predict()时,我能够正确地对SVM进行分类,但HOGDescriptor.detect()或detectMultiScale()总是返回很多正匹配,并且不能给出准确的预测。

CvSVM.predict()使用原始支持向量进行分类,因此我的原始形式计算可能有问题。

有没有训练过自己的检测器的人可以指点我正确的方向?


似乎继承了libsvm中的一个错误,标签的顺序被搞乱了。predict函数知道标签的顺序并查找哪个标签是哪个,因此可以正常工作。我通过将我的+ve标签设置为小于我的-ve标签的数字来解决这个问题,即pos = 1,neg = 2。否则,您可能需要通过乘以-1来反转模型(这就是为什么接受的答案有奇怪的负号)。我选择不以这种方式做,以防他们修复了这个错误(如果您使用predict,则它实际上不是错误,但他们可能会更改它)。 - QED
3个回答

5
我编写了一个CvSVM的子类,用于在训练线性SVM后提取原始形式。正样本标记为1,负样本标记为-1。奇怪的是,我必须在alphas前面加上负号,并保留rho的符号不变,才能从HogDescriptor中获得正确的结果。
LinearSVM.h
#ifndef LINEAR_SVM_H_
#define LINEAR_SVM_H_
#include <opencv2/core/core.hpp>
#include <opencv2/ml/ml.hpp>

class LinearSVM: public CvSVM {
public:
  void getSupportVector(std::vector<float>& support_vector) const;
};  

#endif /* LINEAR_SVM_H_ */

LinearSVM.cc

#include "linear_svm.h"    
void LinearSVM::getSupportVector(std::vector<float>& support_vector) const {

    int sv_count = get_support_vector_count();
    const CvSVMDecisionFunc* df = decision_func;
    const double* alphas = df[0].alpha;
    double rho = df[0].rho;
    int var_count = get_var_count();
    support_vector.resize(var_count, 0);
    for (unsigned int r = 0; r < (unsigned)sv_count; r++) {
      float myalpha = alphas[r];
      const float* v = get_support_vector(r);
      for (int j = 0; j < var_count; j++,v++) {
        support_vector[j] += (-myalpha) * (*v);
      }
    }
    support_vector.push_back(rho);
}

非常好的解决方案,只有一个小问题 @DXM:这种转换到原始形式只适用于线性SVM,那么当我使用RBF核函数时怎么办? - G. Führ
1
我还没有研究过在OpenCV中使用RBF核的源代码。但是我的猜测是,一旦你将核应用于你的特征上,它应该与线性SVM相同。 - DXM
在我看来,这可能非常慢。Rbf内核计算特征和所有SVM支持向量之间的欧几里得距离。看一下预测方法代码。我对你考虑实现它的方式很好奇... - user1197918
什么是“decision_func”?它来自哪里? - ffttyy
decision_func 是从 CvSVM 继承而来的。 - DXM

4

我曾经也遇到过同样的问题。在搜索论坛时,我发现检测器不能使用CvSVM进行训练(我不知道原因)。我使用LIBSVM来训练检测器。以下是提取检测器用于HOGDescriptor.setSVMDetector(w)的代码。有关数据详细信息,请参阅LIBSVM文档/头文件。 我在C++中完成了所有培训,从CV到LIBSVM填充了LIBSVM培训数据; 下面的代码提取了cv :: HOGDescriptor所需的检测器向量。w参数为std :: vector<float> w

    const double * const *sv_coef = model.sv_coef;
const svm_node * const *SV = model.SV;
int l = model.l;
model.label;

const svm_node* p_tmp = SV[0];
int len = 0;
while( p_tmp->index != -1 )
{
    len++;
    p_tmp++;
}
w.resize( len+1 );

for( int i=0; i<l; i++)
{
    double svcoef = sv_coef[0][i];
    const svm_node* p = SV[i];
    while( p->index != -1 )
    {
        w[p->index-1] += float(svcoef * p->value);
        p++;
    }
}
w[len] = float(-model.rho[0]);

希望这能帮到你...

你试过这段代码吗?似乎能够在假图像中检测到正面。 - magarwal

0

根据我在Dalal的HOG检测器论文中所读到的内容,他建议为了消除误报,我们需要重新训练我们的模型。重新训练是通过应用初步模型(你的模型会产生很多误报),然后在所有负样本图像中检测对象来完成的。所有返回的矩形肯定都是误报。

然后,将所有这些误报添加到你的负样本图像(负数据集)中,再次进行训练。正如论文中建议的那样,得到的模型将返回更少的误报。

不幸的是,尽管我尝试了重新训练,但结果模型甚至无法识别任何东西,即使是正样本图像。但我认为这值得一试,因为这是HOG检测器发明者在论文中提出的建议。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接