想实现一个SVM分类器,在网上找了好久,都不能编译,心态要崩了,下楼去跑了一会儿步,才恢复过来。最后找到了一个博客,实现成功了。
根据网上的教程,我复现了一遍,详见该博客https://blog.csdn.net/wf15725243865/article/details/80894132
这期间,我遇到了几个很蠢的问题。
1.一个项目下我编写了多个main函数,当然出错啦
2.别人博客上选取的图片是28*28的,我的图片大小是20*20的,对应的参数需要修改。
HOGDescriptor *hog=new HOGDescriptor(cvSize(20,20),cvSize(10,10),cvSize(5,5),cvSize(5,5),9);
里面的参数依此为WinSize,BlockSize,StrideSize,CellSize,
data_mat = cvCreateMat( nImgNum, 324, CV_32FC1 );
这一句中,第二个参数,即矩阵的列是由下面的descriptors的大小决定的,可以由descriptors.size()得到,且对于不同大小的输入训练图片,这个值是不同的,此处324=nbins*(blocksize.width/cellsize.width)*(blocksize.height/cellsize.height)*((winsize.width-blocksize.width)/blocksize.width+1)*((winsize.height-blocksize.height)/blocksize.height+1)=9*2*2*3*3
3.批量处理数据时我学到了新方法,虽然这种方法很多哈,但我这个菜鸡以前没做过不会呀。具体是在图片文件夹下运行cmd,进入命令提示符,cd f:,进入相应文件夹,输入dir /b > test.txt 可生成图片名的文件,将最后一行删掉。用notepad++软件给图片名前面加上路径,编辑>列块编辑>添加路径,即可在每一行前面加上路径,每一行后面添加可以使用如下方法:使用快捷键CTRL+F替换功能,点击正则表达式,将$(每行的结尾)替换成"需要添加的内容",将^(每行开头)替换为“想添加的内容”。间隔添加空行,可将\n替换为\n\n;我还遇到一个很蠢的问题,需要在偶数空白行添加标签,我只能先将\n替换为\n0,将0F替换为F
希望自己继续坚持吧!
具体程序如下:
//#include "stdafx.h"
#include "opencv2/opencv.hpp"
#include "windows.h"
#include "fstream"
#include
using namespace std;
using namespace cv;
int _tmain(int argc, _TCHAR* argv[])
{
vector img_path;//输入文件名变量
vector img_catg;
int nLine = 0;
string buf;
ifstream svm_data( "F:/data train/train.txt" );//训练样本图片的路径都写在这个txt文件中,使用bat批处理文件可以得到这个txt文件
unsigned long n;
while( svm_data )//将训练样本文件依次读取进来
{
if( getline( svm_data, buf ) ) //第一个参数表示输入流,第二个参数表示存放的字符串,第三个参数如果默认表示遇到回车就停止
{
nLine ++;
if( nLine % 2 == 0 )//注:奇数行是图片全路径,偶数行是标签
{
img_catg.push_back( atoi( buf.c_str() ) );//atoi将字符串转换成整型,标志(0,1,2,...,9),注意这里至少要有两个类别,否则会出错
}
else
{
img_path.push_back( buf );//图像路径
}
}
}
svm_data.close();//关闭文件
CvMat *data_mat, *res_mat;
int nImgNum = nLine / 2; //nImgNum是样本数量,只有文本行数的一半,另一半是标签
data_mat = cvCreateMat( nImgNum, 324, CV_32FC1 ); //第二个参数,即矩阵的列是由下面的descriptors的大小决定的,可以由descriptors.size()得到,且对于不同大小的输入训练图片,这个值是不同的
//此处324=nbins*(blocksize.width/cellsize.width)*(blocksize.height/cellsize.height)*((winsize.width-blocksize.width)/blocksize.width+1)*((winsize.height-blocksize.height)/blocksize.height+1)=9*2*2*3*3
cvSetZero( data_mat );
//类型矩阵,存储每个样本的类型标志
res_mat = cvCreateMat( nImgNum, 1, CV_32FC1 );
cvSetZero( res_mat );
IplImage* src;
IplImage* trainImg=cvCreateImage(cvSize(20,20),8,3);//需要分析的图片,这里默认设定图片是28*28大小,所以上面定义了324,如果要更改图片大小,可以先用debug查看一下descriptors是多少,然后设定好再运行
//处理HOG特征
for( string::size_type i = 0; i != img_path.size(); i++ )
{
src=cvLoadImage(img_path[i].c_str(),1);
if( src == NULL )
{
cout<<" can not load the image: "<descriptors;//存放结果
hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); //Hog特征计算
cout<<"HOG dims: "<::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
{
cvmSet(data_mat,i,n,*iter);//存储HOG特征
n++;
}
cvmSet( res_mat, i, 0, img_catg[i] );
cout<<" 处理完毕: "< img_tst_path;
ifstream img_tst( "F:/data test/test.txt" ); //加载需要预测的图片集合,这个文本里存放的是图片全路径,不要标签,ifstream表示读文件
while( img_tst )
{
if( getline( img_tst, buf ) )
{
img_tst_path.push_back( buf );
}
}
img_tst.close();
ofstream predict_txt( "SVM_PREDICT.txt" );//把预测结果存储在这个文本中 ,ofstream表示写文件
for( string::size_type j = 0; j != img_tst_path.size(); j++ )//依次遍历所有的待检测图片
{
test = cvLoadImage( img_tst_path[j].c_str(), 1);
if( test == NULL )
{
cout<<" can not load the image: "<descriptors;//结果数组
hog->compute(trainTempImg, descriptors,Size(1,1), Size(0,0));
cout<<"HOG dims: "<::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
{
cvmSet(SVMtrainMat,0,n,*iter);
n++;
}
int ret = svm.predict(SVMtrainMat);//检测结果
sprintf( result, "%s %d\r\n",img_tst_path[j].c_str(),ret );
predict_txt<
#include "opencv2/opencv.hpp"
#include "windows.h"
#include "fstream"
#include
using namespace std;
using namespace cv;
int _tmain(int argc, _TCHAR* argv[])
{
CvSVM svm;
svm.load("F:\\VS2010\\TEST\\test5\\test5\\HOG_SVM_DATA.xml");//加载训练好的xml文件,这里训练的是10K个手写数字
//检测样本
IplImage *test;
char result[300]; //存放预测结果
test = cvLoadImage("1.png", 1); //待预测图片,用系统自带的画图工具随便手写
if (!test)
{
MessageBox(NULL,TEXT("待预测图像不存在!"),TEXT("提示"),MB_ICONWARNING);
return -1;
}
IplImage* trainTempImg=cvCreateImage(cvSize(20,20),8,3);
cvZero(trainTempImg);
cvResize(test,trainTempImg);
HOGDescriptor *hog=new HOGDescriptor(cvSize(20,20),cvSize(10,10),cvSize(5,5),cvSize(5,5),9);
vectordescriptors;//存放结果
hog->compute(trainTempImg, descriptors,Size(1,1), Size(0,0)); //Hog特征计算
cout<<"HOG dims: "<::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
{
cvmSet(SVMtrainMat,0,n,*iter);
n++;
}
int ret = svm.predict(SVMtrainMat);//检测结果
sprintf(result, "%d\r\n",ret );
cvNamedWindow("dst",1);
cvShowImage("dst",test);
MessageBox(NULL,result,TEXT("预测结果"),MB_OK);
cvReleaseImage(&test);
cvReleaseImage(&trainTempImg);
return 0;
}