最近跟着老师做一个交通识别的项目, 总算明白了一个道理, 这水啊, 不去亲自蹚上一遭就不知道有多深, 更根本的原因当然还是自己学的不够扎实, 不够好.
经过了一个寒假的折磨,终于做出了一个原型来, 想到了自己当时被折磨的头疼的样子,想着将一部分源代码发上来, 希望可以帮助到别人.
呵呵,废话不多说了
这里我发的是一个手写字符识别的程序(这是在编写交通标志的过程中产生的,因为当时手头的交通标志的样本够,所以从网上下载了手写字符的样本库来测试SVM)
//添加使用到的头文件 #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <opencv2/ml/ml.hpp> #include <iostream> #include <fstream> #include "stdlib.h" //声明命名空间 using namespace std; using namespace cv; using namespace cv::ml; //!训练数据参数 const int sample_num_perclass = 40; //训练每类图片数量 const int class_num = 3; //训练类数 //!所有图片尺寸归一化 const int image_cols = 16; //定义图片尺寸 const int image_rows = 28; //定义图片尺寸 //!生成的训练文件保存位置 char SVMName[40] = "SVM.xml"; //分类器的训练生成的名字,读取时也按照这个名字来 #define RW 1 //0为读取现有的分类器,1表示重新训练一个分类器 //!读取的图像的路径 char path[40] = "/home/aimer/Desktop/test2.png"; //!程序入口 double Hu[7]; //存储得到的Hu矩阵 Moments mo; //矩变量 cv::Size size = cv::Size(image_cols, image_rows); int main(void) { #if RW //!读取训练数据 Mat trainingData = Mat::zeros(sample_num_perclass*class_num, 7, CV_32FC1); //填入图像的7个Hu矩 Mat trainingLabel = Mat::zeros(sample_num_perclass*class_num, 1, CV_32SC1); char buf[50]; //字符缓冲区 for(int i=0;i<class_num;i++) //不同了类的循环 { for(int j=0;j<sample_num_perclass;j++) //一个类中的图片数量 { //!生成图片的路径(不同类的图片被放在了不同的文件夹下) sprintf(buf, "/home/aimer/Desktop/charSamples/%d/%d.png", i, j+1); //!读取 Mat src = imread(buf, 0); //!重设尺寸(归一化) Mat reImg; resize(src, reImg, size, CV_INTER_CUBIC); Mat canny; Canny(reImg, canny, 200, 120); //!求Hu矩 mo = moments(canny); HuMoments(mo, Hu); //!将Hu矩填入训练数据集里 float *dstPoi = trainingData.ptr<float>(i*sample_num_perclass+j); //指向源的指针 for(int r=0;r<7;r++) dstPoi[r] = (float)Hu[r]; //!添加对该数据的分类标签 int *labPoi = trainingLabel.ptr<int>(i*sample_num_perclass+j); labPoi[0] = i; } } imwrite("res.png", trainingData); //!创建SVM支持向量机并训练数据 Ptr<SVM> svm = SVM::create(); svm->setType(SVM::C_SVC); svm->setC(0.01); svm->setKernel(SVM::LINEAR); svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 10000, 1e-6)); svm->train(trainingData, ROW_SAMPLE, trainingLabel); svm->save(SVMName); #else //读取xml文件 Ptr<SVM> svm=SVM::load<SVM>(SVMName); #endif //!读取一副图片进行测试 Mat temp = imread("/home/aimer/Desktop/test2.png", 0); Mat dst; resize(temp, dst, size, CV_INTER_CUBIC); Mat canny; Canny(dst, canny, 200, 120); mo = moments(canny); HuMoments(mo, Hu); Mat pre(1, 7, CV_32FC1); float *p = pre.ptr<float>(0); for(int i=0;i<7;i++) p[i] = Hu[i]; float res = svm->predict(pre); cout<<res<<endl; return 0; }
整体思路是:读取图片(程序没有做灰度处理,因为读取到的时候就是灰度图了,与imread的参数有关),然后归一化,求出七个不变矩,然后填充样进行训练,训练完成后读取一幅图片进行测试.
环境为:Ubuntu 16.04 64位+OpenCV 3.1.0+Qt 4.8
注意一点的是:素材文件夹下面的图片名字要改成数字(每个文件下的文件名从1开始,例如:1.png;并且不能断开,例如:1.png,3.png这是不允许的,程序中被没有加入这些判断检测程序,可以选择自己加上这些代码,这样就免去了对文件重命名的烦恼)
样本的链接:
链接:http://pan.baidu.com/s/1pLPeZkZ 密码:26eb
感谢这位网上大咖, 看了他的文章对望帮助很大, 再次感谢
http://www.cnblogs.com/ronny/p/opencv_road_more_01.html
这是他写的关于神经网络识别车牌号的代码