初识SVM(验证码识别)

之前读了一堆关于SVM的论文,最近终于开始用opencv的SVM来实战了,事实证明果然不能停留于理论,真正实践又花了一定时间,把自己的历程记录如下:

首先来看一下我的main函数:

int main() {
	Mat data_mat, res_mat;
	Mat res;
	vector<string> img_path;
	vector<int> img_catg;
	int nLine = 0;
	
	//loadCatePath(img_path, img_catg, nLine);
		
	//生成测试数据
	//createData(img_path, data_mat, res_mat, res, nLine);

	//生成xml模型
	//createXML(img_path, img_catg, data_mat, res_mat, res, nLine);

	//测试
	testSVM();
	
	//system("pause");
	return 0;
}

由于是第一次写SVM的代码,刚开始写的很乱,后来自己又整理了一下,大致就分为如上流程.
img_path存的是图片的路径,img_catg存的是图片对应的label,然后就先回到loadCatePath函数:

void loadCatePath(vector<string> &img_path, vector<int> &img_catg,  int &nLine) {

	string buf;
	char c[10];

	for (int i = 2; i < 10; ++i) {

		_itoa(i, c, 10);
		string tmp(c);
		string addre = filename + tmp + "/trainpath.txt";
		ifstream svm_data(addre);
		while (svm_data) {
			if (getline(svm_data, buf)) {
				nLine++;
				img_catg.emplace_back(i);
				img_path.emplace_back(buf);
			}
		}
		svm_data.close();
	}
}

我的图片存放在多个文件夹下,文件夹名称从1、2、3一直到9,filename是公共目录,因此我们就可以用如上的方法实现依次读取文件夹,并用对应的label给图片“赋值”。

生成测试数据部分就因人而异了,针对各项目预处理方法都不同,就不多说,然后是生成XML模型部分:

void createXML(vector<string> &img_path, vector<int> &img_catg, Mat &data_mat, Mat &res_mat, Mat &res, int nImgNum) {
	Mat trainImg = Mat::zeros(IMGHEIGHT, IMGWIDTH, CV_8UC3);
	int hogImgWidht = 64, hogImgHeight = 64, n;
	for (string::size_type i = 0; i < img_path.size(); ++i) {
		res = imread(img_path[i].c_str(), 1);
		cout << " processing " << img_path[i].c_str() << endl;
		resize(res, trainImg, cv::Size(hogImgWidht, hogImgHeight), 0, 0, INTER_CUBIC);
		HOGDescriptor *hog = new HOGDescriptor(cvSize(hogImgWidht, hogImgHeight), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9);
		vector<float> descriptors;
		hog->compute(trainImg, descriptors, Size(1, 1), Size(0, 0));
		if (i == 0) {
			data_mat = Mat::zeros(nImgNum, descriptors.size(), CV_32FC1);
		}
		cout << "HOG dims: " << descriptors.size() << endl;
		n = 0;
		for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); ++iter) {
			data_mat.at<float>(i, n) = *iter;
			n++;
		}
		res_mat.at<float>(i, 0) = img_catg[i];
		cout << " end processing " << img_path[i].c_str() << " " << img_catg[i] << endl;
	}

	CvSVM svm;
	CvSVMParams param;
	CvTermCriteria criteria;
	criteria = cvTermCriteria(CV_TERMCRIT_EPS, 1000, FLT_EPSILON);
	param = CvSVMParams(CvSVM::C_SVC, CvSVM::RBF, 10.0, 0.09, 1.0, 10.0, 0.5, 1.0, NULL, criteria);
	svm.train(data_mat, res_mat, Mat(), Mat(), param);
	svm.save("F:/compiler/opencv/forfun/SVM_DATA.xml");
}

都是调用了ML.h中的方法,那几个参数具体的功能还没测试过,之后需要多看一下,最后通过svm.train和svm.svm就在对应路径下生成了xml文件。

既然模型有了,接下来就可以针对我们自己的图片进行测试了:

void testSVM() {
	IplImage *srcImg = cvLoadImage("D:\\other\\verifycode2\\2835.jpg");
	showImage("2835", srcImg);
	IplImage *grayImg = cvCreateImage(cvGetSize(srcImg), IPL_DEPTH_8U, 1);
	//灰度
	grayImage(srcImg, grayImg);
	binary(grayImg);
	cvSmooth(grayImg, grayImg, CV_MEDIAN);
	drawContours(srcImg, grayImg);
	cvReleaseImage(&srcImg);
	cvReleaseImage(&grayImg);
}

这里有几个showImage、grayImage等函数,看名字就知道意思了,重点是在drawContours这里,将原图和处理后的二值图传递过去,因为我这里做的是验证码识别,用到了分割,这一部分的实现过程如下:

	CvSeq* contours = NULL;
	CvMemStorage* storage = cvCreateMemStorage(0);
	cvFindContours(grayImg, storage, &contours, sizeof(CvContour), CV_RETR_EXTERNAL);

	int count = 0;
	int idx = 0;
	int tempCount = 0;
	
	cvSeqSort(contours, cmp_func);

	int z = 0;
	vector<float> descriptors;
	vector<CvRect> v;
	for (CvSeq* c = contours; c != NULL; c = c->h_next) {
		v.emplace_back(cvBoundingRect(c, 0));
	}

	sort(v.begin(), v.end(), mycmp);
	for (int i = 0; i < v.size(); ++i) {
		CvRect rc = v[i];
		if (rc.height > srcImg->width / 10) {
			cvDrawRect(srcImg, cvPoint(rc.x, rc.y), cvPoint(rc.x + rc.width, rc.y + rc.height), CV_RGB(100, 100, 100));
			count++;
			IplImage* resImg = cvCreateImage(cvSize(rc.width, rc.height), srcImg->depth, srcImg->nChannels);
			cvSetImageROI(srcImg, rc);
			cvCopyImage(srcImg, resImg);
			cvResetImageROI(srcImg);
			Mat dstImg = (Mat)resImg;
			resize(dstImg, dstImg, Size(64, 64));
			//测试部分
			
			CvSVM svm;
			svm.load("SVM_DATA.xml");
			HOGDescriptor *hog = new HOGDescriptor(cvSize(64, 64), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9);      
			vector<float>descriptors;//结果数组  
			Mat trainImg = Mat::zeros(64, 64, CV_8UC3);
			resize(dstImg, trainImg, cv::Size(64, 64), 0, 0, INTER_CUBIC);
			hog->compute(trainImg, descriptors, Size(1, 1), Size(0, 0)); //调用计算函数开始计算   
			Mat SVMtrainMat = Mat::zeros(1, descriptors.size(), CV_32FC1);
			int 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);
			cout << ret;
	}
	cvReleaseMemStorage(&storage);
}

以上即为我与SVM的第一次亲密接触,接下来还有许多研究的机会,希望能有更多进展,最后附上我的结果图:
这里写图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值