diff --git a/.gitignore b/.gitignore index 8ddd2d0..12f42a4 100644 --- a/.gitignore +++ b/.gitignore @@ -78,6 +78,7 @@ ipch/ *.psess *.vsp *.vspx +*.suo # TFS 2012 Local Workspace $tf/ diff --git a/EasyPR.v12.vcxproj b/EasyPR.v12.vcxproj new file mode 100644 index 0000000..e9eb5c2 --- /dev/null +++ b/EasyPR.v12.vcxproj @@ -0,0 +1,128 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {62ADD040-59C5-4D8E-A065-8C5D0CD777BE} + Win32Proj + EasyPR + + + + Application + true + Unicode + v120 + + + Application + false + true + Unicode + v120 + + + + + + + + + + + + + + + true + + + false + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + stdafx.h + MultiThreadedDebug + + + Console + true + D:\libs\opencv\build\x86\vc12\lib;%(AdditionalLibraryDirectories) + opencv_calib3d249d.lib;opencv_contrib249d.lib;opencv_core249d.lib;opencv_features2d249d.lib;opencv_flann249d.lib;opencv_gpu249d.lib;opencv_highgui249d.lib;opencv_imgproc249d.lib;opencv_legacy249d.lib;opencv_ml249d.lib;opencv_nonfree249d.lib;opencv_objdetect249d.lib;opencv_ocl249d.lib;opencv_photo249d.lib;opencv_stitching249d.lib;opencv_superres249d.lib;opencv_ts249d.lib;opencv_video249d.lib;opencv_videostab249d.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EasyPR.v12.vcxproj.filters b/EasyPR.v12.vcxproj.filters new file mode 100644 index 0000000..ebe558f --- /dev/null +++ b/EasyPR.v12.vcxproj.filters @@ -0,0 +1,123 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 资源文件 + + + 资源文件 + + + 资源文件 + + + + + + + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + \ No newline at end of file diff --git a/src/core/chars_identify.cpp b/src/core/chars_identify.cpp index 1886d50..b2ffff5 100644 --- a/src/core/chars_identify.cpp +++ b/src/core/chars_identify.cpp @@ -9,20 +9,20 @@ namespace easypr{ #define VERTICAL 0 #define NDEBUG -//й +//中国车牌 const char strCharacters[] = {'0','1','2','3','4','5',\ - '6','7','8','9','A','B', 'C', 'D', 'E','F', 'G', 'H', /* ûI */\ - 'J', 'K', 'L', 'M', 'N', /* ûO */ 'P', 'Q', 'R', 'S', 'T', \ + '6','7','8','9','A','B', 'C', 'D', 'E','F', 'G', 'H', /* 没有I */\ + 'J', 'K', 'L', 'M', 'N', /* 没有O */ 'P', 'Q', 'R', 'S', 'T', \ 'U','V', 'W', 'X', 'Y', 'Z'}; -const int numCharacter = 34; /* ûI0,1024Ӣַ֮ */ +const int numCharacter = 34; /* 没有I和0,10个数字与24个英文字符之和 */ -//¶ѵʱõַݣȫ棬Щʡûѵûַ -const string strChinese[] = {"zh_cuan" /* */, "zh_e" /* */, "zh_gan" /* */, \ - "zh_hei" /* */, "zh_hu" /* */, "zh_ji" /* */, \ - "zh_jl" /* */, "zh_jin" /* */, "zh_jing" /* */, "zh_shan" /* */, \ - "zh_liao" /* */, "zh_lu" /* ³ */, "zh_min" /* */, "zh_ning" /* */, \ - "zh_su" /* */, "zh_sx" /* */, "zh_wan" /* */,\ - "zh_yu" /* ԥ */, "zh_yue" /* */, "zh_zhe" /* */}; +//以下都是我训练时用到的中文字符数据,并不全面,有些省份没有训练数据所以没有字符 +const string strChinese[] = {"zh_cuan" /* 川 */, "zh_e" /* 鄂 */, "zh_gan" /* 赣*/, \ + "zh_hei" /* 黑 */, "zh_hu" /* 沪 */, "zh_ji" /* 冀 */, \ + "zh_jl" /* 吉 */, "zh_jin" /* 津 */, "zh_jing" /* 京 */, "zh_shan" /* 陕 */, \ + "zh_liao" /* 辽 */, "zh_lu" /* 鲁 */, "zh_min" /* 闽 */, "zh_ning" /* 宁 */, \ + "zh_su" /* 苏 */, "zh_sx" /* 晋 */, "zh_wan" /* 皖 */,\ + "zh_yu" /* 豫 */, "zh_yue" /* 粤 */, "zh_zhe" /* 浙 */}; const int numChinese = 20; const int numAll = 54; /* 34+20=54 */ @@ -36,26 +36,26 @@ CCharsIdentify::CCharsIdentify() if (m_map.empty()) { - m_map.insert(pair("zh_cuan","")); - m_map.insert(pair("zh_e","")); - m_map.insert(pair("zh_gan","")); - m_map.insert(pair("zh_hei","")); - m_map.insert(pair("zh_hu","")); - m_map.insert(pair("zh_ji","")); - m_map.insert(pair("zh_jl","")); - m_map.insert(pair("zh_jin","")); - m_map.insert(pair("zh_jing","")); - m_map.insert(pair("zh_shan","")); - m_map.insert(pair("zh_liao","")); - m_map.insert(pair("zh_lu","³")); - m_map.insert(pair("zh_min","")); - m_map.insert(pair("zh_ning","")); - m_map.insert(pair("zh_su","")); - m_map.insert(pair("zh_sx","")); - m_map.insert(pair("zh_wan","")); - m_map.insert(pair("zh_yu","ԥ")); - m_map.insert(pair("zh_yue","")); - m_map.insert(pair("zh_zhe","")); + m_map.insert(pair("zh_cuan","川")); + m_map.insert(pair("zh_e","鄂")); + m_map.insert(pair("zh_gan","赣")); + m_map.insert(pair("zh_hei","黑")); + m_map.insert(pair("zh_hu","沪")); + m_map.insert(pair("zh_ji","冀")); + m_map.insert(pair("zh_jl","吉")); + m_map.insert(pair("zh_jin","津")); + m_map.insert(pair("zh_jing","京")); + m_map.insert(pair("zh_shan","陕")); + m_map.insert(pair("zh_liao","辽")); + m_map.insert(pair("zh_lu","鲁")); + m_map.insert(pair("zh_min","闽")); + m_map.insert(pair("zh_ning","宁")); + m_map.insert(pair("zh_su","苏")); + m_map.insert(pair("zh_sx","晋")); + m_map.insert(pair("zh_wan","皖")); + m_map.insert(pair("zh_yu","豫")); + m_map.insert(pair("zh_yue","粤")); + m_map.insert(pair("zh_zhe","浙")); } } @@ -72,7 +72,7 @@ void CCharsIdentify::LoadModel(string s) ann.load(s.c_str(), "ann"); } -//create the accumulation histograms,img is a binary image, t is ˮƽֱ +//create the accumulation histograms,img is a binary image, t is 水平或垂直 Mat CCharsIdentify::ProjectedHistogram(Mat img, int t) { int sz=(t)?img.rows:img.cols; @@ -80,7 +80,7 @@ Mat CCharsIdentify::ProjectedHistogram(Mat img, int t) for(int j=0; j(j)=countNonZero(data); //ͳһлһУԪصĸ浽mhist + mhist.at(j)=countNonZero(data); //统计这一行或一列中,非零元素的个数,并保存到mhist中 } //Normalize histogram @@ -88,12 +88,12 @@ Mat CCharsIdentify::ProjectedHistogram(Mat img, int t) minMaxLoc(mhist, &min, &max); if(max>0) - mhist.convertTo(mhist,-1 , 1.0f/max, 0);//mhistֱͼеֵһֱͼ + mhist.convertTo(mhist,-1 , 1.0f/max, 0);//用mhist直方图中的最大值,归一化直方图 return mhist; } -//! ַͼ +//! 获得字符的特征图 Mat CCharsIdentify::features(Mat in, int sizeData) { //Histogram features @@ -109,7 +109,7 @@ Mat CCharsIdentify::features(Mat in, int sizeData) Mat out = Mat::zeros(1, numCols, CV_32F); - //Asign values to feature,ANNΪˮƽֱֱͼ͵ͷֱͼɵʸ + //Asign values to feature,ANN的样本特征为水平、垂直直方图和低分辨率图像所组成的矢量 int j=0; for(int i=0; i matVec; string plateIdentify = ""; @@ -33,7 +33,7 @@ int CCharsRecognise::charsRecognise(Mat plate, string& plateLicense) Mat charMat = matVec[j]; bool isChinses = false; - //Ĭ׸ַַ + //默认首个字符块是中文字符 if (j == 0) isChinses = true; diff --git a/src/core/chars_segment.cpp b/src/core/chars_segment.cpp index c982be8..2206df4 100644 --- a/src/core/chars_segment.cpp +++ b/src/core/chars_segment.cpp @@ -14,7 +14,7 @@ CCharsSegment::CCharsSegment() m_LiuDingSize = DEFAULT_LIUDING_SIZE; m_theMatWidth = DEFAULT_MAT_WIDTH; - //ɫжϲ + //!车牌颜色判断参数 m_ColorThreshold = DEFAULT_COLORTHRESHOLD; m_BluePercent = DEFAULT_BLUEPERCEMT; m_WhitePercent = DEFAULT_WHITEPERCEMT; @@ -22,7 +22,7 @@ CCharsSegment::CCharsSegment() m_debug = DEFAULT_DEBUG; } -//! ַߴ֤ +//! 字符尺寸验证 bool CCharsSegment::verifySizes(Mat r){ //Char sizes 45x90 float aspect=45.0f/90.0f; @@ -46,12 +46,12 @@ bool CCharsSegment::verifySizes(Mat r){ return false; } -//! ַԤ +//! 字符预处理 Mat CCharsSegment::preprocessChar(Mat in){ //Remap image int h=in.rows; int w=in.cols; - int charSize=CHAR_SIZE; //ͳһÿַĴС + int charSize=CHAR_SIZE; //统一每个字符的大小 Mat transformMat=Mat::eye(2,3,CV_32F); int m=max(w,h); transformMat.at(0,2)=m/2 - w/2; @@ -66,7 +66,7 @@ Mat CCharsSegment::preprocessChar(Mat in){ return out; } -//! ֱͼ⣬Ϊжϳɫ׼ +//! 直方图均衡,为判断车牌颜色做准备 Mat CCharsSegment::histeq(Mat in) { Mat out(in.size(), in.type()); @@ -88,8 +88,8 @@ Mat CCharsSegment::histeq(Mat in) } //getPlateType -//жϳƵͣ1Ϊƣ2Ϊƣ0Ϊδ֪Ĭ -//ͨɫռĶжϣ0.3ΪƣΪ +//判断车牌的类型,1为蓝牌,2为黄牌,0为未知,默认蓝牌 +//通过像素中蓝色所占比例的多少来判断,大于0.3为蓝牌,否则为黄牌 int CCharsSegment::getPlateType(Mat input) { Mat img; @@ -129,9 +129,9 @@ int CCharsSegment::getPlateType(Mat input) } //clearLiuDing -//ȥϷť -//ÿԪصĽԾСXΪȫ0Ϳڣ -//XƼֵΪɸʵʵ +//去除车牌上方的钮钉 +//计算每行元素的阶跃数,如果小于X认为是柳丁,将此行全部填0(涂黑) +//X的推荐值为,可根据实际调整 Mat CCharsSegment::clearLiuDing(Mat img) { const int x = m_LiuDingSize; @@ -159,13 +159,13 @@ Mat CCharsSegment::clearLiuDing(Mat img) return img; } -//! ַָ +//! 字符分割与排序 int CCharsSegment::charsSegment(Mat input, vector& resultVec) { if( !input.data ) { return -3; } - //жϳɫԴȷthreshold + //判断车牌颜色以此确认threshold方法 int plateType = getPlateType(input); cvtColor(input, input, CV_RGB2GRAY); @@ -183,7 +183,7 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec) imwrite(ss.str(), img_threshold); } - //ȥϷԼ·ĺߵȸ + //去除车牌上方的柳钉以及下方的横线等干扰 clearLiuDing(img_threshold); @@ -209,7 +209,7 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec) vector vecRect; //Remove patch that are no inside limits of aspect ratio and area. - //ضߴͼųȥ + //将不符合特定尺寸的图块排除出去 while (itc != contours.end()) { Rect mr = boundingRect(Mat(*itc)); @@ -225,11 +225,11 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec) return -3; vector sortedRect; - //Էϳߴͼ鰴մҽ + //对符合尺寸的图块按照从左到右进行排序 SortRect(vecRect, sortedRect); int specIndex = 0; - //ָʾеضRect,A"A" + //获得指示城市的特定Rect,如苏A的"A" specIndex = GetSpecificRect(sortedRect); if(m_debug) @@ -243,9 +243,9 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec) } } - //ضRectƳַ - //ҪԭǸfindContoursѲ׽ַ׼ȷRect˽ - //˹ض㷨ָ + //根据特定Rect向左反推出中文字符 + //这样做的主要原因是根据findContours方法很难捕捉到中文字符的准确Rect,因此仅能 + //退过特定算法来指定 Rect chineseRect; if (specIndex < sortedRect.size()) chineseRect = GetChineseRect(sortedRect[specIndex]); @@ -261,9 +261,9 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec) } - //½һȫµRect - //ַRectһӽΪ϶ߵ - //Rectֻ˳ȥ6ֻ7ַԱӰµġ1ַ + //新建一个全新的排序Rect + //将中文字符Rect第一个加进来,因为它肯定是最左边的 + //其余的Rect只按照顺序去6个,车牌只可能是7个字符!这样可以避免阴影导致的“1”字符 vector newSortedRect; newSortedRect.push_back(chineseRect); RebuildRect(sortedRect, newSortedRect, specIndex); @@ -292,7 +292,7 @@ int CCharsSegment::charsSegment(Mat input, vector& resultVec) return 0; } -//! Rectλôҽ +//! 将Rect按位置从左到右进行排序 int CCharsSegment::SortRect(const vector& vecRect, vector& out) { vector orderIndex; @@ -336,7 +336,7 @@ int CCharsSegment::SortRect(const vector& vecRect, vector& out) return 0; } -//! ⳵²ַλúʹС +//! 根据特殊车牌来构造猜测中文字符的位置和大小 Rect CCharsSegment::GetChineseRect(const Rect rectSpe) { int height = rectSpe.height; @@ -352,7 +352,7 @@ Rect CCharsSegment::GetChineseRect(const Rect rectSpe) return a; } -//! ҳָʾеַRectA7003X"A"λ +//! 找出指示城市的字符的Rect,例如苏A7003X,就是"A"的位置 int CCharsSegment::GetSpecificRect(const vector& vecRect) { vector xpositions; @@ -379,7 +379,7 @@ int CCharsSegment::GetSpecificRect(const vector& vecRect) Rect mr = vecRect[i]; int midx = mr.x + mr.width/2; - //һַһĴСƵ1/72/7֮䣬Ҫҵ⳵ + //如果一个字符有一定的大小,并且在整个车牌的1/7到2/7之间,则是我们要找的特殊车牌 if ((mr.width > maxWidth * 0.8 || mr.height > maxHeight * 0.8) && (midx < int(m_theMatWidth / 7) * 2 && midx > int(m_theMatWidth / 7) * 1)) { @@ -390,17 +390,17 @@ int CCharsSegment::GetSpecificRect(const vector& vecRect) return specIndex; } -//! -// 1.ַRectߵȫRectȥؽַλá -// 2.ַRectʼѡ6Rectȥ +//! 这个函数做两个事情 +// 1.把特殊字符Rect左边的全部Rect去掉,后面再重建中文字符的位置。 +// 2.从特殊字符Rect开始,依次选择6个Rect,多余的舍去。 int CCharsSegment::RebuildRect(const vector& vecRect, vector& outRect, int specIndex) { - //ֻ7Rect,ȥĵľֻ6Rect + //最大只能有7个Rect,减去中文的就只有6个Rect int count = 6; for (int i = 0; i < vecRect.size(); i++) { - //ַߵRectȥܻȥRectûϵǺؽ + //将特殊字符左边的Rect去掉,这个可能会去掉中文Rect,不过没关系,我们后面会重建。 if (i < specIndex) continue; diff --git a/src/core/features.cpp b/src/core/features.cpp index 26ec713..e5a790f 100644 --- a/src/core/features.cpp +++ b/src/core/features.cpp @@ -1,6 +1,6 @@ -// ļEasyPRɵĺ -// ռΪeasypr -// еeasyprĿ޸ +// 这个文件定义了EasyPR里所有特征生成的函数 +// 所属命名空间为easypr +// 这个部分中的特征由easypr的开发者修改 #include "../include/prep.h" #include "../include/features.h" @@ -10,7 +10,7 @@ */ namespace easypr { -//! ֱͼ +//! 直方图均衡 Mat histeq(Mat in) { Mat out(in.size(), in.type()); @@ -31,7 +31,7 @@ Mat histeq(Mat in) return out; } -// ȡֱˮƽֱͼ +// !获取垂直和水平方向直方图 Mat ProjectedHistogram(Mat img, int t) { int sz=(t)?img.rows:img.cols; @@ -39,7 +39,7 @@ Mat ProjectedHistogram(Mat img, int t) for(int j=0; j(j)=countNonZero(data); //ͳһлһУԪصĸ浽mhist + mhist.at(j)=countNonZero(data); //统计这一行或一列中,非零元素的个数,并保存到mhist中 } //Normalize histogram @@ -47,13 +47,13 @@ Mat ProjectedHistogram(Mat img, int t) minMaxLoc(mhist, &min, &max); if(max>0) - mhist.convertTo(mhist,-1 , 1.0f/max, 0);//mhistֱͼеֵһֱͼ + mhist.convertTo(mhist,-1 , 1.0f/max, 0);//用mhist直方图中的最大值,归一化直方图 return mhist; } -//! óƵ +//! 获得车牌的特征数 Mat getTheFeatures(Mat in) { const int VERTICAL = 0; @@ -68,7 +68,7 @@ Mat getTheFeatures(Mat in) Mat out = Mat::zeros(1, numCols, CV_32F); - //Asign values to feature,Ϊˮƽֱֱͼ + //Asign values to feature,样本特征为水平、垂直直方图 int j=0; for(int i=0; i& resultVec) { - //dzƵͼ鼯 + //可能是车牌的图块集合 vector matVec; int resultLo = m_plateLocate->plateLocate(src, matVec); diff --git a/src/core/plate_judge.cpp b/src/core/plate_judge.cpp index 4b4dfec..f6ae18a 100644 --- a/src/core/plate_judge.cpp +++ b/src/core/plate_judge.cpp @@ -27,7 +27,7 @@ void CPlateJudge::LoadModel(string s) svm.load(s.c_str(), "svm"); } -//! ֱͼ +//! 直方图均衡 Mat CPlateJudge::histeq(Mat in) { Mat out(in.size(), in.type()); @@ -49,7 +49,7 @@ Mat CPlateJudge::histeq(Mat in) } -//! ԵͼSVMж +//! 对单幅图像进行SVM判断 int CPlateJudge::plateJudge(const Mat& inMat,int& result) { if (m_getFeatures == NULL) @@ -58,7 +58,7 @@ int CPlateJudge::plateJudge(const Mat& inMat,int& result) Mat features; m_getFeatures(inMat, features); - //ֱͨͼ⻯IJɫͼԤ + //通过直方图均衡化后的彩色图进行预测 Mat p = features.reshape(1, 1); p.convertTo(p, CV_32FC1); @@ -69,7 +69,7 @@ int CPlateJudge::plateJudge(const Mat& inMat,int& result) } -//! ԶͼSVMж +//! 对多幅图像进行SVM判断 int CPlateJudge::plateJudge(const vector& inVec, vector& resultVec) { diff --git a/src/core/plate_locate.cpp b/src/core/plate_locate.cpp index 5405c7d..7d6e9b7 100644 --- a/src/core/plate_locate.cpp +++ b/src/core/plate_locate.cpp @@ -25,8 +25,8 @@ CPlateLocate::CPlateLocate() m_debug = DEFAULT_DEBUG; } -//! ģʽ빤ҵģʽл -//! Ϊ棬øΪλƬٶͼƬIJָĬֵ +//! 生活模式与工业模式切换 +//! 如果为真,则设置各项参数为定位生活场景照片(如百度图片)的参数,否则恢复默认值。 void CPlateLocate::setLifemode(bool param) { if(param == true) @@ -52,12 +52,12 @@ void CPlateLocate::setLifemode(bool param) } -//! minAreaRectõСӾΣݺȽж +//! 对minAreaRect获得的最小外接矩形,用纵横比进行判断 bool CPlateLocate::verifySizes(RotatedRect mr) { float error = m_error; //Spain car plate size: 52x11 aspect 4,7272 - //China car plate size: 440mm*140mmaspect 3.142857 + //China car plate size: 440mm*140mm,aspect 3.142857 float aspect = m_aspect; //Set a min and max area. All other patchs are discarded //int min= 1*aspect*1; // minimum area @@ -85,7 +85,7 @@ bool CPlateLocate::verifySizes(RotatedRect mr) } } -//! ʾɵijͼ񣬱жǷɹת +//! 显示最终生成的车牌图像,便于判断是否成功进行了旋转。 Mat CPlateLocate::showResultMat(Mat src, Size rect_size, Point2f center, int index) { Mat img_crop; @@ -113,10 +113,10 @@ Mat CPlateLocate::showResultMat(Mat src, Size rect_size, Point2f center, int ind return resultResized; } -//! λͼ -//! src ԭʼͼ -//! resultVec һMat洢ץȡͼ -//! ɹ0򷵻-1 +//! 定位车牌图像 +//! src 原始图像 +//! resultVec 一个Mat的向量,存储所有抓取到的图像 +//! 成功返回0,否则返回-1 int CPlateLocate::plateLocate(Mat src, vector& resultVec) { Mat src_blur, src_gray; @@ -129,7 +129,7 @@ int CPlateLocate::plateLocate(Mat src, vector& resultVec) if( !src.data ) { return -1; } - //˹ģSizeеӰ쳵ƶλЧ + //高斯模糊。Size中的数字影响车牌定位的效果。 GaussianBlur( src, src_blur, Size(m_GaussianBlurSize, m_GaussianBlurSize), 0, 0, BORDER_DEFAULT ); @@ -199,11 +199,11 @@ int CPlateLocate::plateLocate(Mat src, vector& resultVec) imwrite(ss.str(), img_threshold); } - //Find of possibles plates + //Find 轮廓 of possibles plates vector< vector< Point> > contours; findContours(img_threshold, contours, // a vector of contours - CV_RETR_EXTERNAL, // ȡⲿ + CV_RETR_EXTERNAL, // 提取外部轮廓 CV_CHAIN_APPROX_NONE); // all pixels of each contours Mat result; @@ -252,10 +252,10 @@ int CPlateLocate::plateLocate(Mat src, vector& resultVec) { // rotated rectangle drawing // Get rotation matrix - // תⲿִȷʵԽijЩбijƵ - // Ҳ󽫸ijƸбۺϿǣDzʹδ롣 - // 2014-08-14,µһͼƬзкܶ೵бģ˾ٴγ - // δ롣 + // 旋转这部分代码确实可以将某些倾斜的车牌调整正, + // 但是它也会误将更多正的车牌搞成倾斜!所以综合考虑,还是不使用这段代码。 + // 2014-08-14,由于新到的一批图片中发现有很多车牌是倾斜的,因此决定再次尝试 + // 这段代码。 if(m_debug) { Point2f rect_points[4]; @@ -272,7 +272,7 @@ int CPlateLocate::plateLocate(Mat src, vector& resultVec) angle = 90 + angle; swap(rect_size.width, rect_size.height); } - //ץȡķתm_angleǶȣdzƣ + //如果抓取的方块旋转超过m_angle角度,则不是车牌,放弃处理 if (angle - m_angle < 0 && angle + m_angle > 0) { //Create and rotate image diff --git a/src/core/plate_recognize.cpp b/src/core/plate_recognize.cpp index 0a614bf..ab41411 100644 --- a/src/core/plate_recognize.cpp +++ b/src/core/plate_recognize.cpp @@ -12,13 +12,13 @@ CPlateRecognize::CPlateRecognize() //m_charsRecognise = new CCharsRecognise(); } -////! װSVMģ +////! 装载SVM模型 //void CPlateRecognize::LoadSVM(string strSVM) //{ // m_plateDetect->LoadModel(strSVM.c_str()); //} // -////! װANNģ +////! 装载ANN模型 //void CPlateRecognize::LoadANN(string strANN) //{ // m_charsRecognise->LoadModel(strANN.c_str()); @@ -38,7 +38,7 @@ CPlateRecognize::CPlateRecognize() int CPlateRecognize::plateRecognize(Mat src, vector& licenseVec) { - //Ʒ鼯 + //车牌方块集合 vector plateVec; int resultPD = plateDetect(src, plateVec); @@ -51,10 +51,10 @@ int CPlateRecognize::plateRecognize(Mat src, vector& licenseVec) { Mat plate = plateVec[j]; - //ȡɫ + //获取车牌颜色 string plateType = getPlateType(plate); - //ȡƺ + //获取车牌号 string plateIdentify = ""; int resultCR = charsRecognise(plate, plateIdentify); if (resultCR == 0) diff --git a/src/include/chars_identify.h b/src/include/chars_identify.h index 3657418..d08015c 100644 --- a/src/include/chars_identify.h +++ b/src/include/chars_identify.h @@ -24,39 +24,39 @@ class CCharsIdentify public: CCharsIdentify(); - //! ַָ + //! 字符分割 string charsIdentify(Mat, bool); - //! ַ + //! 字符分类 int classify(Mat, bool); - //create the accumulation histograms,img is a binary image, t is ˮƽֱ + //create the accumulation histograms,img is a binary image, t is 水平或垂直 Mat ProjectedHistogram(Mat img, int t); - //! ַͼ + //! 获得字符的特征图 Mat features(Mat in, int sizeData); - //! װANNģ + //! 装载ANN模型 void LoadModel(); - //! װANNģ + //! 装载ANN模型 void LoadModel(string s); - //! ȡģ· + //! 设置与读取模型路径 inline void setModelPath(string path){ m_path = path; } inline string getModelPath() const{ return m_path; } private: - //ʹõANNģ + //!使用的ANN模型 CvANN_MLP ann; - //! ģʹ洢· + //! 模型存储路径 string m_path; - //! ߴ + //! 特征尺寸 int m_predictSize; - //! ʡݶӦmap + //! 省份对应map map m_map; }; diff --git a/src/include/chars_recognise.h b/src/include/chars_recognise.h index 80d2240..ea17452 100644 --- a/src/include/chars_recognise.h +++ b/src/include/chars_recognise.h @@ -27,32 +27,32 @@ class CCharsRecognise public: CCharsRecognise(); - //! ַָʶ + //! 字符分割与识别 int charsRecognise(Mat, String&); - //! װANNģ + //! 装载ANN模型 void LoadANN(string s); - //! Ƿģʽ + //! 是否开启调试模式 inline void setCRDebug(int param){ m_charsSegment->setDebug(param);} - //! ȡģʽ״̬ + //! 获取调试模式状态 inline int getCRDebug(){ return m_charsSegment->getDebug();} - //! óɫ + //! 获得车牌颜色 inline string getPlateType(Mat input) const { - string color = "δ֪"; + string color = "未知"; int result = m_charsSegment->getPlateType(input); if (1 == result) - color = ""; + color = "蓝牌"; if (2 == result) - color = ""; + color = "黄牌"; return color; } - //! ñ + //! 设置变量 inline void setLiuDingSize(int param){ m_charsSegment->setLiuDingSize(param);} inline void setColorThreshold(int param){ m_charsSegment->setColorThreshold(param);} inline void setBluePercent(float param){ m_charsSegment->setBluePercent(param);} @@ -61,10 +61,10 @@ public: inline float getWhitePercent() const { return m_charsSegment->getWhitePercent();} private: - //ַָ + //!字符分割 CCharsSegment* m_charsSegment; - //! ַʶ + //! 字符识别 CCharsIdentify* m_charsIdentify; }; diff --git a/src/include/chars_segment.h b/src/include/chars_segment.h index ed1c40f..be4bef0 100644 --- a/src/include/chars_segment.h +++ b/src/include/chars_segment.h @@ -24,45 +24,45 @@ class CCharsSegment public: CCharsSegment(); - //! ַָ + //! 字符分割 int charsSegment(Mat, vector& ); - //! ַߴ֤ + //! 字符尺寸验证 bool verifySizes(Mat r); - //! ַԤ + //! 字符预处理 Mat preprocessChar(Mat in); - //! ֱͼ + //! 生成直方图 Mat ProjectedHistogram(Mat img, int t); - //! ַض + //! 生成字符的特定特征 Mat features(Mat in, int sizeData); - //! ֱͼ⣬Ϊжϳɫ׼ + //! 直方图均衡,为判断车牌颜色做准备 Mat histeq(Mat in); - //! óɫ + //! 获得车牌颜色 int getPlateType(Mat input); - //! ȥӰַʶ + //! 去除影响字符识别的柳钉 Mat clearLiuDing(Mat img); - //! ⳵²ַλúʹС + //! 根据特殊车牌来构造猜测中文字符的位置和大小 Rect GetChineseRect(const Rect rectSpe); - //! ҳָʾеַRectA7003XAλ + //! 找出指示城市的字符的Rect,例如苏A7003X,就是A的位置 int GetSpecificRect(const vector& vecRect); - //! - // 1.ַRectߵȫRectȥؽַλá - // 2.ַRectʼѡ6Rectȥ + //! 这个函数做两个事情 + // 1.把特殊字符Rect左边的全部Rect去掉,后面再重建中文字符的位置。 + // 2.从特殊字符Rect开始,依次选择6个Rect,多余的舍去。 int RebuildRect(const vector& vecRect, vector& outRect, int specIndex); - //! Rectλôҽ + //! 将Rect按位置从左到右进行排序 int SortRect(const vector& vecRect, vector& out); - //! ñ + //! 设置变量 inline void setLiuDingSize(int param){ m_LiuDingSize = param;} inline void setColorThreshold(int param){ m_ColorThreshold = param;} @@ -71,38 +71,38 @@ public: inline void setWhitePercent(float param){ m_WhitePercent = param;} inline float getWhitePercent() const { return m_WhitePercent;} - //! ǷģʽĬ0ر + //! 是否开启调试模式常量,默认0代表关闭 static const int DEFAULT_DEBUG = 0; - //! preprocessCharó + //! preprocessChar所用常量 static const int CHAR_SIZE = 20; static const int HORIZONTAL = 1; static const int VERTICAL = 0; - //! preprocessCharó + //! preprocessChar所用常量 static const int DEFAULT_LIUDING_SIZE = 7; static const int DEFAULT_MAT_WIDTH = 136; static const int DEFAULT_COLORTHRESHOLD = 150; - //! Ƿģʽ + //! 是否开启调试模式 inline void setDebug(int param){ m_debug = param;} - //! ȡģʽ״̬ + //! 获取调试模式状态 inline int getDebug(){ return m_debug;} private: - //жϲ + //!柳钉判断参数 int m_LiuDingSize; - //ƴС + //!车牌大小参数 int m_theMatWidth; - //ɫжϲ + //!车牌颜色判断参数 int m_ColorThreshold; float m_BluePercent; float m_WhitePercent; - //! Ƿģʽ0رգ0 + //! 是否开启调试模式,0关闭,非0开启 int m_debug; }; diff --git a/src/include/features.h b/src/include/features.h index 976173a..4346f8e 100644 --- a/src/include/features.h +++ b/src/include/features.h @@ -6,31 +6,31 @@ */ namespace easypr { -//! ֱͼ +//! 直方图均衡 Mat histeq(Mat in); -// ȡֱˮƽֱͼ +// !获取垂直和水平方向直方图 Mat ProjectedHistogram(Mat img, int t); -//! óƵ +//! 获得车牌的特征数 Mat getTheFeatures(Mat in); -// ! EasyPRgetFeaturesص -// ڴӳƵimagesvmѵfeatures +// ! EasyPR的getFeatures回调函数 +// !用于从车牌的image生成svm的训练特征features typedef void(*svmCallback)(const Mat& image, Mat& features); -// ! EasyPRgetFeaturesص -// ֱͼĻص +// ! EasyPR的getFeatures回调函数 +// !本函数是生成直方图均衡特征的回调函数 void getHisteqFeatures(const Mat& image, Mat& features); -// ! EasyPRgetFeaturesص -// ǻȡֱˮƽֱͼͼֵ +// ! EasyPR的getFeatures回调函数 +// !本函数是获取垂直和水平的直方图图值 void getHistogramFeatures(const Mat& image, Mat& features); -// ǻȡSIFT +// !本函数是获取SIFT特征子 void getSIFTFeatures(const Mat& image, Mat& features); -// ǻȡHOG +// !本函数是获取HOG特征子 void getHOGFeatures(const Mat& image, Mat& features); diff --git a/src/include/plate_detect.h b/src/include/plate_detect.h index abe497f..12e68b8 100644 --- a/src/include/plate_detect.h +++ b/src/include/plate_detect.h @@ -27,22 +27,22 @@ class CPlateDetect public: CPlateDetect(); - //! Ƽ⣺ƶλж + //! 车牌检测:车牌定位与判断 int plateDetect(Mat, vector&); - //! װSVMģ + //! 装载SVM模型 void LoadSVM(string s); - //! ģʽ빤ҵģʽл + //! 生活模式与工业模式切换 inline void setPDLifemode(bool param){m_plateLocate->setLifemode(param);} - //! Ƿģʽ + //! 是否开启调试模式 inline void setPDDebug(int param){ m_plateLocate->setDebug(param);} - //! ȡģʽ״̬ + //! 获取调试模式状态 inline int getPDDebug(){ return m_plateLocate->getDebug();} - //! ȡ + //! 设置与读取变量 inline void setGaussianBlurSize(int param){ m_plateLocate->setGaussianBlurSize(param);} inline int getGaussianBlurSize() const{ return m_plateLocate->getGaussianBlurSize();} @@ -63,10 +63,10 @@ public: inline void setJudgeAngle(int param){m_plateLocate->setJudgeAngle(param);} private: - //ƶλ + //!车牌定位 CPlateLocate* m_plateLocate; - //! ж + //! 车牌判断 CPlateJudge* m_plateJudge; }; diff --git a/src/include/plate_judge.h b/src/include/plate_judge.h index 388a98a..4c50093 100644 --- a/src/include/plate_judge.h +++ b/src/include/plate_judge.h @@ -25,34 +25,34 @@ class CPlateJudge public: CPlateJudge(); - //! ж + //! 车牌判断 int plateJudge(const vector&, vector&); - //! жϣһͼ + //! 车牌判断(一副图像) int plateJudge(const Mat& inMat, int& result); - //! ֱͼ + //! 直方图均衡 Mat histeq(Mat); - //! װSVMģ + //! 装载SVM模型 void LoadModel(); - //! װSVMģ + //! 装载SVM模型 void LoadModel(string s); - //! ȡģ· + //! 设置与读取模型路径 inline void setModelPath(string path){ m_path = path; } inline string getModelPath() const{ return m_path; } private: - //ʹõSVMģ + //!使用的SVM模型 CvSVM svm; - // ! EasyPRgetFeaturesص - // ڴӳƵimagesvmѵfeatures + // ! EasyPR的getFeatures回调函数 + // !用于从车牌的image生成svm的训练特征features svmCallback m_getFeatures; - //! ģʹ洢· + //! 模型存储路径 string m_path; }; diff --git a/src/include/plate_locate.h b/src/include/plate_locate.h index 61d94bc..48240ab 100644 --- a/src/include/plate_locate.h +++ b/src/include/plate_locate.h @@ -25,19 +25,19 @@ class CPlateLocate public: CPlateLocate(); - //! ƶλ + //! 车牌定位 int plateLocate(Mat, vector& ); - //! Ƶijߴ֤ + //! 车牌的尺寸验证 bool verifySizes(RotatedRect mr); - //! ʾ + //! 结果车牌显示 Mat showResultMat(Mat src, Size rect_size, Point2f center, int index); - //! ģʽ빤ҵģʽл + //! 生活模式与工业模式切换 void setLifemode(bool param); - //! ȡ + //! 设置与读取变量 inline void setGaussianBlurSize(int param){ m_GaussianBlurSize = param;} inline int getGaussianBlurSize() const{ return m_GaussianBlurSize;} @@ -57,13 +57,13 @@ public: inline void setJudgeAngle(int param){ m_angle = param;} - //! Ƿģʽ + //! 是否开启调试模式 inline void setDebug(int param){ m_debug = param;} - //! ȡģʽ״̬ + //! 获取调试模式状态 inline int getDebug(){ return m_debug;} - //! PlateLocateó + //! PlateLocate所用常量 static const int DEFAULT_GAUSSIANBLUR_SIZE = 5; static const int SOBEL_SCALE = 1; static const int SOBEL_DELTA = 0; @@ -73,39 +73,39 @@ public: static const int DEFAULT_MORPH_SIZE_WIDTH = 17; static const int DEFAULT_MORPH_SIZE_HEIGHT = 3; - //! showResultMató + //! showResultMat所用常量 static const int WIDTH = 136; static const int HEIGHT = 36; static const int TYPE = CV_8UC3; - //! verifySizeó + //! verifySize所用常量 static const int DEFAULT_VERIFY_MIN = 3; static const int DEFAULT_VERIFY_MAX = 20; - //! Ƕжó + //! 角度判断所用常量 static const int DEFAULT_ANGLE = 30; - //! ǷģʽĬ0ر + //! 是否开启调试模式常量,默认0代表关闭 static const int DEFAULT_DEBUG = 0; protected: - //! ˹ģñ + //! 高斯模糊所用变量 int m_GaussianBlurSize; - //! Ӳñ + //! 连接操作所用变量 int m_MorphSizeWidth; int m_MorphSizeHeight; - //! verifySizeñ + //! verifySize所用变量 float m_error; float m_aspect; int m_verifyMin; int m_verifyMax; - //! Ƕжñ + //! 角度判断所用变量 int m_angle; - //! Ƿģʽ0رգ0 + //! 是否开启调试模式,0关闭,非0开启 int m_debug; }; diff --git a/src/include/plate_recognize.h b/src/include/plate_recognize.h index a07a162..c799e46 100644 --- a/src/include/plate_recognize.h +++ b/src/include/plate_recognize.h @@ -27,39 +27,39 @@ class CPlateRecognize : public CPlateDetect, public CCharsRecognise public: CPlateRecognize(); - //! Ƽַʶ + //! 车牌检测与字符识别 int plateRecognize(Mat, vector&); - //! ģʽ빤ҵģʽл + //! 生活模式与工业模式切换 inline void setLifemode(bool param) { CPlateDetect::setPDLifemode(param); } - //! Ƿģʽ + //! 是否开启调试模式 inline void setDebug(int param) { CPlateDetect::setPDDebug(param); CCharsRecognise::setCRDebug(param); } - ////! ƶλж + ////! 车牌定位与判断 //int plateDetect(Mat, vector&); - ////! ַָʶ + ////! 字符分割与识别 //int charsRecognise(Mat, String&); - ////! װSVM + ////! 装载SVM //void LoadSVM(string s); - ////! װANNģ + ////! 装载ANN模型 //void LoadANN(string s); private: - ////Ƽ + ////!车牌检测 //CPlateDetect* m_plateDetect; - ////! ַʶ + ////! 字符识别 //CCharsRecognise* m_charsRecognise; }; diff --git a/src/include/util.h b/src/include/util.h index ea22940..fdb5db1 100644 --- a/src/include/util.h +++ b/src/include/util.h @@ -2,17 +2,17 @@ #ifndef __UTIL_H__ #define __UTIL_H__ -//C++Ļȡļк +//C++的获取文件夹函数 void getFiles(string path, vector& files); -//C++spilt +//C++的spilt函数 void SplitString(const string& s, vector& v, const string& c); -//C++Ĵļ·Ƶļƣ׺ķ +//C++的从文件路径名称到文件名称(不包括后缀)的方法 void getFileName(const string& filepath, string& name); -//! levenshtein룬ڼƵľ -//EasyPRlevenshteinʶʵƵ +//! levenshtein距离,用于计算两个车牌的距离 +//!EasyPR中用levenshtein距离衡量车牌识别与真实车牌的误差 template unsigned int levenshtein_distance(const T &s1, const T & s2) { const size_t len1 = s1.size(), len2 = s2.size(); @@ -31,32 +31,32 @@ unsigned int levenshtein_distance(const T &s1, const T & s2) { } -/// test.cppз +/// test.cpp中方法 int testMain(); -/// accuracy_test.cppз +/// accuracy_test.cpp中方法 int acurayTest(const string&); -/// mc_data_prepare.cppз +/// mc_data_prepare.cpp中方法 void getLearnData(); void Code2Province(const string& code, string& province); void changeFileName(); void getPlateLicense(const string& filepath, string& plateLicense); -/// learn_prepare.cppз +/// learn_prepare.cpp中方法 void label_data(); -/// general_test_prepare.cppз +/// general_test_prepare.cpp中方法 int general_test(); -// deface.cppз -// ʶ -// ڷݵgeneral_testݼķͼд -// EasyPRԴĿdzעرͼƬмʻ˵˽ +// deface.cpp中方法 +// 反人脸识别函数 +// 在发布数据到general_test数据集里,请先用这里的方法对图像进行处理 +// EasyPR开源项目非常注重保护图片中驾驶人的隐私 int deface(); -/// generate_gdts.cppз +/// generate_gdts.cpp中方法 int generate_gdts(); #endif diff --git a/src/main.cpp b/src/main.cpp index 2a59f07..a53286a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,18 +18,18 @@ extern const string GENERAL_TEST_PATH = "image/general_test"; extern const string NATIVE_TEST_PATH = "image/native_test"; //////////////////////////////////////////////////////////// -// EasyPR ѵ +// EasyPR 训练命令行 const string option[] = { - "1. ;" , - "2. ;" , - "3. SVMѵ;" , - "4. ANNѵ(δ);" , - "5. GDTS;" , - "6. Ŷ;" , - "7. л;" , - "8. ˳;" , + "1. 测试;" , + "2. 批量测试;" , + "3. SVM训练;" , + "4. ANN训练(未开放);" , + "5. GDTS生成;" , + "6. 开发团队;" , + "7. 感谢名单;" , + "8. 退出;" , }; const int optionCount = 8; @@ -49,7 +49,7 @@ int main() cout << "////////////////////////////////////"<< endl; cout << selectOption.str(); cout << "////////////////////////////////////"<< endl; - cout << "ѡһ:"; + cout << "请选择一项操作:"; int select = -1; bool isRepeat = true; @@ -75,28 +75,28 @@ int main() generate_gdts(); break; case 6: - // Ŷ; + // 开发团队; cout << endl; - cout << "EasyPRŶĿǰһ5ҵСڽEasyPR汾Ŀ" << endl; - cout << "ԱĿȤԸΪԴһǺܻӭļ롣" << endl; - cout << "ĿǰƸҪ˲ǣƶλͼʶѧϰվطţˡ" << endl; - cout << "Լ뷢ʼַ(easypr_dev@163.com)ڴļ룡" << endl; + cout << "我们EasyPR团队目前有一个5人左右的小组在进行EasyPR后续版本的开发工作。" << endl; + cout << "如果你对本项目感兴趣,并且愿意为开源贡献一份力量,我们很欢迎你的加入。" << endl; + cout << "目前招聘的主要人才是:车牌定位,图像识别,深度学习,网站建设相关方面的牛人。" << endl; + cout << "如果你觉得自己符合条件,请发邮件到地址(easypr_dev@163.com),期待你的加入!" << endl; cout << endl; break; case 7: - // л + // 感谢名单 cout << endl; - cout << "ĿڽУܵ˺ܶ˵İǶԱĿͻ׵" << endl; - cout << "(װ潨飬ţṩȵ,ʱ˳)" << endl; - cout << "taotao1233, ƴjsxyheluһ죬ѧϰܶԬ־ʥСʯ" << endl; - cout << "кܶͬѧԱĿҲ˹֧֣ڴҲһʾϵл⣡" << endl; + cout << "本项目在建设过程中,受到了很多人的帮助,其中以下是对本项目做出突出贡献的" << endl; + cout << "(贡献包括有益建议,代码调优,数据提供等等,排名按时间顺序):" << endl; + cout << "taotao1233, 唐大侠,jsxyhelu,如果有一天,学习奋斗,袁承志,圣城小石匠," << endl; + cout << "还有很多的同学对本项目也给予了鼓励与支持,在此也一并表示真诚的谢意!" << endl; cout << endl; break; case 8: isExit = true; break; default: - cout << ":"; + cout << "输入错误,请重新输入:"; isRepeat = true; break; } @@ -104,18 +104,18 @@ int main() } return 0; } -// /EasyPR ѵ +// /EasyPR 训练命令行 结束 //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// -// acurayTestMain +// acurayTestMain 命令行 const string acuray_option[] = { "1. general_test;" , "2. native_test;" , - "3. ;" , + "3. 返回;" , }; const int acuray_optionCount = 3; @@ -135,7 +135,7 @@ int acurayTestMain() cout << "////////////////////////////////////"<< endl; cout << selectOption.str(); cout << "////////////////////////////////////"<< endl; - cout << "ѡһ:"; + cout << "请选择一项操作:"; int select = -1; bool isRepeat = true; @@ -155,7 +155,7 @@ int acurayTestMain() isExit = true; break; default: - cout << ":"; + cout << "输入错误,请重新输入:"; isRepeat = true; break; } @@ -164,22 +164,22 @@ int acurayTestMain() return 0; } -// acurayTestMain +// acurayTestMain 命令行 //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// -// SVM ѵ +// SVM 训练命令行 const string svm_option[] = { - "1. learndata(뵽Ļ);" , - "2. ǩlearndata;" , - "3. Ƽ(not divide and train);" , - "4. Ƽ(not train);" , - "5. Ƽ(not divide);" , - "6. Ƽ;" , - "7. ;" , + "1. 生成learndata(调整代码到你的环境后再用);" , + "2. 标签learndata;" , + "3. 车牌检测(not divide and train);" , + "4. 车牌检测(not train);" , + "5. 车牌检测(not divide);" , + "6. 车牌检测;" , + "7. 返回;" , }; const int svm_optionCount = 7; @@ -199,7 +199,7 @@ int svmMain() cout << "////////////////////////////////////"<< endl; cout << selectOption.str(); cout << "////////////////////////////////////"<< endl; - cout << "ѡһ:"; + cout << "请选择一项操作:"; int select = -1; bool isRepeat = true; @@ -231,7 +231,7 @@ int svmMain() isExit = true; break; default: - cout << ":"; + cout << "输入错误,请重新输入:"; isRepeat = true; break; } @@ -240,5 +240,5 @@ int svmMain() return 0; } -// SVM ѵ +// SVM 训练命令行 //////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/src/test/accuracy_test.cpp b/src/test/accuracy_test.cpp index 01b1aa2..a0df620 100644 --- a/src/test/accuracy_test.cpp +++ b/src/test/accuracy_test.cpp @@ -1,5 +1,5 @@ -// ͨȷʲļ -// AcurayTestӦmainеѡ2 +// 通用正确率测试文件 +// AcurayTest对应到main控制命令中的选项2 #include "../include/plate_recognize.h" #include "../include/util.h" @@ -9,7 +9,7 @@ using namespace easypr; int acurayTest(const string& test_path) { - ////ȡ·µļ + ////获取该路径下的所有文件 vector files; getFiles(test_path, files); @@ -32,20 +32,20 @@ int acurayTest(const string& test_path) cout << "Begin to test the easypr accuracy!" << endl; - // ܵIJͼƬ + // 总的测试图片数量 int count_all = 0; - // ͼƬ + // 错误的图片数量 int count_err = 0; - // δʶͼƬ + // 未识别的图片数量 int count_norecogin = 0; - // ַܵ + // 总的字符差距 float diff_all = 0; - // ƽַ + // 平均字符差距 float diff_avg = 0; - // ȫƥʶ + // 完全匹配的识别次数 float match_count = 0; - // ȫƥʶռʶͼƬеı + // 完全匹配的识别次数所占识别图片中的比例 float match_rate = 0; for (int i = 0; i < size; i++) @@ -53,13 +53,13 @@ int acurayTest(const string& test_path) string filepath = files[i].c_str(); cout << "------------------" << endl; - // ȡʵij + // 获取真实的车牌 string plateLicense = ""; getFileName(filepath, plateLicense); - cout << "ԭ:" << plateLicense << endl; + cout << "原牌:" << plateLicense << endl; - // EasyPRʼжϳ + // EasyPR开始判断车牌 Mat src = imread(filepath); vector plateVec; int result = pr.plateRecognize(src, plateVec); @@ -69,20 +69,20 @@ int acurayTest(const string& test_path) if (num == 0) { - cout << ""<< "޳" < 1) { - // ೵ʹdiffСǸ¼ + // 多车牌使用diff最小的那个记录 int mindiff = 10000; for (int j = 0; j < num; j++) { cout << plateVec[j] << " (" << j+1 << ")"< spilt_plate; SplitString(colorplate, spilt_plate, ":"); @@ -95,23 +95,23 @@ int acurayTest(const string& test_path) } } - cout << ":" << mindiff << "ַ" << endl; + cout << "差距:" << mindiff << "个字符" << endl; if(mindiff == 0) { - // ȫƥ + // 完全匹配 match_count++; } diff_all = diff_all + mindiff; } else { - // ֻһdiff + // 单车牌只计算一次diff for (int j = 0; j < num; j++) { cout << plateVec[j] < spilt_plate; SplitString(colorplate, spilt_plate, ":"); @@ -119,11 +119,11 @@ int acurayTest(const string& test_path) if (size == 2) { int diff = levenshtein_distance(plateLicense, spilt_plate[size-1]); - cout << ":" << diff << "ַ" << endl; + cout << "差距:" << diff << "个字符" << endl; if(diff == 0) { - // ȫƥ + // 完全匹配 match_count++; } diff_all = diff_all + diff; @@ -134,7 +134,7 @@ int acurayTest(const string& test_path) } else { - cout << ":" << result << endl; + cout << "错误码:" << result << endl; count_err++; } count_all++; @@ -144,20 +144,20 @@ int acurayTest(const string& test_path) cout << "Easypr accuracy test end!" << endl; cout << "------------------" << endl; cout << endl; - cout << "ȷͳ:" << endl; - cout << "ͼƬ:" << count_all << ", "; - cout << "δʶͼƬ:" << count_norecogin << ", "; + cout << "正确率统计:" << endl; + cout << "总图片数:" << count_all << "张, "; + cout << "未识别图片:" << count_norecogin << "张, "; float count_recogin = count_all - (count_err + count_norecogin); float count_rate = count_recogin / count_all * 100; - cout << "ʶ:" << count_rate << "% " << endl; + cout << "识别率:" << count_rate << "% " << endl; diff_avg = diff_all / count_recogin; match_rate = match_count/ count_recogin * 100; - cout << "ƽ־:" << diff_avg << ", "; - cout << "ȫƥ:" << match_count << ", "; - cout << "ȫƥ:" << match_rate << "% " << endl; + cout << "平均字距:" << diff_avg << "个, "; + cout << "完全匹配数:" << match_count << "张, "; + cout << "完全匹配率:" << match_rate << "% " << endl; cout << endl; cout << "------------------" << endl; diff --git a/src/test/test.cpp b/src/test/test.cpp index 45997c2..69b5c11 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -20,21 +20,21 @@ int test_plate_recognize(); int testMain(); -//ҪԵͼƬַд +//把你要测试的图片地址写在下面 const string test_img = ""; const string testOption[] = { - "1. test plate_locate(ƶλ);" /* ƶλ */, - "2. test plate_judge(ж);" /* ж */, - "3. test plate_detect(Ƽ);" /* Ƽ⣨ƶλ복жϣ */, - "4. test chars_segment(ַָ);" /* ַָ */, - "5. test chars_identify(ַ);" /* ַ */, - "6. test chars_recognise(ַʶ);" /* ַʶ𣨰ַַָ */, - "7. test plate_recognize(ʶ);" /* ʶ */, - "8. test all(ȫ);" /* ȫ */, - "9. ;" /* ˳ */, + "1. test plate_locate(车牌定位);" /* 车牌定位 */, + "2. test plate_judge(车牌判断);" /* 车牌判断 */, + "3. test plate_detect(车牌检测);" /* 车牌检测(包含车牌定位与车牌判断) */, + "4. test chars_segment(字符分隔);" /* 字符分隔 */, + "5. test chars_identify(字符鉴别);" /* 字符鉴别 */, + "6. test chars_recognise(字符识别);" /* 字符识别(包含字符分隔与字符鉴别) */, + "7. test plate_recognize(车牌识别);" /* 车牌识别 */, + "8. test all(测试全部);" /* 以上全部 */, + "9. 返回;" /* 退出 */, }; const int testOptionCount = 9; @@ -54,7 +54,7 @@ int testMain() cout << "////////////////////////////////////"<< endl; cout << selectOption.str(); cout << "////////////////////////////////////"<< endl; - cout << "ѡһ:"; + cout << "请选择一项操作:"; int select = -1; bool isRepeat = true; @@ -100,7 +100,7 @@ int testMain() isExit = true; break; default: - cout << ":"; + cout << "输入错误,请重新输入:"; isRepeat = true; break; } @@ -143,10 +143,10 @@ int test_plate_judge() Mat src = imread("image/plate_judge.jpg"); - //dzƵͼ鼯 + //可能是车牌的图块集合 vector matVec; - //SVMжϺõͼ鼯 + //经过SVM判断后得到的图块集合 vector resultVec; CPlateLocate lo; @@ -236,7 +236,7 @@ int test_chars_identify() Mat resultMat = resultVec[j]; bool isChinses = false; - //Ĭ׸ַַ + //默认首个字符块是中文字符 if (j == 0) isChinses = true; @@ -245,7 +245,7 @@ int test_chars_identify() } } - const string plateLicense = "E771H6"; + const string plateLicense = "苏E771H6"; cout << "plateLicense: " << plateLicense << endl; cout << "plateIdentify: " << plateIdentify << endl; diff --git a/src/train/ann_train.cpp b/src/train/ann_train.cpp index eb254f3..0ddf3b3 100644 --- a/src/train/ann_train.cpp +++ b/src/train/ann_train.cpp @@ -1,4 +1,4 @@ -// ann_train.cpp : annģ͵ѵļҪOCR +// ann_train.cpp : ann模型的训练文件,主要用在OCR中 #include #include @@ -24,21 +24,21 @@ using namespace easypr; CvANN_MLP ann; -//й +//中国车牌 const char strCharacters[] = {'0','1','2','3','4','5',\ - '6','7','8','9','A','B', 'C', 'D', 'E','F', 'G', 'H', /* ûI */\ - 'J', 'K', 'L', 'M', 'N', /* ûO */ 'P', 'Q', 'R', 'S', 'T', \ + '6','7','8','9','A','B', 'C', 'D', 'E','F', 'G', 'H', /* 没有I */\ + 'J', 'K', 'L', 'M', 'N', /* 没有O */ 'P', 'Q', 'R', 'S', 'T', \ 'U','V', 'W', 'X', 'Y', 'Z'}; -const int numCharacter = 34; /* ûI0,1024Ӣַ֮ */ +const int numCharacter = 34; /* 没有I和0,10个数字与24个英文字符之和 */ -//¶ѵʱõַݣȫ棬Щʡûѵûַ -//Щ2ıʾѵʱַһֱΣҲΪѵݴ洢 -const string strChinese[] = {"zh_cuan" /* */, "zh_e" /* */, "zh_gan" /* */, \ - "zh_hei" /* */, "zh_hu" /* */, "zh_ji" /* */, \ - "zh_jl" /* */, "zh_jin" /* */, "zh_jing" /* */, "zh_shan" /* */, \ - "zh_liao" /* */, "zh_lu" /* ³ */, "zh_min" /* */, "zh_ning" /* */, \ - "zh_su" /* */, "zh_sx" /* */, "zh_wan" /* */,\ - "zh_yu" /* ԥ */, "zh_yue" /* */, "zh_zhe" /* */}; +//以下都是我训练时用到的中文字符数据,并不全面,有些省份没有训练数据所以没有字符 +//有些后面加数字2的表示在训练时常看到字符的一种变形,也作为训练数据存储 +const string strChinese[] = {"zh_cuan" /* 川 */, "zh_e" /* 鄂 */, "zh_gan" /* 赣*/, \ + "zh_hei" /* 黑 */, "zh_hu" /* 沪 */, "zh_ji" /* 冀 */, \ + "zh_jl" /* 吉 */, "zh_jin" /* 津 */, "zh_jing" /* 京 */, "zh_shan" /* 陕 */, \ + "zh_liao" /* 辽 */, "zh_lu" /* 鲁 */, "zh_min" /* 闽 */, "zh_ning" /* 宁 */, \ + "zh_su" /* 苏 */, "zh_sx" /* 晋 */, "zh_wan" /* 皖 */,\ + "zh_yu" /* 豫 */, "zh_yue" /* 粤 */, "zh_zhe" /* 浙 */}; const int numChinese = 20; const int numAll = 54; /* 34+20=54 */ @@ -59,7 +59,7 @@ Mat features(Mat in, int sizeData){ int numCols=vhist.cols+hhist.cols+lowData.cols*lowData.cols; Mat out=Mat::zeros(1,numCols,CV_32F); - //Asign values to feature,ANNΪˮƽֱֱͼ͵ͷֱͼɵʸ + //Asign values to feature,ANN的样本特征为水平、垂直直方图和低分辨率图像所组成的矢量 int j=0; for(int i=0; i files; - ////ȡ·µļ + ////获取该路径下的所有文件 getFiles(filePath, files ); int size = files.size(); if (0 == size) cout << "No File Found in learn HasPlate!" << endl; - ////ѡȡ70%Ϊѵݣ30%Ϊ + ////随机选取70%作为训练数据,30%作为测试数据 srand(unsigned(time(NULL))); random_shuffle(files.begin(), files.end()); @@ -61,13 +61,13 @@ void learn2NoPlate(float bound = 0.7) char * filePath = "train/data/plate_detect_svm/learn/NoPlate"; vector files; - ////ȡ·µļ + ////获取该路径下的所有文件 getFiles(filePath, files ); int size = files.size(); if (0 == size) cout << "No File Found in learn NoPlate!" << endl; - ////ѡȡ70%Ϊѵݣ30%Ϊ + ////随机选取70%作为训练数据,30%作为测试数据 srand(unsigned(time(NULL))); random_shuffle(files.begin(), files.end()); @@ -107,7 +107,7 @@ void getHasPlateTrain(Mat& trainingImages, vector& trainingLabels, char * filePath = "train/data/plate_detect_svm/train/HasPlate"; vector files; - ////ȡ·µļ + ////获取该路径下的所有文件 getFiles(filePath, files ); int size = files.size(); @@ -120,7 +120,7 @@ void getHasPlateTrain(Mat& trainingImages, vector& trainingLabels, //cout << files[i].c_str() << endl; Mat img = imread(files[i].c_str()); - //ûص + //调用回调函数决定特征 Mat features; getFeatures(img, features); features = features.reshape(1, 1); @@ -138,7 +138,7 @@ void getNoPlateTrain(Mat& trainingImages, vector& trainingLabels, char * filePath = "train/data/plate_detect_svm/train/NoPlate"; vector files; - ////ȡ·µļ + ////获取该路径下的所有文件 getFiles(filePath, files ); int size = files.size(); @@ -151,7 +151,7 @@ void getNoPlateTrain(Mat& trainingImages, vector& trainingLabels, //cout << files[i].c_str() << endl; Mat img = imread(files[i].c_str()); - //ûص + //调用回调函数决定特征 Mat features; getFeatures(img, features); features = features.reshape(1, 1); @@ -167,7 +167,7 @@ void getHasPlateTest(vector& testingImages, vector& testingLabels) char * filePath = "train/data/plate_detect_svm/test/HasPlate"; vector files; - ////ȡ·µļ + ////获取该路径下的所有文件 getFiles(filePath, files ); int size = files.size(); @@ -191,7 +191,7 @@ void getNoPlateTest(vector& testingImages, vector& testingLabels) char * filePath = "train/data/plate_detect_svm/test/NoPlate"; vector files; - ////ȡ·µļ + ////获取该路径下的所有文件 getFiles(filePath, files ); int size = files.size(); @@ -210,7 +210,7 @@ void getNoPlateTest(vector& testingImages, vector& testingLabels) } -//! SVM׼ȷʣعԼFScore +//! 测试SVM的准确率,回归率以及FScore void getAccuracy(Mat& testingclasses_preditc, Mat& testingclasses_real) { int channels = testingclasses_preditc.channels(); @@ -312,13 +312,13 @@ int svmTrain(bool dividePrepared = true, bool trainPrepared = true, if (dividePrepared == false) { - //ָlearnݵtraintest + //分割learn里的数据到train和test里 cout << "Divide learn to train and test" << endl; learn2HasPlate(); learn2NoPlate(); } - //ѵݼڴ + //将训练数据加载入内存 if (trainPrepared == false) { cout << "Begin to get train data to memory" << endl; @@ -335,7 +335,7 @@ int svmTrain(bool dividePrepared = true, bool trainPrepared = true, vector testingImages; vector testingLabels_real; - //ݼڴ + //将测试数据加载入内存 cout << "Begin to get test data to memory" << endl; getHasPlateTest(testingImages, testingLabels_real); getNoPlateTest(testingImages, testingLabels_real); @@ -345,8 +345,8 @@ int svmTrain(bool dividePrepared = true, bool trainPrepared = true, { CvSVMParams SVM_params; SVM_params.svm_type = CvSVM::C_SVC; - //SVM_params.kernel_type = CvSVM::LINEAR; //CvSVM::LINEAR; ͣҲ޺ - SVM_params.kernel_type = CvSVM::RBF; //CvSVM::RBF ҲǸ˹ + //SVM_params.kernel_type = CvSVM::LINEAR; //CvSVM::LINEAR; 线型,也就是无核 + SVM_params.kernel_type = CvSVM::RBF; //CvSVM::RBF 径向基函数,也就是高斯核 SVM_params.degree = 0.1; SVM_params.gamma = 1; SVM_params.coef0 = 0.1; @@ -393,7 +393,7 @@ int svmTrain(bool dividePrepared = true, bool trainPrepared = true, //cout << files[i].c_str() << endl; Mat p = testingImages[i]; - //ûص + //调用回调函数决定特征 Mat features; getFeatures(p, features); diff --git a/src/util/deface.cpp b/src/util/deface.cpp index 3a1d970..0007484 100644 --- a/src/util/deface.cpp +++ b/src/util/deface.cpp @@ -1,9 +1,9 @@ // // main.cpp -// +// 人脸马赛克 // // Created by zhou shiwei on 15/1/20. -// Copyright (c) 2015 zhou shiwei. All rights reserved. +// Copyright (c) 2015年 zhou shiwei. All rights reserved. // // Modified by liu ruoze on 15/1/23 @@ -15,9 +15,9 @@ #include #include -// ʶļ -// ڷݵgeneral_testݼķͼд -// EasyPRԴĿdzעرͼƬмʻ˵˽ +// 反人脸识别文件 +// 在发布数据到general_test数据集里,请先用这里的方法对图像进行处理 +// EasyPR开源项目非常注重保护图片中驾驶人的隐私 #include "../include/plate_recognize.h" #include "../include/util.h" @@ -29,9 +29,9 @@ using namespace cv; Mat detectAndMaskFace(Mat& img, CascadeClassifier& cascade, double scale ); -// ʶ -// ڷݵgeneral_testݼķͼд -// EasyPRԴĿdzעرͼƬмʻ˵˽ +// 反人脸识别函数 +// 在发布数据到general_test数据集里,请先用这里的方法对图像进行处理 +// EasyPR开源项目非常注重保护图片中驾驶人的隐私 int deface() { CascadeClassifier cascade; diff --git a/src/util/general_test_prepare.cpp b/src/util/general_test_prepare.cpp index acaae03..1c84427 100644 --- a/src/util/general_test_prepare.cpp +++ b/src/util/general_test_prepare.cpp @@ -1,6 +1,6 @@ -// general_testеͼƬ -// ͨʹeasyprζȡͼƬеһʶָͼƬ -// easyprʶֲһ׼ȷҪٴȷֹ +// 辅助生成general_test中的图片 +// 通用做法是使用easypr依次读取图片,并用其中的一个车牌识别文字给图片重命名 +// easypr识别的文字不一定准确,因此需要人再次确认与手工调整下 #include "../include/plate_recognize.h" #include "../include/util.h" @@ -10,12 +10,12 @@ using namespace easypr; extern const string GENERAL_TEST_PATH; -// TODO ·ij +// TODO 将下面的路径改成你的 const string your_data_path = "F:/data/easypr-data/tmp-2"; int general_test() { - ////ȡ·µļ + ////获取该路径下的所有文件 vector files; getFiles(your_data_path, files); @@ -43,7 +43,7 @@ int general_test() string filepath = files[i].c_str(); cout << "------------------" << endl; - // EasyPRʼжϳ + // EasyPR开始判断车牌 Mat src = imread(filepath); vector plateVec; @@ -54,14 +54,14 @@ int general_test() if (num == 0) { - cout << ""<< "޳" < spilt_plate; SplitString(colorplate, spilt_plate, ":"); @@ -76,7 +76,7 @@ int general_test() } else { - cout << ":" << result << endl; + cout << "错误码:" << result << endl; } } diff --git a/src/util/generate_gdts.cpp b/src/util/generate_gdts.cpp index d3e2dab..50480df 100644 --- a/src/util/generate_gdts.cpp +++ b/src/util/generate_gdts.cpp @@ -1,7 +1,7 @@ -// GDTSļ -// ھݵGDTSݼķͼԤ -// EasyPRԴĿdzעرԭʼͼƬİȨ -// еľͨGDSLЭԼ֤ʹ˽ڷҵĿ +// 生成GDTS的文件 +// 在捐赠数据到GDTS数据集里,请先用这里的方法对图像进行预处理 +// EasyPR开源项目非常注重保护原始图片的版权 +// 所有的捐赠数据通过GDSL协议进行约定,保证使用人仅用于非商业性目的 #include "../include/plate_recognize.h" #include "../include/util.h" @@ -9,15 +9,15 @@ using namespace easypr; -// TODO ·ijԭʼͼƬ· -// ͼƬҪ࣬10-30ž㹻ˣEasyPRGDTSݼʹòΪҪָ -// ֻҪЩͼƬ㹻ӳݼҪ +// TODO 将下面的路径改成你的原始图片路径 +// 图片不要多,10-30张就足够了,EasyPR对GDTS数据集的使用不以量为主要指标 +// 只要这些图片足够反映你数据集的主要特征即可 const string src_path = "F:/data/easypr-data/tmp-1"; -// TODO ·ijϣɾGDTSݴŵ· +// TODO 将下面的路径改成你希望生成捐赠给GDTS数据存放的新路径 const string dst_path = "F:/data/easypr-data/tmp-2"; -// EasyPRͼԤģü +// EasyPR的图像预处理函数,进行模糊化与裁剪化处理 Mat imageProcess(Mat src); Mat detectAndMaskFace(Mat& img, CascadeClassifier& cascade, @@ -25,12 +25,12 @@ Mat detectAndMaskFace(Mat& img, CascadeClassifier& cascade, int generate_gdts() { - // ȡʶļ + // 获取人脸识别文件 CascadeClassifier cascade; //string cascadeName="/Users/zhoushiwei/Dropbox/Avatar/SDMLIB/haarcascade_frontalface_alt2.xml"; string cascadeName="model/haarcascade_frontalface_default.xml"; - ////ȡ·µļ + ////获取该路径下的所有文件 vector files; getFiles(src_path, files); int size = files.size(); @@ -49,16 +49,16 @@ int generate_gdts() cout << "------------------" << endl; cout << filepath << endl; - // EasyPRȡԭͼƬ + // EasyPR读取原图片 Mat src = imread(filepath); - // EasyPRʼͼƬģü + // EasyPR开始对图片进行模糊化与裁剪化处理 Mat img = imageProcess(src); - // EasyPRʼͼƬʶ + // EasyPR开始对图片进行人脸识别处理 Mat dst = detectAndMaskFace(img, cascade, 1.5); - // ͼƬ· + // 将图片导出到新路径 vector spilt_path; SplitString(filepath, spilt_path, "\\"); int spiltsize = spilt_path.size(); @@ -110,7 +110,7 @@ int generate_gdts() -// EasyPRͼԤģü +// EasyPR的图像预处理函数,进行模糊化与裁剪化处理 Mat imageProcess(Mat img) { int width = img.size().width; diff --git a/src/util/learn_prepare.cpp b/src/util/learn_prepare.cpp index 4a50033..9feff99 100644 --- a/src/util/learn_prepare.cpp +++ b/src/util/learn_prepare.cpp @@ -1,29 +1,29 @@ // learn data_prepare : -// learn datacpplearn dataָtrain dataverify data test dataܺͣġ -// learn dataӦñǩݣ˼ͨEasyPRԶԺҲҪΪһ. +// 生成learn data的cpp,learn data指的是train data,verify data, test data的总和,这个名字是我起的。 +// learn data应该是贴好标签的数据,因此即便通过EasyPR自动化处理以后,也要人为的修正一下. -// ӦðµIJ˳֯learn data -// 1.EasyPRnot label dataдͨEasyPRԳͼƬбǩŵͬļ£ -// 2.ǩ֣һгƵģһ޳Ƶģ -// 2.EasyPRɱǩԺ㻹Ҫȷ£ȷǩתƵǸȥļ£ -// 3.ͨIJ裬ȷijͼƬͷdzͼƬѾֱŵļ£hasplatenoplate -// 4.ļзŵEasyPRĿ¼train/data/plate_detect_svm/learn -// 5.EasyPRѡѵĿ¼µġƼ⣨not divideԶlearn dataֿ飬ѵ +// 你应该按照如下的步骤和顺序组织learn data: +// 1.用EasyPR对not label data进行处理,通过EasyPR辅助来对车牌图片进行标签(放到不同文件夹下); +// 2.标签分两种,一种是有车牌的,一种是无车牌的; +// 2.EasyPR生成标签以后,你还得需要肉眼确认下,将被不正确标签的数据转移到它们该去的文件夹下; +// 3.通过上面的步骤,正确的车牌图片和非车牌图片已经被分别放到两个文件下,假设是hasplate和noplate; +// 4.将这两个文件夹放到EasyPR目录train/data/plate_detect_svm/learn下面 +// 5.运行EasyPR,选择“训练”目录下的“车牌检测(not divide)”,这个程序会自动把learn data分块,训练,测试 #include "../include/plate_recognize.h" #include "../include/util.h" using namespace easypr; -//! ·ijλ +//! 将以下路径改成你的位置 char * notlabelPath = "F:/data/easypr-data/notlabel"; char * hasPaltePath = "F:/data/easypr-data/learn/hasPlate/"; char * noPlatePath = "F:/data/easypr-data/learn/noPlate/"; -//! ȡnot label datalearn data +//! 读取not label data,生成learn data void label_data() { - ////ȡ·µļ + ////获取该路径下的所有文件 vector files; getFiles(notlabelPath, files); diff --git a/src/util/mc_data_prepare.cpp b/src/util/mc_data_prepare.cpp index 6b97b41..2c82e33 100644 --- a/src/util/mc_data_prepare.cpp +++ b/src/util/mc_data_prepare.cpp @@ -1,7 +1,7 @@ // mc_data_prepare.cpp : -// ԤijҪ -// 1.ȡԭ rawdata -// 2./ѡԵѡȡݳΪlearndataݲãһΪ1000100001 +// 数据预处理的程序,主要做以下两件事 +// 1.读取原生数据 rawdata,这可能有数百万张 +// 2.随机/选择性地选取部分数据成为learndata,这个根据参数设置,一般设置为1000,10000,或者1百万 #include #include @@ -19,65 +19,65 @@ const int LEARANDATA_COUNT = 1000; void getFiles( string path, vector& files ); void SplitString(const string& s, vector& v, const string& c); -//! ʡݶӦmap +//! 省份对应map map mc_map; void Code2Province(const string& code, string& province) { if (mc_map.empty()) { - mc_map.insert(pair("E00","δʶ")); - mc_map.insert(pair("A01","")); - mc_map.insert(pair("A02","")); - mc_map.insert(pair("A03","")); - mc_map.insert(pair("A04","")); - mc_map.insert(pair("B01","")); - mc_map.insert(pair("B02","")); - mc_map.insert(pair("B03","")); - mc_map.insert(pair("B04","")); - mc_map.insert(pair("B05","")); - mc_map.insert(pair("S01","")); - mc_map.insert(pair("S02","")); - mc_map.insert(pair("S03","")); - mc_map.insert(pair("S04","")); - mc_map.insert(pair("S05","")); - mc_map.insert(pair("S06","")); - mc_map.insert(pair("S07","")); - mc_map.insert(pair("S08","")); - mc_map.insert(pair("S09","")); - mc_map.insert(pair("S10","ԥ")); - mc_map.insert(pair("S11","")); - mc_map.insert(pair("S12","")); - mc_map.insert(pair("S13","")); - mc_map.insert(pair("S14","")); - mc_map.insert(pair("S15","")); - mc_map.insert(pair("S16","")); - mc_map.insert(pair("S17","")); - mc_map.insert(pair("S18","³")); - mc_map.insert(pair("S19","")); - mc_map.insert(pair("S20","")); - mc_map.insert(pair("S21","")); - mc_map.insert(pair("S22","")); - mc_map.insert(pair("J01","")); - mc_map.insert(pair("J02","")); - mc_map.insert(pair("J03","")); - mc_map.insert(pair("J04","")); - mc_map.insert(pair("J05","")); - mc_map.insert(pair("J06","")); - mc_map.insert(pair("J07","")); - mc_map.insert(pair("J08","")); - mc_map.insert(pair("J09","")); - mc_map.insert(pair("J10","")); + mc_map.insert(pair("E00","未识别")); + mc_map.insert(pair("A01","京")); + mc_map.insert(pair("A02","津")); + mc_map.insert(pair("A03","沪")); + mc_map.insert(pair("A04","渝")); + mc_map.insert(pair("B01","桂")); + mc_map.insert(pair("B02","蒙")); + mc_map.insert(pair("B03","宁")); + mc_map.insert(pair("B04","新")); + mc_map.insert(pair("B05","藏")); + mc_map.insert(pair("S01","皖")); + mc_map.insert(pair("S02","闽")); + mc_map.insert(pair("S03","粤")); + mc_map.insert(pair("S04","甘")); + mc_map.insert(pair("S05","贵")); + mc_map.insert(pair("S06","鄂")); + mc_map.insert(pair("S07","冀")); + mc_map.insert(pair("S08","黑")); + mc_map.insert(pair("S09","湘")); + mc_map.insert(pair("S10","豫")); + mc_map.insert(pair("S11","琼")); + mc_map.insert(pair("S12","吉")); + mc_map.insert(pair("S13","苏")); + mc_map.insert(pair("S14","赣")); + mc_map.insert(pair("S15","辽")); + mc_map.insert(pair("S16","青")); + mc_map.insert(pair("S17","川")); + mc_map.insert(pair("S18","鲁")); + mc_map.insert(pair("S19","陕")); + mc_map.insert(pair("S20","晋")); + mc_map.insert(pair("S21","云")); + mc_map.insert(pair("S22","浙")); + mc_map.insert(pair("J01","军")); + mc_map.insert(pair("J02","海")); + mc_map.insert(pair("J03","空")); + mc_map.insert(pair("J04","北")); + mc_map.insert(pair("J05","成")); + mc_map.insert(pair("J06","广")); + mc_map.insert(pair("J07","济")); + mc_map.insert(pair("J08","兰")); + mc_map.insert(pair("J09","南")); + mc_map.insert(pair("J10","沈")); } if (mc_map.count(code)) province = mc_map[code]; else - province = ""; + province = "无"; } -//MCȥϲײŵϸ +//MC:切去上部与底部干扰的细节 Mat cutBottom(Mat img) { int width = img.size().width; @@ -87,7 +87,7 @@ Mat cutBottom(Mat img) return dst; } -//MCfilepathʾF:\data\easypr-data\learndata\20150110132005-210028-S18-H3952K.jpg +//MC:filepath示例:F:\data\easypr-data\learndata\20150110132005-210028-S18-H3952K.jpg bool isNotNight(const string& filepath) { vector spilt_path; @@ -110,8 +110,8 @@ bool isNotNight(const string& filepath) datestr = spilt_name[0]; if (datestr != "") { - //"20150110132005", ʱڵ67λ - //10㵽2ͼƬȡ + //"20150110132005", 时间在第6,7个位置 + //将早上10点到下午2点的图片截取出来 string hourstr = datestr.substr(8, 2); if ( hourstr <= "14" && hourstr >= "10") return true; @@ -123,7 +123,7 @@ bool isNotNight(const string& filepath) return false; } -//! MCrawdataļ·learndata +//! MC:将rawdata的文件换个路径到learndata里 bool getNewPath(const string& filepath, string& newfilepath) { string writePath = "F:/data/easypr-data/learndata/"; @@ -142,7 +142,7 @@ bool getNewPath(const string& filepath, string& newfilepath) } -//! MCͨfilepathȡƺ +//! MC:通过filepath获取车牌号码 void getPlateLicense(const string& filepath, string& plateLicense) { vector spilt_path; @@ -164,10 +164,10 @@ void getPlateLicense(const string& filepath, string& plateLicense) string provinceStr = ""; if (name_size != 0) { - // plateStrһַ".jpg" + // plateStr是最后一个字符串,包括后面的".jpg" plateStr = spilt_name[name_size-1]; - // ".jpg"ȥ + // 将".jpg"去掉 vector spilt_plate; SplitString(plateStr, spilt_plate, "."); int plate_size = spilt_plate.size(); @@ -177,7 +177,7 @@ void getPlateLicense(const string& filepath, string& plateLicense) rawplate = spilt_plate[0]; } - // provinceStrǵڶַҪ"S13""" + // provinceStr是倒数第二个字符串,主要是"S13"代表"苏" provinceCode = spilt_name[name_size-2]; Code2Province(provinceCode, provinceStr); plateLicense = provinceStr + rawplate; @@ -187,12 +187,12 @@ void getPlateLicense(const string& filepath, string& plateLicense) } -//! MCrawdataȡݵlearndata +//! MC:将rawdata截取部分数据到learndata中 void getLearnData() { char * filePath = "F:/data/easypr-data/rawdata"; - ////ȡ·µļ + ////获取该路径下的所有文件 vector files; getFiles(filePath, files ); @@ -200,11 +200,11 @@ void getLearnData() if (0 == size) cout << "No File Found in rawdata!" << endl; - ////rawdata + ////随机排列rawdata srand(unsigned(time(NULL))); random_shuffle(files.begin(), files.end()); - ////ѡȡǰLEARANDATA_COUNTrawdataΪlearndata + ////选取前LEARANDATA_COUNT个rawdata数据作为learndata int boundry = LEARANDATA_COUNT; int count = 0; cout << "Save learndata!" << endl; @@ -213,15 +213,15 @@ void getLearnData() cout << files[i].c_str() << endl; string filepath = files[i].c_str(); - //ֻ + //只处理白天的数据 if (isNotNight(filepath)!=true) continue; - //ȡݣͼƬԤ + //读取数据,并对图片进行预处理 Mat img = imread(filepath); img = cutBottom(img); - //洢·滻Ϊµ + //存储路径替换为新的 string newfilepath = ""; getNewPath(filepath, newfilepath); @@ -238,13 +238,13 @@ void getLearnData() } } -//! ļ滻صMCcode滻Ϊprovince +//! 将文件名称替换,重点是MC的code替换为province void changeFileName() { //char * filePath = "F:/data/easypr-data/learndata"; char * filePath = "F:/data/PlateLocate/pic1"; - ////ȡ·µļ + ////获取该路径下的所有文件 vector files; getFiles(filePath, files ); @@ -257,7 +257,7 @@ void changeFileName() cout << files[i].c_str() << endl; string filepath = files[i].c_str(); - //ȡݣͼƬԤ + //读取数据,并对图片进行预处理 Mat img = imread(filepath); img = cutBottom(img); diff --git a/src/util/util.cpp b/src/util/util.cpp index b010d4a..e4dcd39 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -10,17 +10,17 @@ using namespace std; void getFiles(string path, vector& files) { - //ļ + //文件句柄 long hFile = 0; - //ļϢ + //文件信息 struct _finddata_t fileinfo; string p; if((hFile = _findfirst(p.assign(path).append("\\*").c_str(),&fileinfo)) != -1) { do { - //Ŀ¼,֮ - //,б + //如果是目录,迭代之 + //如果不是,加入列表 if((fileinfo.attrib & _A_SUBDIR)) { if(strcmp(fileinfo.name,".") != 0 && strcmp(fileinfo.name,"..") != 0) @@ -35,7 +35,7 @@ void getFiles(string path, vector& files) } } -//C++spilt +//C++的spilt函数 void SplitString(const string& s, vector& v, const string& c) { std::string::size_type pos1, pos2; @@ -53,7 +53,7 @@ void SplitString(const string& s, vector& v, const string& c) } -//! ͨļƻȡļ׺ +//! 通过文件夹名称获取文件名,不包括后缀 void getFileName(const string& filepath, string& name) { vector spilt_path;