您的位置:首页 > 运维架构

初识SVM(验证码识别)

2016-10-22 14:22 295 查看
之前读了一堆关于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这里,将原
4000
图和处理后的二值图传递过去,因为我这里做的是验证码识别,用到了分割,这一部分的实现过程如下:

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的第一次亲密接触,接下来还有许多研究的机会,希望能有更多进展,最后附上我的结果图:

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