SVM+HOG识别数字

想实现一个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;

}

 

你可能感兴趣的:(opencv)