您的位置:首页 > 编程语言 > C#

【EmguCV】C#实现HOG与SVM的几个问题

2015-06-04 21:18 441 查看

关于SVM中的alpha、rho向量


由于EmguCV封装的更加彻底,在C#中并不能跟C++一样通过重载获得这两个中间变量

//继承自CvSVM的类,因为生成setSVMDetector()中用到的检测子参数时,需要用到训练好的SVM的decision_func参数,
//但通过查看CvSVM源码可知decision_func参数是protected类型变量,无法直接访问到,只能继承之后通过函数访问
class MySVM : public CvSVM
{
public:
//获得SVM的决策函数中的alpha数组
double * get_alpha_vector()
{
return this->decision_func->alpha;
}

//获得SVM的决策函数中的rho参数,即偏移量
float get_rho()
{
return this->decision_func->rho;
}
};


见C++实例:训练SVM分类器进行HOG行人检测 /article/2151922.html


为了获取这两个变量用于自定义HOG检测子,暂时想到的几种办法:

1、C#读取生成的XML文件


分类器训练好后一般需要进行保存,方便直接预测

SVM svm = new SVM();
bool trained = svm.Train(my_train.sampleFeatureMat, my_train.sampleLabelMat, null, null, p);
svm.Save(@"../HOG_SVM.xml");


这里给出我的C#提取SVM参数方式:

(只用于提取训练目标为1与-1两类的XML文件,如果类型大于2,则有多个rho与alpha数组,需要进一步组合)

using System;
using System.Text;
using System.Xml;
using System.IO;

namespace HOG_SVM
{
class GetData
{
public double[] alpha;
public double rho;

XmlDocument doc;
StreamReader sr;
int sv_count;
string alpha_str;

public GetData()
{
doc = new XmlDocument();
doc.Load(Form1.LOAD_PATH);
XmlNode nodes = doc.DocumentElement;
get_rho(nodes);
getAlpha_str(nodes);
getSv_count(nodes);
getAlpha();
}

public void get_rho(XmlNode nodes)
{
if (nodes.HasChildNodes)
{
foreach (XmlNode node in nodes.ChildNodes)
{
if (nodes.Name == "rho")
{
rho = Double.Parse(nodes.InnerText);
return;
}
get_rho(node);
}
}
}

public void getAlpha_str(XmlNode nodes)
{
if (nodes.HasChildNodes)
{
foreach (XmlNode node in nodes.ChildNodes)
{
if (nodes.Name == "alpha")
{
//sr = new StreamReader(new Stream(nodes.InnerText));
alpha_str = nodes.InnerText;
return;
}
getAlpha_str(node);
}
}
}

public void getSv_count(XmlNode nodes)
{
if (nodes.HasChildNodes)
{
foreach (XmlNode node in nodes.ChildNodes)
{
if (nodes.Name == "sv_count")
{
sv_count = int.Parse(nodes.InnerText);
return;
}
getSv_count(node);
}
}
}

public void getAlpha()
{
byte[] array = Encoding.ASCII.GetBytes(alpha_str);
MemoryStream stream = new MemoryStream(array); //convert stream 2 string
sr = new StreamReader(stream);
alpha = new double[sv_count];
sr.ReadLine();
int i = 0;
while (true)
{

string tmp = sr.ReadLine();
if (tmp == "")
continue;

string[] tmp2 = tmp.Split(' ');
foreach (string ele in tmp2)
{
if (ele != "")
{
alpha[i] = double.Parse(ele);
i++;
}
}

if (i == sv_count)
break;
}
}
}
}


c#读取XML的方式比较多,还可以利用Linq操作xml,另外也可以参考以下链接:

c# 读取opencv 生成的svm训练好的xml分类器http://blog.csdn.net/yeyang911/article/details/12905153



2、使用其他C#的SVM库


关于提取参数,自定义HOG Detector的问题,后来在网上搜到了这种方式

Training custom SVM to use with HOGDescriptor in OpenCV:

I was struggling with the same problem. Searching forums I have found, that the detector cannot be trained using CvSVM (I don't know the reason). I used LIBSVM for training the the detector. Here is the code to extract the detector for HOGDescriptor.setSVMDetector( w): For data details see LIBSVM documentation/header. I did all the training in C++, filling the LIBSVM training data from CV to LIBSVM; the code below extracts the detector vector needed for cv::HOGDescriptor. The w parameter is
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]);


来自: http://stackoverflow.com/questions/15339657/training-custom-svm-to-use-with-hogdescriptor-in-opencv

该回答提到的 LIBSVM 库就是比较好的替代手段,应该可以直接获取到这两个中间量,而不用再去解析XML。

可以去作者主页上下载LIBSVM库:http://www.csie.ntu.edu.tw/~cjlin/libsvm/#csharp



3、其他相关链接



前些天的【OpenCV】基于HOG与SVM的行人检测学习(原理小结):

/article/5317589.html

training GPU HOGDescriptor for multi scale detection:

http://answers.opencv.org/question/4351/training-gpu-hogdescriptor-for-multi-scale-detection/



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: