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;