问题内容:路面箭头检测与识别(该部分主要介绍基于SVM的分类,也就是识别,检测问题暂不谈)
问题背景:路面箭头识别在无人车中有着重要的作用:
1.车道线等重要信息的检测,需要排除路面箭头的干扰;
2.需要根据路面箭头的指示,完成下一步动作
问题描述:为了简化这个问题,重点描述基于OpenCV的SVM路面箭头分类,我们将预先检测到的待分类 路面箭头给出如下,样本均从俯视图(逆透视)中检测获得:
图片1-11中包括:1-3、10为虚线的误检、4-5为直右箭头、6-9为误检、11为倒着的直左箭头
问题难点(本文中未解决):为何找到一个合适的特征,来解决箭头的旋转不变、尺度不变问题
作者在有限的时间中尝试过Hu矩特征、SIFT特征,效果都不是很理想,具体情况表现为:
Hu矩特征:虽然有旋转不变特性,但是将信息压缩太严重,最后得到的仅是一个七维特征,放入SVM中训练效果很差;
SIFT特征:其也具有尺度和旋转不变性,且对光照不均等现象具有抑制作用,但是作者尝试发现,样本和测试集的特征点检测较少,无法聚类得到定长的特征算子,故无法进行SVM分类
本文采用方法:考虑到路面箭头的形式、形状甚至大小比较单一,仅仅是位置、角度不同,故可以放入较多的模板来反映同一标志不同角度的形态特征,最后将整图信息压缩到固定大小作为特征算子输入SVM中,仍可以取得不错的效果。
样本准备:
不同样式、相同样式不同角度以及负样本,本文采用374个样本。
代码操作:
首先在工程的路径下放入样本集以及测试集,如下图所示sample和test文件夹
上代码:
#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/ml/ml.hpp> #include <opencv2\opencv.hpp> #include "opencv2/core/core.hpp" #include "highgui.h" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/features2d/features2d.hpp" #include "opencv2/nonfree/nonfree.hpp" #include <iostream> #include <time.h> #include "MomentFeature.h" #include <iostream> #include <fstream> #include <iterator> #include <vector> using namespace cv; using namespace std; #define trainnum 374//374 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) /* //标签值,角度未合并 float label[trainnum] = { 1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7, 8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9, 10,10,10,10,10,10,10,10,10,10, 11,11,11,11,11,11,11,11,11,11, 12,12,12,12,12,12,12,12,12,12, 13,13,13,13,13,13,13,13,13,13, 14,14,14,14,14,14,14,14,14,14, 15,15,15,15,15,15,15,15,15,15, 16,16,16,16,16,16,16,16,16,16, 17,17,17,17,17,17,17,17,17,17, 18,18,18,18,18,18,18,18,18,18, 1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9, 4,4,4,4,4,4,4,4,4,4, 6,6,6,6,6,6,6,6,6,6, 8,8,8,8,8,8,8,8,8,8, 3,3,3,3,3,3,3,3,3,3, 6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6, 11,11,11,11,11,11,11,11,11,11, 16,16,16,16,16,16,16,16,16,16, 12,12,12,12,12,12,12,12,12,12, 12,12,12,12,12,12,12,12,12,12, 3,3,3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,3,3, 19,19,19,19,19,19,19,19,19,19, 19,19,19,19,19,19,19,19,19,19, 19,19,19,19,19,19,19,19,19,19, 8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8, 10,10,10,10 }; */ //标签值,角度合并了! float label[trainnum] = { 1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3, 1,1,1,1,1,1,1,1,1,1, 5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5, 8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9, 10,10,10,10,10,10,10,10,10,10, 1,1,1,1,1,1,1,1,1,1, 3,3,3,3,3,3,3,3,3,3, 5,5,5,5,5,5,5,5,5,5, 14,14,14,14,14,14,14,14,14,14, 15,15,15,15,15,15,15,15,15,15, 2,2,2,2,2,2,2,2,2,2, 17,17,17,17,17,17,17,17,17,17, 18,18,18,18,18,18,18,18,18,18, 1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9, 1,1,1,1,1,1,1,1,1,1, 5,5,5,5,5,5,5,5,5,5, 8,8,8,8,8,8,8,8,8,8, 3,3,3,3,3,3,3,3,3,3, 5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5, 1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,3,3, 17,17,17,17,17,17,17,17,17,17, 17,17,17,17,17,17,17,17,17,17, 17,17,17,17,17,17,17,17,17,17, 8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8, 10,10,10,10 }; string labelname[500] = {"左1",//1,4,11 "右1",//2,16 "直右",//3,12 "左2",//4 "直1",//5,6,7,13 "直2",//6 "直3",//7 "虚线",//8 "斑马线1",//9 "斑马线2",//10 "倒左",//11 "倒直右",//12 "倒直",//13 "误检",//14 "误检2",//15 "倒右",//16 "倒直左",//17 "误检3",//18 "直左"//19,17 }; /*---------------------------- * 功能 : 将 cv::Mat 数据写入到 .txt 文件 *---------------------------- * 函数 : WriteData * 访问 : public * 返回 : -1:打开文件失败;0:写入数据成功;1:矩阵为空 * * 参数 : fileName [in] 文件名 * 参数 : matData [in] 矩阵数据 */ int WriteData(string fileName, cv::Mat& matData) { int retVal = 0; // 打开文件 ofstream outFile(fileName.c_str(), ios_base::out); //按新建或覆盖方式写入 if (!outFile.is_open()) { cout << "打开文件失败" << endl; retVal = -1; return (retVal); } // 检查矩阵是否为空 if (matData.empty()) { cout << "矩阵为空" << endl; retVal = 1; return (retVal); } // 写入数据 for (int r = 0; r < matData.rows; r++) { for (int c = 0; c < matData.cols; c++) { if(c != 0) outFile << ","; float data = matData.at<float>(r,c); //读取数据,at<type> - type 是矩阵元素的具体数据格式 outFile << data ; //每列数据用 tab 隔开 } outFile << endl; //换行 } return (retVal); } void floatscale(float* f,int num, int scale) { for(int i = 0; i < num; i++) { f[i]=f[i]*scale; } } int main() { //读取sample中的样本 char filename[200]; Mat sample; Mat train; Mat Hu_train; //读取图片数据,提取特征也在这里! IplImage* ImageGray; float feavec[48]; for(int i = 0; i < trainnum; i++) { sprintf(filename,"sample/%d.jpg",1+i); //*************把图片信息直接放入************ sample = imread(filename,-1); resize(sample,sample,Size(10,70)); sample = sample.reshape(0,1); sample.convertTo(sample, CV_32F); train.push_back(sample); //******************************************* //********zernike特征*********** //ImageGray = cvLoadImage(filename,0); //MomentFeature MF; //MF.SetXStep(1); //MF.SetYStep(3); //MF.SetVecNum(3,9); //////Hu[3] + Zernike[9] //int FeatureLength = MF.GetFeatureLength(); //MF.GetMomentFeature(ImageGray,1,1,feavec); //cout << FeatureLength << endl; //Mat feature(1, 48, CV_32FC1, feavec); //normalize(feature,feature,1.0,0.0,NORM_MINMAX); //train.push_back(feature); //cout << feavec[47] << endl; //feavec为输出特征 //******************************* //********Hu********* //Canny(sample,sample,60,120); //Moments mo; //矩变量 //double M[7];//Hu矩输出 //计算Hu矩 //mo=moments(sample); //HuMoments(mo, M); //cout << M[0] << " " << M[1] << " " << M[2] << " " << M[3] << " " << M[4] << " " << M[5] << " " << M[6] << " " << endl; //Mat Hu(1, 7, CV_64F, M); //train.push_back(Hu); //******************* //*******harris****** //Mat cornerStrength; //cornerHarris(sample, cornerStrength, 2, 3, 0.01); //Mat harrisCorner; //threshold(cornerStrength, harrisCorner, 0.00001, 255, THRESH_BINARY); //imshow("角点检测后的二值效果图", harrisCorner); //waitKey(); //******************* //*******SIFT******** //SIFT sift(10); //vector<KeyPoint> key_points; //特征点 // descriptors为描述符,mascara为掩码矩阵 //Mat descriptors, mascara; //Mat output_img; //输出图像矩阵 //sift(sample,mascara,key_points,descriptors); //执行SIFT运算 //cout << descriptors.cols << " " << descriptors.rows << " " <<(int)key_points.size() << endl; //******************* } //Hu需要reshape以下 //resize(train,train,Size(7,20)); //特征写入txt WriteData("feature_train.txt",train); //导入标签值 Mat labels(trainnum, 1, CV_32FC1, label); cout << train.cols << " " << train.rows << endl; cout << labels.cols << " " << labels.rows << endl; //*********************SVM训练部分*********************** //准备开始训练 CvSVM classifier; CvSVMParams SVM_params; SVM_params.kernel_type = CvSVM::LINEAR; //使用RBF分类非线性问题 SVM_params.svm_type = CvSVM::C_SVC; SVM_params.degree = 0; SVM_params.gamma = 0.01; SVM_params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 1000, FLT_EPSILON); SVM_params.C = 1; SVM_params.coef0 = 0; SVM_params.nu = 0; SVM_params.p = 0.005; //classifier.train(train,labels ,Mat(),Mat(),SVM_params); //SVM训练 //使用调参 //对不用的参数step设为0 //CvParamGrid nuGrid = CvParamGrid(1,1,0.0); //CvParamGrid coeffGrid = CvParamGrid(1,1,0.0); //CvParamGrid degreeGrid = CvParamGrid(1,1,0.0); classifier.train_auto(train,labels ,Mat(),Mat(),SVM_params, 10, classifier.get_default_grid(CvSVM::C), classifier.get_default_grid(CvSVM::GAMMA), classifier.get_default_grid(CvSVM::P), classifier.get_default_grid(CvSVM::NU), classifier.get_default_grid(CvSVM::COEF), classifier.get_default_grid(CvSVM::DEGREE) ); classifier.save("model180.txt"); //****************************************************** //这里载入分类器,方便直接训练 //CvSVM classifier; //classifier.load("model180.txt"); vector<Mat> testdata; //定义测试数据 Mat testmmat; Mat test; int testnum = 11; for(int i = 0; i < testnum; i++) { sprintf(filename,"test/%d.jpg",i+1); //*************直接把图片信息放入*********** test = imread(filename,-1); resize(test,test,Size(10,70)); test = test.reshape(0,1); test.convertTo(test, CV_32FC1); testdata.push_back(test); testmmat.push_back(test); //****************************************** //********zernike特征*********************** //ImageGray = cvLoadImage(filename,0); //MomentFeature MF; //MF.SetXStep(1); //MF.SetYStep(3); //MF.SetVecNum(3,9); //////Hu[3] + Zernike[9] //int FeatureLength = MF.GetFeatureLength(); //MF.GetMomentFeature(ImageGray,1,1,feavec); //cout << FeatureLength << endl; //Mat feature(1, 48, CV_32FC1, feavec); //normalize(feature,feature,1.0,0.0,NORM_MINMAX); //testdata.push_back(feature); //testmmat.push_back(feature); //feavec为输出特征 //****************************************** //********Hu******************* //Canny(test,test,60,120); //Moments mo; //矩变量 //double M[7];//Hu矩输出 //计算Hu矩 //mo=moments(test); //HuMoments(mo, M); //cout << M[0] << " " << M[1] << " " << M[2] << " " << M[3] << " " << M[4] << " " << M[5] << " " << M[6] << " " << endl; //Mat Hu(1, 7, CV_32FC1, M); //testdata.push_back(Hu); //***************************** } WriteData("feature_test.txt",testmmat); char textInImage[200]; //使用训练好的分类器进行预测 for (int i = 0;i < testdata.size() ; ++i) { clock_t start = clock(); int result = (int)classifier.predict(testdata[i]); std::cout<<"测试样本"<<i+1<<"的测试结果为:" <<result<< " " << labelname[result-1] << "\n"; clock_t end = clock(); double tt = static_cast<double>(end - start); sprintf(textInImage, "elapsed time: %5.2f ms", tt); cout << textInImage << endl; } getchar(); }(以上程序注释部分大部分为特征算子的尝试,本文不作介绍,所以注释掉,但是留在这里,有兴趣的可以留言进行研究!同时,将提取的特征写入文件,方便进行其他测试!)
相关推荐
本案例为:Python3+OpenCV+数据人脸采集-人脸识别综合案例环境:Python3.9 OpenCV版本:4.8.1需要电脑有摄像头支持功能:1. 明星人脸采集2. 批量处理人脸数据3. 录入自己人脸4. 训练数据5. 使用训练结果数据6. 适配...
在OpenCV中,我们可以使用`cv2.ml.SVM_create()`创建SVM对象,然后通过设置参数来配置模型,如类型(C-SVM、ν-SVM等)、内核类型(线性、多项式、RBF等)、C值(惩罚系数)和γ值(RBF核的参数)。完成模型配置后,...
在机器学习和计算机视觉项目中,OpenCV和OpenCV_contrib的结合使用能帮助开发者实现诸如图像分类、目标检测、图像分割、人脸识别、全景图拼接、光学字符识别(OCR)等一系列复杂的任务。由于其丰富的功能和跨平台的...
opencv-4.1.1+opencv_contrib-4.1.1+cmake-3.14.5-win64-x64 OpenCV 给第三方编译用的整套环境。 OpenCV源码 + Contrib源码 + CMake 工具。
Qt+openCV学习笔记(十三)openCV4.5.5+android-ndk-r22-windows-x86_64编译的armeabi-v7a动态库 https://blog.csdn.net/aggs1990/article/details/124526728 CSDN审核可能较慢,如无法下载,可以过段时间再回来看...
总的来说,这个项目涵盖了计算机视觉和机器学习的基础应用,通过OpenCV和SVM为不同类型的图像构建分类器。对于初学者来说,这是一个很好的实践项目,可以深入理解图像处理、特征提取和机器学习模型训练的过程。而...
openCV4.6.0+android-ndk-r22-windows-x86_64编译动、静态库(armeabi-v7a) CSDN审核可能较慢,如无法下载,可以过段时间再回来看下 仅供相关爱好者交流使用,请于下载24小时内删除
毕业设计-人脸识别打卡系统-qt + opencv + mysql:sqlite-可执行内含文档代码-可执行内含文档代码.zip
【Python OpenCV+SVM车牌识别系统详解】 在现代信息技术中,车牌识别(License Plate Recognition,LPR)是一项关键的技术,广泛应用于智能交通、停车场管理等领域。本系统利用Python编程语言结合OpenCV计算机视觉...
OpenCV-MinGW-Build-OpenCV-4.5.0-with-contrib
在“opencv+svm实现图像分类代码+训练图.rar”这个项目中,我们可以期待以下几个关键知识点: 1. **图像预处理**:首先,OpenCV可能会被用来对图像进行预处理,包括灰度化、直方图均衡化、尺寸缩放等,以便于后续的...
opencv_python-4.1.2+contrib-cp35-cp35m-win_amd64 python 包 opencv_python-4.1.2+contrib-cp35-cp35m-win_amd64 python 包 opencv_python-4.1.2+contrib-cp35-cp35m-win_amd64 python 包 opencv_python-4.1.2+...
OpenCV 4.5.0是该库的一个版本,包含了丰富的功能和优化,适用于各种计算机视觉应用,如图像识别、物体检测、人脸识别、视频分析等。贡献模块(contrib)是OpenCV中的额外模块,包含了更多实验性和前沿的算法,例如...
opencv 3.1.0 64位DLL链接库opencv-3.1.0-windows-x86_64.jar 和 ffmpeg 3.1.2的64位DLL链接库ffmpeg-3.1.2-windows-x86_64.jar。亲测可用。资源难得,希望对大家有帮助。
VS2019编译的opencv-4.2.0+contrib-4.2.0,支持CUDA,DNN功能。GPU显卡的Compute Capability需>=5.3 编译所用的工具及环境: Cmake-3.17.5 VS2019 opencv-4.2.0 opencv-contrib-4.2.0 cuda-10.1 cudnn-7.6.2 tbb...
OpenCV(开源计算机视觉库)是一个强大的跨平台计算机视觉库,它包含了大量的图像处理和计算机视觉算法,广泛应用于机器学习、图像识别、自动驾驶等领域。在本压缩包“OpenCV-MinGW-Build-OpenCV-4.5.2-x64.zip”中...
赠送jar包:opencv-4.5.5-1.5.7.jar; 赠送原API文档:opencv-4.5.5-1.5.7-javadoc.jar; 赠送源代码:opencv-4.5.5-1.5.7-sources.jar; 赠送Maven依赖信息文件:opencv-4.5.5-1.5.7.pom; 包含翻译后的API文档:...
毕业设计-人脸识别打卡系统qt+opencv+mysql-sqlite.zip 使用技术: qt + opencv + mysql/sqlite 使用说明: /docs/人脸识别打卡系统使用说明.pdf
openCV4.6.0+android-ndk-r22-windows-x86_64编译的arm64-v8a动、静态库 https://blog.csdn.net/aggs1990/article/details/124527556 CSDN审核可能较慢,如无法下载,可以过段时间再回来看下 仅供相关爱好者交流使用...