车辆检测(视觉分类器训练) ------------------原创作品

使用同样的方法,你可以训练自己的识别物体。

一、准备训练数据

训练需要一定数量样本。样本分两类:负样本和正样本。负样本是指不包含物体的图像。正样本是需要检测的物体的图像(最好不要包含其他图像,避免正样本干扰,提高训练正确 性),负样本需要手工准备,大小没有要求,只要不要包含需要检测的物体就行。

正样本可以只要几张,其余的可通过 opencv_createsamples 创建,这个函数是怎么创建其他正样本的呢?通过将现有的图像进行X,Y,Z方向的旋转和背景颜色一系列随机变化产生。

开始正题,首先准备训练数据,创建一个cartraining文件夹,所有的训练工作在里面进行。

1、 负样本准备

负样本照片都放在cartraining/negative_gray目录,负样本最好都是用灰度图像,可提高样本训练速度。若你的图像不是灰度图像,请是用我的图像处理程序,原始图片放在negative文件夹中,处理后的图片会在negative_gray文件夹中生成。

// An highlighted block
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{Mat src_img,gray_image,src_result;int i,j=0;char src_img_name[40]={0},dst_img_name[40]={0};//负样本图像处理,INT PICNUM=100; //需修改下面的图片数量for(i=1;i<=PICNUM;i++){src_img_name[40]={0},dst_img_name[40]={0};sprintf(src_img_name,"cartraining/negative/%d.jpg",i);  cout<<src_img_name<<endl;src_img=imread(src_img_name,1);if(src_img.empty()) continue;cvtColor( src_img, gray_image, CV_BGR2GRAY ); j++;sprintf(dst_img_name,"cartraining/negative_gray/neg_%d.jpg",j);  cout<<"write:"<<dst_img_name<<endl;imwrite(dst_img_name,gray_image);}
}

图片:

在与negative_gray同一级目录创建neg.txt文件,内容包含里面的每张图片;
创建方法可在windows中使用CMD进入dos,在图像目录下 执行dir /b >neg.txt生成neg.txt文件,neg.txt文件在cartraining目录中。然后再替换成如下形式(图像顺序不管):(特别注意 windows下生成的路径与Linux中斜杠方向是相反的

2、 正样本准备

下面准备正样本图片,正样本图片必须满足图片尺寸大小相同,一般为30X30大小,且同样为灰度图片,图片中尽量避免其他物体出现。我的正样本图像存放在cartraining/positive_small_size目录。原始准备的彩色图片在cartraining/positive目录,需要使用我的图片处理程序获得正样本图像:


同样方法准备正样本,在windows中使用CMD进入dos,图像目录下 执行dir /b >pos.txt生成pos.txt文件, pos.txt文件在cartraining目录中。与neg.txt不同的是,后面需要跟一些数据参数,数据参数同样使用替换的方式追加。
下面说下参数意义:1 表示该图片只有一个检测图像,0 0 为检测图像起点 30 30 为检测图像长度和宽度。

3、 获得正样本描述文件
使用opencv_createsamples程序获得正样本描述符。opencv_createsamples 函数的参数如下:
• -vec <vec_file_name>
输出文件,也叫正样本描述文件,后面训练需要。内含用于训练的正样本。
• -img <image_file_name>
输入图像文件名(例如一个公司的标志)。
• -bg <background_file_name>
背景图像的描述文件,文件中包含一系列的图像文件名,这些图像将被随机选作物体的背景。
• -num <number_of_samples>
生成的正样本的数目。
• -bgcolor <background_color>
背景颜色(目前为灰度图);背景颜色表示透明颜色。因为图像压缩可造成颜色偏差,颜色的容差可以由 -bgthresh 指定。所有处于 bgcolor-bgthresh 和 bgcolor+bgthresh 之间的像素都被设置为透明像素。
• -bgthresh <background_color_threshold>
• -inv

如果指定该标志,前景图像的颜色将翻转。
• -randinv
如果指定该标志,颜色将随机地翻转。
• -maxidev <max_intensity_deviation>
前景样本里像素的亮度梯度的最大值。
• -maxxangle <max_x_rotation_angle>
X轴最大旋转角度,必须以弧度为单位。
• -maxyangle <max_y_rotation_angle>
Y轴最大旋转角度,必须以弧度为单位。
• -maxzangle <max_z_rotation_angle>
Z轴最大旋转角度,必须以弧度为单位。
• -show
很有用的调试选项。如果指定该选项,每个样本都将被显示。如果按下 Esc 键,程序将继续创建样本但不再显示。
• -w <sample_width>
输出样本的宽度(以像素为单位)。
• -h <sample_height>
输出样本的高度(以像素为单位)。
使用opencv_createsamples命令获取正样本的样本描述符用于训练,命令如下:

./opencv_createsamples –vec pos.vec –info pos.txt –num  507 –w 30 –h 30

参数说明:–vec pos.vec 用于指定样本描述文件的输出名称
–info pos.txt 正样本信息文件
–num 507 正样本数目为507张
–w 30 –h 30 样本宽度和高度都为30
命令结束后,会生产pos.vec文件,下面将用该文件进行训练。

上述命令是在LINUX中的使用,在windows中方法类似。
进行车辆识别所需要用到的资源如下:
'工具组链接:' https://download.csdn.net/download/xfjy2010/11205487
链接是Linux的训练工具组,包含正样本处理程序(正样本处理程序需要make 命令自己编译)、样本创建程序opencv_createsamples和训练程序opencv_traincascade :

'样本原始资源获取:' https://download.csdn.net/download/xfjy2010/11205471

如果觉得处理样本图片麻烦,当然也有处理好后的样本图片,可以直接用于训练
处理后的可直接用于训练的样本:' https://download.csdn.net/download/xfjy2010/11205479

二、样本训练

训练使用opencv_traincascade 命令,opencv_traincascade 的命令行参数,以用途分组介绍:

  1. 通用参数:
    o -data <cascade_dir_name>
    目录名,如不存在训练程序会创建它,用于存放训练好的分类器。
    o -vec <vec_file_name>
    包含正样本的vec文件名(由 opencv_createsamples 程序生成)。
    o -bg <background_file_name>
    背景描述文件,也就是包含负样本文件名的那个描述文件。
    o -numPos <number_of_positive_samples>
    每级分类器训练时所用的正样本数目。
    o -numNeg <number_of_negative_samples>
    每级分类器训练时所用的负样本数目,可以大于 -bg 指定的图片数目。
    o -numStages <number_of_stages>
    训练的分类器的级数。
    o -precalcValBufSize <precalculated_vals_buffer_size_in_Mb>
    缓存大小,用于存储预先计算的特征值(feature values),单位为MB。
    o -precalcIdxBufSize <precalculated_idxs_buffer_size_in_Mb>
    缓存大小,用于存储预先计算的特征索引(feature indices),单位为MB。内存越大,训练时间越短。
    o -baseFormatSave
    这个参数仅在使用Haar特征时有效。如果指定这个参数,那么级联分类器将以老的格式存储。
  2. 级联参数:
    o -stageType <BOOST(default)>
    级别(stage)参数。目前只支持将BOOST分类器作为级别的类型。
    o -featureType<{HAAR(default), LBP}>
    特征的类型: HAAR - 类Haar特征; LBP - 局部纹理模式特征。
    o -w
    o -h

    训练样本的尺寸(单位为像素)。必须跟训练样本创建(使用 opencv_createsamples 程序创建)时的尺寸保持一致。
    该命令参数很多,用到的就那么几个。

在cartraining目录下执行:

./opencv_traincascade –data  xml  –vec pos.vec –bg neg.txt –numPos 400 –numNeg 1044 –w 30 –h 30

参数说明:
–data xml 训练产生的数据文件到xml文件夹下,在该文件夹下将产生所需的分类器文件,
–vec pos.vec 正样本描述文件
–bg neg.txt 负样本的信息文件
–numPos 400 正样本数目 (注意:数目最好是你所准备的正样本数目的80%左右,原因在于每高一层训练,算法会增加正样本数目,不然后面训练的层级高了以后,就会报错)
–numNeg 1044 负样本数目
–w 30 –h 30 训练样本长宽,必须和创建的正样本一致。

执行训练命令,训练时间为大约为6个小时的样子,训练层级为19层,在xml文件夹下将产生分类器,cascade.xml为我们最终需要的分类器,其他的是中间层级产生的分类器文件。若训练中途断掉,可以使用它们接着训练。


训练好的XML分类器下载:' https://download.csdn.net/download/xfjy2010/11205491

三、效果检验:

正样本数量507张,负样本1044张,得到的分类器效果还是不错,若要达到更好的效果,可以提高样本数量,训练层级也进行提高。

测试代码如下:

#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>using namespace std;
using namespace cv;static void help()
{cout << "\nThis program demonstrates the use of cv::CascadeClassifier class to detect objects (Face + eyes). You can use Haar or LBP features.\n""This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n""It's most known use is for faces.\n""Usage:\n""./facedetect [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n""   [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n""   [--scale=<image scale greater or equal to 1, try 1.3 for example>]\n""   [--try-flip]\n""   [filename|camera_index]\n\n""see facedetect.cmd for one call:\n""./facedetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml\" --scale=1.3\n\n""During execution:\n\tHit any key to quit.\n""\tUsing OpenCV version " << CV_VERSION << "\n" << endl;
}void detectAndDraw( Mat& img, CascadeClassifier& cascade,CascadeClassifier& nestedCascade,double scale, bool tryflip );string cascadeName;
string nestedCascadeName;int main( int argc, const char** argv )
{VideoCapture capture;Mat frame, image;string inputName;bool tryflip;CascadeClassifier cascade, nestedCascade;double scale;cv::CommandLineParser parser(argc, argv,"{help h||}""{cascade|../../../data/haarcascades/haarcascade_frontalface_alt.xml|}""{nested-cascade|../../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml|}"//hogcascade_pedestrians"{scale|1|}{try-flip||}{@filename||}");if (parser.has("help")){help();return 0;}cascadeName = parser.get<string>("cascade");nestedCascadeName = parser.get<string>("nested-cascade");scale = parser.get<double>("scale");if (scale < 1)scale = 1;tryflip = parser.has("try-flip");if(tryflip){cout<<"try_flip"<<endl;}inputName = parser.get<string>("@filename");if (!parser.check()){parser.printErrors();return 0;}if ( !nestedCascade.load( nestedCascadeName ) )cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;cascadeName="cartraining/xml/cascade.xml";if( !cascade.load( cascadeName ) ){cerr << "ERROR: Could not load classifier cascade" << endl;help();return -1;}//image = imread( "lena.jpg", 1 );image = imread( "cartraining/test/timg2.jpg", 1 );if(image.empty()) cout << "Couldn't read ../data/lena.jpg" << endl;if( capture.isOpened() ){cout << "Video capturing has been started ..." << endl;for(;;){capture >> frame;if( frame.empty() )break;Mat frame1 = frame.clone();detectAndDraw( frame1, cascade, nestedCascade, scale, tryflip );char c = (char)waitKey(10);if( c == 27 || c == 'q' || c == 'Q' )break;}}else{cout << "Detecting face(s) in " << inputName << endl;if( !image.empty() ){detectAndDraw( image, cascade, nestedCascade, scale, tryflip );waitKey(0);}else if( !inputName.empty() ){/* assume it is a text file containing thelist of the image filenames to be processed - one per line */FILE* f = fopen( inputName.c_str(), "rt" );if( f ){char buf[1000+1];while( fgets( buf, 1000, f ) ){int len = (int)strlen(buf);while( len > 0 && isspace(buf[len-1]) )len--;buf[len] = '\0';cout << "file " << buf << endl;image = imread( buf, 1 );if( !image.empty() ){detectAndDraw( image, cascade, nestedCascade, scale, tryflip );char c = (char)waitKey(0);if( c == 27 || c == 'q' || c == 'Q' )break;}else{cerr << "Aw snap, couldn't read image " << buf << endl;}}fclose(f);}}}return 0;
}void detectAndDraw( Mat& img, CascadeClassifier& cascade,CascadeClassifier& nestedCascade,double scale, bool tryflip )
{double t = 0;vector<Rect> faces, faces2;const static Scalar colors[] ={Scalar(255,0,0),Scalar(255,128,0),Scalar(255,255,0),Scalar(0,255,0),Scalar(0,128,255),Scalar(0,255,255),Scalar(0,0,255),Scalar(255,0,255)};Mat gray, smallImg;cvtColor( img, gray, COLOR_BGR2GRAY );double fx = 1 / scale;resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT );equalizeHist( smallImg, smallImg );t = (double)getTickCount();cascade.detectMultiScale( smallImg, faces,1.1, 2, 0//|CASCADE_FIND_BIGGEST_OBJECT//|CASCADE_DO_ROUGH_SEARCH|CASCADE_SCALE_IMAGE,Size(30, 30) );if( tryflip ){flip(smallImg, smallImg, 1);cascade.detectMultiScale( smallImg, faces2,1.1, 2, 0//|CASCADE_FIND_BIGGEST_OBJECT//|CASCADE_DO_ROUGH_SEARCH|CASCADE_SCALE_IMAGE,Size(30, 30) );for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r ){faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));}}t = (double)getTickCount() - t;printf( "detection time = %g ms\n", t*1000/getTickFrequency());for ( size_t i = 0; i < faces.size(); i++ ){Rect r = faces[i];Mat smallImgROI;vector<Rect> nestedObjects;Point center;Scalar color = colors[i%8];int radius;double aspect_ratio = (double)r.width/r.height;if( 0.75 < aspect_ratio && aspect_ratio < 1.3 ){center.x = cvRound((r.x + r.width*0.5)*scale);center.y = cvRound((r.y + r.height*0.5)*scale);radius = cvRound((r.width + r.height)*0.25*scale);circle( img, center, radius, color, 3, 8, 0 );}elserectangle( img, cvPoint(cvRound(r.x*scale), cvRound(r.y*scale)),cvPoint(cvRound((r.x + r.width-1)*scale), cvRound((r.y + r.height-1)*scale)),color, 3, 8, 0);if( nestedCascade.empty() )continue;smallImgROI = smallImg( r );nestedCascade.detectMultiScale( smallImgROI, nestedObjects,1.1, 2, 0//|CASCADE_FIND_BIGGEST_OBJECT//|CASCADE_DO_ROUGH_SEARCH//|CASCADE_DO_CANNY_PRUNING|CASCADE_SCALE_IMAGE,Size(30, 30) );for ( size_t j = 0; j < nestedObjects.size(); j++ ){Rect nr = nestedObjects[j];center.x = cvRound((r.x + nr.x + nr.width*0.5)*scale);center.y = cvRound((r.y + nr.y + nr.height*0.5)*scale);radius = cvRound((nr.width + nr.height)*0.25*scale);circle( img, center, radius, color, 3, 8, 0 );}}imshow( "result", img );
}


原创作品,转载请注明出处。。。。

车辆检测(视觉分类器训练)相关推荐

  1. 《预训练周刊》第9期:TABBIE:表格数据的预训练表示、「视觉预训练神作」:不用图片却训出图像识别SOTA?...

    No.09 智源社区 预训练组 预 训 练 研究 观点 资源 活动 关于周刊 超大规模预训练模型是当前人工智能领域研究的热点,为了帮助研究与工程人员了解这一领域的进展和资讯,智源社区整理了第9期< ...

  2. 【CVPR2022】UniVIP:自监督视觉预训练的统一框架

    来源:专知 本文为论文,建议阅读5分钟 我们提出了统一自监督视觉预训练(UniVIP) 论文标题:UniVIP: A Unified Framework for Self-Supervised Vis ...

  3. 级联分类器训练及其参数的含义

    转载自:级联分类器训练 - OpenCV 2.3.2 documentation http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/user_guid ...

  4. 【OpenCV3】级联分类器训练——traincascade快速使用详解

    上一篇(OpenCV3中的级联分类器目标检测--cv::CascadeClassifier简介)介绍了如何使用级联分类器进行目标检测.这里,我们介绍一下如何训练自己的级联分类器. 至于原理这里就不再进 ...

  5. HALCON示例程序train_characters_ocr.hdev使用SVM分类器训练字体

    HALCON示例程序train_characters_ocr.hdev使用SVM分类器训练字体 小哥哥小姐姐觉得有用点个赞呗! 示例程序源码(加注释) 蓝色字体均为算子解释链接,可以前往查看解答 关于 ...

  6. 思维碰撞!谷歌提出ViTGAN,用视觉Transformer训练GAN

    点上方计算机视觉联盟获取更多干货 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:新智元 AI博士笔记系列推荐 周志华<机器学习>手推笔记正式开源!可打印版本附pdf下载链接 卷积 ...

  7. 4项探索+4项实践,带你了解华为云视觉预训练研发技术

    摘要:本文主要讲述云原生时代华为云在AI基础研究.视觉预训练模型研发和行业实践,以及AI开发平台ModelArts的最新进展. 近日,在Qcon全球软件开发大会(深圳站)上,华为云人工智能领域首席科学 ...

  8. OpenFace人脸分类器训练

    本篇文章关于OpenFace人脸分类器训练,默认已经安装好了OpenFace和其他的依赖关系,如何配置可见上一篇文章. 参考文章 如有雷同,绝非巧合 1.准备素材 人脸原图,每个图包含一个人脸,每个人 ...

  9. 通用视觉预训练大模型巡礼系列(一):UFO大模型

    ©PaperWeekly 原创 · 作者 | 张燚钧 单位 | 中国移动云能力中心 研究方向 | 预训练大模型 近来,以 ChatGPT 为代表的自然语言对话大模型,以及以 Stable Diffus ...

最新文章

  1. 你还在百度这些代码吗?
  2. python 用命令安装pip_利用Python的pip命令安装nump
  3. JSON转换为excel工具
  4. 分享几个益智题......看你能做对吗?
  5. HDU2504 又见GCD
  6. 07版qq默认经典表情下载
  7. java怎么格式化日期_java 时间格式化各种方法
  8. java读取pdf多表格_怎么用java读取pdf中的表格
  9. 什么是短信接口API
  10. 电脑变wifi 用电脑建立无线网
  11. HMM, CTC和RNN-Transducer对齐方式的差异
  12. 数据库设计4-概念结构设计
  13. 无线传感器网络实验与作业总结
  14. [ Linux ] 零散文件系统安装各种命令和软件的方法
  15. 【数据分析师_02_SQL+MySQL】022_MySQL的全文检索(MyISAM,MATCH AGAINST)
  16. 小程序毕设作品之微信美食菜谱小程序毕业设计成品(3)后台功能
  17. Maven的下载以及安装
  18. matlab的函数库,matlab函数库大全
  19. 三件让人幸福的事情:有人爱,有事做,有所期待 转自俞敏洪的新浪微博
  20. 物联网的安全问题引起争论,这些威胁有待解决...

热门文章

  1. 哔咔服务器无响应,哔咔哔咔漫画进不去怎么办 无法进入解决办法
  2. 什么叫模拟量和数字量
  3. BIOS设置 硬盘热插拔功能
  4. Linux命令--tail
  5. 感知机算法基础形式及对偶形式算法
  6. 六、React(Component)
  7. 一文了解半导体的过去、现在和未来
  8. Windows下运行XServer,XServer和XClient
  9. 善用“天时、地利、人和”,项目经理才能更有底气地要人要资源
  10. html 输入框变红色,为什么CAD的动态输入框变成红色?