1.3 beta 更新

1.3
liuruoze 10 years ago
parent 65754ff030
commit 99c7dd555d

3
.gitignore vendored

@ -196,3 +196,6 @@ EasyPR.xcodeproj/
# Debug tmp files
tmp/
# native_test files
native_test/

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
@ -59,6 +59,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<Profile>true</Profile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -129,4 +130,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

@ -11,11 +11,9 @@ EasyPR是一个中文的开源车牌识别系统其目标是成为一个简
### 更新
本次更新是1.3alpha版主要改进在于提升了字符识别模块的准确性
本次更新是1.3beta版主要改进在于提升了字符识别模块的准确性
平均字符差距从2.0降低到0.7完整匹配度从25%左右上升到目前的68%。
同时车牌定位模块准确率进一步提升从上一个版本的94%上升到现在的99%。见下图:
平均字符差距从0.7降低到0.4完整匹配度从68%左右上升到目前的82%。 见下图:
![1.3版综合效果](doc/res/testresult_1.3.png)
@ -35,8 +33,8 @@ EasyPR是一个中文的开源车牌识别系统其目标是成为一个简
|------|-------|-------|-------
| android | goldriver | 1.1 | [linuxxx/EasyPR_Android](https://github.com/linuxxx/EasyPR_Android)
| linux | Micooz | 1.3 | 已跟EasyPR整合
| ios | zhoushiwei | 1.1 | [zhoushiwei/EasyPR-iOS](https://github.com/zhoushiwei/EasyPR-iOS)
| mac | zhoushiwei | 1.1 | [zhoushiwei/EasyPR](https://github.com/zhoushiwei/EasyPR)
| ios | zhoushiwei | 1.3 | [zhoushiwei/EasyPR-iOS](https://github.com/zhoushiwei/EasyPR-iOS)
| mac | zhoushiwei,Micooz | 1.3 | 已跟EasyPR整合
| java | fan-wenjie | 1.2 | [fan-wenjie/EasyPR-Java](https://github.com/fan-wenjie/EasyPR-Java)
### 兼容性
@ -66,7 +64,9 @@ EasyPR不需要安装开发者直接在其上做改动。如果想使用DLL
### 使用
使用Git克隆一份拷贝到你本机或者直接下载zip压缩吧。使用vs2010或以上版本的IDE选择“从现有代码创建项目”引用EasyPR的目录。
使用Git克隆一份拷贝到你本机或者直接下载zip压缩吧。
使用vs2010或以上版本的IDE选择“从现有代码创建项目”引用EasyPR的目录项目类型切记选择"控制台类型"。
以下表格是本工程中所有目录的解释:
@ -126,9 +126,9 @@ EasyPR不需要安装开发者直接在其上做改动。如果想使用DLL
* liuruoze1.0-1.2版核心代码作者
* 海豚嘎嘎1.3版作者,提升了字符识别准确率
* 海豚嘎嘎1.3版作者,提升了车牌定位与字符识别准确率
* Micoozlinux平台编译性能优化util类
* Micoozlinux与mac的跨平台编译性能优化util类
* jsxyheludeface版本一

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

File diff suppressed because it is too large Load Diff

@ -961,3 +961,71 @@
总图片数:120张, 未识出图片:2张, 定位率:98.3333%
平均字符差距:0.652542个, 完全匹配数:81张, 完全匹配率:68.6441%
总时间:234秒, 平均执行时间:1.95秒
2015-05-05 17:01:19
总图片数:120张, 未识出图片:2张, 定位率:98.3333%
平均字符差距:0.415254个, 完全匹配数:96张, 完全匹配率:81.3559%
总时间:235秒, 平均执行时间:1.95833秒
2015-05-05 18:16:11
总图片数:120张, 未识出图片:3张, 定位率:97.5%
平均字符差距:0.982906个, 完全匹配数:69张, 完全匹配率:58.9744%
总时间:175秒, 平均执行时间:1.45833秒
2015-05-05 18:21:27
总图片数:120张, 未识出图片:2张, 定位率:98.3333%
平均字符差距:0.415254个, 完全匹配数:96张, 完全匹配率:81.3559%
总时间:193秒, 平均执行时间:1.60833秒
2015-05-05 18:27:28
总图片数:1张, 未识出图片:0张, 定位率:100%
平均字符差距:0个, 完全匹配数:1张, 完全匹配率:100%
总时间:0秒, 平均执行时间:0秒
2015-05-05 18:31:09
总图片数:120张, 未识出图片:2张, 定位率:98.3333%
平均字符差距:0.415254个, 完全匹配数:96张, 完全匹配率:81.3559%
总时间:219秒, 平均执行时间:1.825秒
2015-05-06 21:13:22
总图片数:120张, 未识出图片:2张, 定位率:98.3333%
平均字符差距:0.415254个, 完全匹配数:96张, 完全匹配率:81.3559%
总时间:452秒, 平均执行时间:3.76667秒
2015-05-06 22:22:21
总图片数:120张, 未识出图片:2张, 定位率:98.3333%
平均字符差距:0.415254个, 完全匹配数:96张, 完全匹配率:81.3559%
总时间:434秒, 平均执行时间:3.61667秒
2015-05-06 22:52:03
总图片数:120张, 未识出图片:2张, 定位率:98.3333%
平均字符差距:0.415254个, 完全匹配数:96张, 完全匹配率:81.3559%
总时间:199秒, 平均执行时间:1.65833秒
2015-05-06 22:58:48
总图片数:120张, 未识出图片:2张, 定位率:98.3333%
平均字符差距:0.415254个, 完全匹配数:96张, 完全匹配率:81.3559%
总时间:188秒, 平均执行时间:1.56667秒
2015-05-08 17:00:15
总图片数:120张, 未识出图片:2张, 定位率:98.3333%
平均字符差距:0.415254个, 完全匹配数:96张, 完全匹配率:81.3559%
总时间:4176秒, 平均执行时间:34.8秒
2015-05-10 10:19:02
总图片数:9张, 未识出图片:7张, 定位率:22.2222%
平均字符差距:3个, 完全匹配数:0张, 完全匹配率:0%
总时间:21秒, 平均执行时间:2.33333秒
2015-05-10 11:21:09
总图片数:17张, 未识出图片:15张, 定位率:11.7647%
平均字符差距:3个, 完全匹配数:0张, 完全匹配率:0%
总时间:69秒, 平均执行时间:4.05882秒
2015-05-10 11:31:27
总图片数:6张, 未识出图片:0张, 定位率:100%
平均字符差距:3.33333个, 完全匹配数:1张, 完全匹配率:16.6667%
总时间:95秒, 平均执行时间:15.8333秒
2015-05-10 12:00:56
总图片数:47张, 未识出图片:20张, 定位率:57.4468%
平均字符差距:2.66667个, 完全匹配数:8张, 完全匹配率:29.6296%
总时间:33秒, 平均执行时间:0.702128秒
2015-05-10 12:02:47
总图片数:47张, 未识出图片:20张, 定位率:57.4468%
平均字符差距:2.66667个, 完全匹配数:8张, 完全匹配率:29.6296%
总时间:34秒, 平均执行时间:0.723404秒
2015-05-13 21:08:17
总图片数:50张, 未识出图片:23张, 定位率:54%
平均字符差距:2.85185个, 完全匹配数:7张, 完全匹配率:25.9259%
总时间:28秒, 平均执行时间:0.56秒
2015-06-04 20:03:57
总图片数:120张, 未识出图片:2张, 定位率:98.3333%
平均字符差距:0.398305个, 完全匹配数:96张, 完全匹配率:81.3559%
总时间:187秒, 平均执行时间:1.55833秒

File diff suppressed because it is too large Load Diff

@ -21,7 +21,7 @@ namespace easypr{
{
return m_charsIdentify->charsIdentify(plate);
}
int CCharsRecognise::charsRecognise(Mat plate, string& plateLicense, int index)
int CCharsRecognise::charsRecognise(Mat plate, string& plateLicense)
{
//车牌字符方块集合
vector<Mat> matVec;
@ -36,16 +36,16 @@ namespace easypr{
{
Mat charMat = matVec[j];
bool isChinses = false;
bool isSpeci=false;
bool isSpeci = false;
//默认首个字符块是中文字符
if (j == 0)
isChinses = true;
if(j==1)
if (j == 1)
isSpeci=true;
string charcater = m_charsIdentify->charsIdentify(charMat, isChinses,isSpeci);
string charcater = m_charsIdentify->charsIdentify(charMat, isChinses, isSpeci);
plateIdentify = plateIdentify + charcater;
}
}

@ -84,32 +84,34 @@ namespace easypr{
int h = input.rows;
Mat tmpMat = input(Rect(w*0.1,h*0.1,w*0.8,h*0.8));
//判断车牌颜色以此确认threshold方法
Color plateType = getPlateType(tmpMat, true);
Mat input_grey;
cvtColor(input, input_grey, CV_BGR2GRAY);
Mat img_threshold ;
if (BLUE == plateType)
{
//cout << "BLUE" << endl;
img_threshold = input_grey.clone();
int w = input_grey.cols;
int h = input_grey.rows;
Mat tmp = input_grey(Rect(w*0.1,h*0.1,w*0.8,h*0.8));
int threadHoldV = ThresholdOtsu(tmp);
imwrite("./image/tmp/inputgray2.jpg",input_grey);
imwrite("E:/img_inputgray2.jpg",input_grey);
threshold(input_grey, img_threshold,threadHoldV, 255, CV_THRESH_BINARY);
threshold(input_grey, img_threshold, threadHoldV, 255, CV_THRESH_BINARY);
imwrite("E:/img_threshold.jpg",img_threshold);
//threshold(input_grey, img_threshold, 5, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);
}
else if (YELLOW == plateType)
{
//cout << "YELLOW" << endl;
img_threshold = input_grey.clone();
int w = input_grey.cols;
int h = input_grey.rows;
@ -117,15 +119,34 @@ namespace easypr{
int threadHoldV = ThresholdOtsu(tmp);
imwrite("./image/tmp/inputgray2.jpg",input_grey);
threshold(input_grey, img_threshold,threadHoldV, 255, CV_THRESH_BINARY_INV);
threshold(input_grey, img_threshold, threadHoldV, 255, CV_THRESH_BINARY_INV);
//threshold(input_grey, img_threshold, 10, 255, CV_THRESH_OTSU + CV_THRESH_BINARY_INV);
}
else if (WHITE == plateType)
{
//cout << "WHITE" << endl;
/*img_threshold = input_grey.clone();
int w = input_grey.cols;
int h = input_grey.rows;
Mat tmp = input_grey(Rect(w*0.1, h*0.1, w*0.8, h*0.8));
int threadHoldV = ThresholdOtsu(tmp);
imwrite("./image/tmp/inputgray2.jpg", input_grey);*/
threshold(input_grey, img_threshold, 10, 255, CV_THRESH_OTSU + CV_THRESH_BINARY_INV);
}
else
{
//cout << "UNKNOWN" << endl;
threshold(input_grey, img_threshold, 10, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);
}
if (0)
{
imshow("threshold", img_threshold);
waitKey(0);
destroyWindow("threshold");
}
if (m_debug)
{
@ -135,6 +156,8 @@ namespace easypr{
}
//去除车牌上方的柳钉以及下方的横线等干扰
//并且也判断了是否是车牌
//并且在此对字符的跳变次数以及字符颜色所占的比重做了是否是车牌的判别条件
if(!clearLiuDing(img_threshold))
{
return -3;
@ -358,19 +381,6 @@ namespace easypr{
// 2.从特殊字符Rect开始依次选择6个Rect多余的舍去。
int CCharsSegment::RebuildRect(const vector<Rect>& vecRect, vector<Rect>& outRect, int specIndex)
{
//最大只能有7个Rect,减去中文的就只有6个Rect
//int count = 6;
//for (int i = 0; i < vecRect.size(); i++)
//{
// //将特殊字符左边的Rect去掉这个可能会去掉中文Rect不过没关系我们后面会重建。
// if (i < specIndex)
// continue;
// outRect.push_back(vecRect[i]);
// if (!--count)
// break;
//}
int count = 6;
for (size_t i = specIndex; i < vecRect.size() && count; ++i, --count) {

File diff suppressed because it is too large Load Diff

@ -87,4 +87,4 @@ namespace easypr {
//TODO
}
} /* \namespace easypr */
} /* \namespace easypr */

@ -57,7 +57,6 @@ int CPlateDetect::plateDetect(Mat src, vector<Mat>& resultVec, int index)
int CPlateDetect::plateDetectDeep(Mat src, vector<CPlate>& resultVec, bool showDetectArea, int index)
{
vector<Mat> resultPlates;
vector<CPlate> color_Plates;
@ -72,30 +71,47 @@ int CPlateDetect::plateDetectDeep(Mat src, vector<CPlate>& resultVec, bool showD
m_plateLocate->plateColorLocate(src, color_Plates, index);
m_plateJudge->plateJudge(color_Plates, color_result_Plates);
//m_plateJudge->plateJudge(color_Plates, color_result_Plates);
//下面代码是sunjunlishi添加
for (int i=0;i<color_Plates.size();++i)
{
//暂时屏蔽车牌的判断,车牌判断采用 字符跳变的方式判断
//字符跳变的形式 | | | | | | |,根据跳变的规律直接判断车牌,更准,效率更高
//当然判断跳变用的还是原始代码,在后面我加上了主食
color_result_Plates.push_back(color_Plates[i]);
}
for (int i = 0; i< color_result_Plates.size(); i++)
{
CPlate plate = color_result_Plates[i];
RotatedRect minRect = plate.getPlatePos();
Point2f rect_points[4];
minRect.points(rect_points);
all_result_Plates.push_back(plate);
}
//颜色和边界闭操作同时采用
{
m_plateLocate->plateSobelLocate(src, sobel_Plates, index);
m_plateJudge->plateJudge(sobel_Plates, sobel_result_Plates);
//m_plateJudge->plateJudge(sobel_Plates, sobel_result_Plates);
//下面代码是sunjunlishi添加
for (int i=0;i<sobel_Plates.size();++i)
{
//暂时屏蔽车牌的判断,车牌判断采用 字符跳变的方式判断
//字符跳变的形式 | | | | | | |,根据跳变的规律直接判断车牌,更准,效率更高
//当然判断跳变用的还是原始代码,在后面我加上了主食
sobel_result_Plates.push_back(sobel_Plates[i]);
}
for (int i = 0; i< sobel_result_Plates.size(); i++)
{
CPlate plate = sobel_result_Plates[i];
if (0)
{
imshow("plate_mat", plate.getPlateMat());
waitKey(0);
destroyWindow("plate_mat");
}
plate.bColored = false;
all_result_Plates.push_back(plate);
@ -108,72 +124,59 @@ int CPlateDetect::plateDetectDeep(Mat src, vector<CPlate>& resultVec, bool showD
CPlate plate = all_result_Plates[i];
resultVec.push_back(plate);
}
return 0;
}
int CPlateDetect::showResult(const Mat& result)
{
const int RESULTWIDTH = 1000; //640 930
const int RESULTHEIGHT = 810; //540 710
namedWindow("EasyPR", CV_WINDOW_AUTOSIZE);
/*if(cbgImage_ && cbgImage_->width == result.cols/4*4 && cbgImage_->height == result.rows)
{
for (int i=0;i<cbgImage_->height;++i)
{
for (int j=0;j<cbgImage_->width;++j)
{
cbgImage_->imageData[i*cbgImage_->widthStep+j*3] = result.data[i*result.step[0]+j*3+2];
cbgImage_->imageData[i*cbgImage_->widthStep+j*3+1] = result.data[i*result.step[0]+j*3+2+1];
cbgImage_->imageData[i*cbgImage_->widthStep+j*3+2] = result.data[i*result.step[0]+j*3];
}
const int RESULTWIDTH = 930; //640 930
const int RESULTHEIGHT = 710; //540 710
}
}*/
Mat img_window;
img_window.create(RESULTHEIGHT, RESULTWIDTH, CV_8UC3);
//Mat img_window;
//img_window.create(RESULTHEIGHT, RESULTWIDTH, CV_8UC3);
int nRows = result.rows;
int nCols = result.cols;
//int nRows = result.rows;
//int nCols = result.cols;
Mat result_resize;
if (nCols <= img_window.cols && nRows <= img_window.rows) {
result_resize = result;
//Mat result_resize;
//if (nCols <= img_window.cols && nRows <= img_window.rows) {
// result_resize = result;
} else if (nCols > img_window.cols && nRows <= img_window.rows) {
float scale = float(img_window.cols) / float(nCols);
resize(result, result_resize, Size(), scale, scale, CV_INTER_AREA);
//} else if (nCols > img_window.cols && nRows <= img_window.rows) {
// float scale = float(img_window.cols) / float(nCols);
// resize(result, result_resize, Size(), scale, scale, CV_INTER_AREA);
} else if (nCols <= img_window.cols && nRows > img_window.rows) {
float scale = float(img_window.rows) / float(nRows);
resize(result, result_resize, Size(), scale, scale, CV_INTER_AREA);
//} else if (nCols <= img_window.cols && nRows > img_window.rows) {
// float scale = float(img_window.rows) / float(nRows);
// resize(result, result_resize, Size(), scale, scale, CV_INTER_AREA);
} else if (nCols > img_window.cols && nRows > img_window.rows) {
Mat result_middle;
float scale = float(img_window.cols) / float(nCols);
resize(result, result_middle, Size(), scale, scale, CV_INTER_AREA);
//} else if (nCols > img_window.cols && nRows > img_window.rows) {
// Mat result_middle;
// float scale = float(img_window.cols) / float(nCols);
// resize(result, result_middle, Size(), scale, scale, CV_INTER_AREA);
if (result_middle.rows > img_window.rows) {
float scale = float(img_window.rows) / float(result_middle.rows);
resize(result_middle, result_resize, Size(), scale, scale, CV_INTER_AREA);
// if (result_middle.rows > img_window.rows) {
// float scale = float(img_window.rows) / float(result_middle.rows);
// resize(result_middle, result_resize, Size(), scale, scale, CV_INTER_AREA);
}
else {
result_resize = result_middle;
}
} else {
result_resize = result;
}
// }
// else {
// result_resize = result_middle;
// }
//} else {
// result_resize = result;
//}
Mat imageRoi = img_window(Rect((RESULTWIDTH - result_resize.cols) / 2, (RESULTHEIGHT - result_resize.rows) / 2,
result_resize.cols, result_resize.rows));
addWeighted(imageRoi, 0, result_resize, 1, 0, imageRoi);
//Mat imageRoi = img_window(Rect((RESULTWIDTH - result_resize.cols) / 2, (RESULTHEIGHT - result_resize.rows) / 2,
// result_resize.cols, result_resize.rows));
//addWeighted(imageRoi, 0, result_resize, 1, 0, imageRoi);
imshow("EasyPR", img_window);
waitKey();
//imshow("EasyPR", img_window);
destroyWindow("EasyPR");
return 0;
}

@ -117,7 +117,6 @@ int CPlateJudge::plateJudge(const vector<CPlate>& inVec,
resultVec.push_back(inPlate);
}
//resultVec.push_back(inPlate);
}
return 0;
}

File diff suppressed because it is too large Load Diff

@ -36,15 +36,16 @@ CPlateRecognize::CPlateRecognize()
// return result;
//}
int CPlateRecognize::plateRecognize(Mat src, vector<string>& licenseVec,int index)
// !³µÅÆʶ±ðÄ£¿é
int CPlateRecognize::plateRecognize(Mat src, vector<string>& licenseVec, int index)
{
// 车牌方块集合
vector<CPlate> plateVec;
// 如果设置了Debug模式就依次显示所有的图片
bool showDetectArea = getPDDebug();
showDetectArea=0;
// 进行深度定位使用颜色信息与二次Sobel
int resultPD = plateDetectDeep(src, plateVec, showDetectArea, 0);
@ -54,14 +55,11 @@ int CPlateRecognize::plateRecognize(Mat src, vector<string>& licenseVec,int inde
if (resultPD == 0)
{
int num = plateVec.size();
int resultCR = 0;
int index = 0;
for (int j = 0; j < num; j++)
{
CPlate item = plateVec[j];
CPlate item = plateVec[j];
Mat plate = item.getPlateMat();
//获取车牌颜色
@ -75,28 +73,14 @@ int CPlateRecognize::plateRecognize(Mat src, vector<string>& licenseVec,int inde
string license = plateType + ":" + plateIdentify;
licenseVec.push_back(license);
//int height = 36;
//int width = 136;
//if(height*index + height < result.rows)
//{
// Mat imageRoi = result(Rect(0, 0 + height*index, width, height));
// addWeighted(imageRoi, 0, plate, 1, 0, imageRoi);
//
// CvxText text("simhei.ttf");
// float p = 0.5;
// CvScalar size(cvScalar(8,0.5,0.1));
// text.setFont(NULL, &size, NULL, &p); // 透明处理
// text.putText(result, license.c_str(), Point(width,height*(index+1)));
//
//}
//index++;
/*int height = 36;
int width = 136;
if(height*index + height < result.rows)
{
Mat imageRoi = result(Rect(0, 0 + height*index, width, height));
addWeighted(imageRoi, 0, plate, 1, 0, imageRoi);
}
index++;*/
RotatedRect minRect = item.getPlatePos();
Point2f rect_points[4];
@ -105,28 +89,19 @@ int CPlateRecognize::plateRecognize(Mat src, vector<string>& licenseVec,int inde
if(item.bColored)
{
for (int j = 0; j < 4; j++)
{
line(result, rect_points[j], rect_points[(j + 1) % 4], Scalar(255, 255, 0), 2, 8);
//颜色定位车牌,黄色方框
}
}
else
{
for( int j = 0; j < 4; j++ )
{
line(result, rect_points[j], rect_points[(j+1)%4], Scalar(0,0,255), 2, 8 );//sobel定位车牌红色方框
}
}
}
}
}
}
showResult(result);
if (showDetectArea)
showResult(result);
return resultPD;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save