对于一个车牌识别系统,准确和快速应该是值得关注的。为了进一步学习车牌识别系统EasyPR,我在MFC可视化界面中添加了车牌批量识别和批量识别时显示以下数据的功能:识别结果,车牌检测时间,车牌颜色识别时间,字符识别时间。
1. 可视化界面功能简介
目前可视化界面功能可以选择单张车牌识别和车牌批量识别功能,单张车牌识别的界面参考车牌识别系统easyPR的MFC可视化界面,车牌批量识别界面如下图所示。
通过“Choose Folder”选择好待识别文件夹之后,按下”Start”按钮,程序将依次识别文件夹中的车牌,单张车牌的相关数据会依次显示在表格中。EasyPR作者给出的测试资源的所有图片均用其实际车牌来命名,在批量测试时在界面中显示出文件名和识别结果,这样可以比较直观的判断识别结果是否准确。如果读者自建测试图库,推荐按照EasyPR作者的方法对图库中的文件按照车牌来进行命名。
在车牌批量识别界面中的各阶段执行时间的单位均为ms。具体测试时间与电脑配置有关。
本文的相关源码已更新至博主的Github中,还请各位读者多多指教。
2. MFC的CTabCtr使用方法记录
当前MFC界面中,车牌单张识别界面和车牌批量识别界面是用CTabCtrl控件来实现切换的,在这里记录一下该控件的使用方法,以便后续查询。若有同学需要参考,可以对照相应功能与源码。
2.1 假定目前在项目rc中已有三个对话框(可直接在项目rc右键新增对话框),对话框ID分别为TESTPR, TESTPR_BATCH,TESTPR_SINGLE,为这三个对话框分别添加类。
2.2 设置ID为BATCH_DLG,SINGLE_DLG对话框的属性:
外观–>Style–>Child
外观–>Border–>none
2.3 三个对话框中均需要包含OnPaint函数,若类创建时没有该函数,可以手动添加。
2.4 在ID为TEST_PR的对话框中添加CTabCtrl控件,在头文件中添加指向该控件,指向TESTPR_BATCH,和TESTPR_SINGLE的指针,在oninitialDialog函数中对这些变量进行初始化。类处理文件生成时不一定有oninitialDialog函数,可以手动添加。函数添加完成后,在该函数中添加如下代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
m_batchTestDlg=newCBatchTest();
m_singleTestDlg=newCSingleTest();
m_batchTestDlg->Create(IDD_TESTPR_BATCH,GetDlgItem(IDC_EASYPRTAB));
m_singleTestDlg->Create(IDD_TESTPR_SINGLE,GetDlgItem(IDC_EASYPRTAB));
m_easyprTab=((CTabCtrl*)GetDlgItem(IDC_EASYPRTAB));
m_easyprTab->InsertItem(0,_T("Single Test"));
m_easyprTab->InsertItem(1,_T("Batch Test"));
CRectrs;
m_easyprTab->GetClientRect(&rs);
rs.top+=25;
rs.bottom-=5;
rs.left+=5;
rs.right-=5;
m_batchTestDlg->MoveWindow(&rs);
m_singleTestDlg->MoveWindow(&rs);
m_batchTestDlg->ShowWindow(false);
m_singleTestDlg->ShowWindow(true);
m_easyprTab->SetCurSel(0);
3. MFC的CListCtrl使用方法记录
3.1 在BatchDlg对话框中添加CListCtrl控件,在.h和.cpp中添加指向CListCtrl空间的全局变量。
3.2 在BatchDlg.cpp中添加oninitialDialog函数,在函数中添加设置CListCtrl表头和表格风格的代码:
3.3 在批量识别过程中,根据识别结果依次填充表格内容,此部分可以根据功能查阅相关源码。
4. 依次获取文件夹中的图像文件
批量识别功能实现时,用户选择待识别的文件夹,程序中会从该文件夹中读取图像文件,依次识别,处理代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
CFileFindfileFinder;//类CFileFind执行本地文件查找
CStringstrPicFile=TEXT("");//
CStringstrFilePath;//保存文件路径
CStringstrFileName;//保存文件名
intnIndex=0;
do
{
if(m_folderPath.Right(1)==TEXT("\\"))
{
intnPos=m_folderPath.ReverseFind(TEXT('\\'));
m_folderPath=m_folderPath.Left(nPos);
}
strPicFile.Format(TEXT("%s\\%s"),m_folderPath,TEXT("*.jpg"));//只选择jpg格式的图片
BOOLbWorking=fileFinder.FindFile(strPicFile);
while(bWorking)
{
bWorking=fileFinder.FindNextFile();
if(fileFinder.IsDots())//IsDots判断是否为点,由CFileFind对象引用IsDots的意思是:这是一个目录并且不是这个目录本身或者上层目录
{
continue;
}
strFilePath=fileFinder.GetFilePath();//图片的完整路径
strFileName=fileFinder.GetFileName();//图片文件的名字
if(fileFinder.IsDirectory())//检查是否是文件夹,是返回true,不是返回false
{
//继续遍历目录
continue;
}
else
{
intnPos=strFilePath.ReverseFind(TEXT('.'));
CStringstrExt=strFilePath.Right(strFilePath.GetLength()-nPos-1);
if(strExt.CompareNoCase(TEXT("jpg"))==0||
strExt.CompareNoCase(TEXT("jpeg"))==0||
strExt.CompareNoCase(TEXT("bmp"))==0)
{
//要进行的批量操作
processPlate(strFilePath);
m_BatchList->InsertItem(nIndex,strFileName);//插入行
m_BatchList->SetItemText(nIndex,1,m_plateResult);//设置该行的不同列的显示字符
m_BatchList->SetItemText(nIndex,2,m_pdTime);//设置该行的不同列的显示字符
m_BatchList->SetItemText(nIndex,3,m_colorTime);//设置该行的不同列的显示字符
m_BatchList->SetItemText(nIndex,4,m_crTime);//设置该行的不同列的显示字符
nIndex++;
}
}
}
}while(fileFinder.FindNextFile());
fileFinder.Close();
5. 函数执行时间测试
测试函数执行时间用到了QueryPerformanceCounter和QueryPerformanceFrequency,以测试车牌检测的时间为例,使用方法如下:
1
2
3
4
5
6
7
8
9
10
11
LARGE_INTEGERnFreq;
LARGE_INTEGERstart,end;
doubleeslapsPD;
QueryPerformanceFrequency(&nFreq);//返回每秒嘀哒声的个数,即频率
QueryPerformanceCounter(&start);//获取开始时计数器的数值
intresultPD=pd.plateDetect(src,plateVec);//车牌检测
QueryPerformanceCounter(&end);//获取结束时计数器的数值
eslapsPD=(double)(end.QuadPart-start.QuadPart)/(double)nFreq.QuadPart;//获取车牌检测的时间
6. 参考资料