本人作为一个机器学习的小菜鸟,在学习相关知识的过程中,CSDN博客给了我很大的帮助,作为回馈,我也来写点博客为后来者铺路。
注意:在程序前需要包含一些必要的OpenCV头文件,我是将这些头文件写在了CvHeadFiles.h文件之中
#include
"CvHeadFiles.h"
#include
<iostream>
#include
<fstream>
#include
<string>
#include
<vector>
using
namespace
cv;
using
namespace
cv::ml;
using
namespace
std;
int
main(
int
argc
,
char
**
argv
)
{
//--------------准备训练数据--------------------
//定义相关变量
int
ImgWidht = 24;
int
ImgHeight = 24;
vector
<
string
> img_path;
vector
<
int
> img_catg;
int
nLine = 0;
string
buf;
int
lab;
ifstream
svm_data(
"SVM_DATA.txt"
);
unsigned
long
n;
//依次读入样本的名和标签
for
(;;)
{
nLine++;
if
(nLine % 2)
{
svm_data
>>
buf;
if
(buf
==
"end"
)
break
;
img_path.push_back(buf);
//图像路径
}
else
{
svm_data
>>
lab;
img_catg.push_back(lab);
}
}
svm_data.close();
//关闭文件
//定义相关变量
Mat
data_mat, res_mat;
int
nImgNum = (nLine-1)/2;
//读入样本数量
res_mat
=
Mat
::zeros(nImgNum, 1,
CV_32SC1
);
Mat
src;
Mat
trainImg =
Mat
::zeros(ImgHeight, ImgWidht,
CV_8UC3
);
//需要分析的图片
//依次提取样本的HOG特征
for
(
string
::
size_type
i = 0; i != img_path.size(); i++)
{
//读入样本
src
=
imread(img_path
[
i
]
.c_str(), 1);
//依次读入样本图片
cout
<<
" processing "
<<
img_path
[
i
]
.c_str()
<<
endl;
resize(src, trainImg, cv::
Size
(ImgWidht, ImgHeight), 0, 0,
INTER_CUBIC
);
//将样本图片调整为标准大小
//对样本提取HOG特征向量
HOGDescriptor
*hog =
new
HOGDescriptor
(cvSize(ImgWidht, ImgHeight), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9);
//具体意思见参考文章1,2
vector
<
float
> descriptors;
//存放提取HOG特征向量的结果数组
hog->compute(trainImg, descriptors,
Size
(1, 1),
Size
(0, 0));
//对读入的样本图片提取HOG特征向量
if
(i == 0)
{
data_mat
=
Mat
::zeros(nImgNum, descriptors.size(),
CV_32FC1
);
//根据输入图片大小进行分配空间
}
cout
<<
"HOG dims: "
<<
descriptors.size()
<<
endl;
//存储所提取的样本的HOG特征值
n = 0;
for
(
vector
<
float
>::
iterator
iter = descriptors.begin();iter
!=
descriptors.end();iter
++
)
{
data_mat.at<
float
>(i, n) =
*
iter;
n++;
}
//存储样本的标签
res_mat.at<
int
>(i, 0) = img_catg
[
i
]
;
cout
<<
" end processing "
<<
img_path
[
i
]
.c_str()
<<
" "
<<
img_catg
[
i
]
<<
endl;
}
//----------------------------设置SVM参数---------------------------------
cout
<<
"\n------------------------------------------------------------\n"
;
cout
<<
"Starting training process"
<<
endl;
Ptr
<
SVM
> svm =
SVM
::create();
svm
->
setType(
SVM
::
C_SVC
);
svm
->
setC(10);
svm
->
setKernel(
SVM
::
RBF
);
svm
->
setTermCriteria(
TermCriteria
(
TermCriteria
::
MAX_ITER
, 10000, 1e-6));
//-------------------------------训练SVM------------------------------------------
svm
->
train(data_mat,
ROW_SAMPLE
, res_mat);
//注意此处data_mat和res_mat的类型
//利用训练数据和确定的学习参数,进行SVM学习
svm
->
save(
"SVM_DATA.xml"
);
cout
<<
"Finished training process"
<<
endl;
//--------------------------------检测样本---------------------------------------
//依次读入测试样本名
vector
<
string
> img_tst_path;
ifstream
img_tst(
"SVM_TEST.txt"
);
for
(;;)
{
img_tst
>>
buf;
if
(buf
==
"end"
)
break
;
img_tst_path.push_back(buf);
}
img_tst.close();
//定义相关变量
Mat
test;
int
pos=0, neg=0,sum=0;
char
line[512];
ofstream
predict_txt(
"SVM_PREDICT.txt"
);
for
(
string
::
size_type
j = 0; j < img_tst_path.size(); j++)
{
//依次读入测试样本
test
=
imread(img_tst_path
[
j
]
.c_str(), 1);
//读入图像
resize(test, trainImg, cv::
Size
(ImgWidht, ImgHeight), 0, 0,
INTER_CUBIC
);
//要搞成同样的大小才可以检测到
//提取测试样本的HOG特征
HOGDescriptor
*hog =
new
HOGDescriptor
(cvSize(ImgWidht, ImgHeight), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9);
vector
<
float
>descriptors;
//结果数组
hog->compute(trainImg, descriptors,
Size
(1, 1),
Size
(0, 0));
//调用计算函数开始计算
cout
<<
"The Detection Result:"
<<
endl;
cout
<<
"HOG dims: "
<<
descriptors.size()
<<
endl;
//存储所提取的特征
Mat
SVMtrainMat =
Mat
::zeros(1, descriptors.size(),
CV_32FC1
);
n = 0;
for
(
vector
<
float
>::
iterator
iter = descriptors.begin();iter
!=
descriptors.end();iter
++
)
{
SVMtrainMat.at<
float
>(0, n) =
*
iter;
n++;
}
//对提取的特征进行检验
int
ret = svm
->
predict(SVMtrainMat);
if
(ret == 1)
pos++;
else
neg++;
std::sprintf(line,
"%s %d\r\n"
, img_tst_path
[
j
]
.c_str(), ret);
printf(
"%s %d\r\n"
, img_tst_path
[
j
]
.c_str(), ret);
//getchar();
predict_txt
<<
line;
}
sum = neg + pos;
cout
<<
"neg="
<<
neg
<<
"\n"
;
cout
<<
"pos="
<<
pos
<<
"\n"
;
cout
<<
"sum="
<<
sum
<<
"\n"
;
predict_txt.close();
system(
"pause"
);
return
0;
}