【深度学习模型】智云视图中文车牌识别源码解析(二)



感受

HyperLPR可以识别多种中文车牌包括白牌,新能源车牌,使馆车牌,教练车牌,武警车牌等。 代码不可谓不混乱(别忘了这是职业公司的准产品级代码,如果是什么毕业论文我就不说了)测试驱动什么的别想了,所以可能这次更了就不更了!!


代码结构

本次是Pipeline.cpp部分;

  • CNNRecognizer.cpp:加载模型预测标签;
  • FastDeskew.cpp:快速旋转歪斜的车牌;
  • FineMapping.cpp:绘制车牌检测框;
  • Pipeline.cpp:这是串联程序,串联起了plateDetection、fineMapping、plateSegmentation、generalRecognizer、segmentationFreeRecognizer;
  • PlateDetection.cpp:探测车牌在图中何处位置;
  • PlateSegmentation.cpp:将每一个字符从车牌图像中分离;
  • Recognizer.cpp:挨个识别字符并返回识别结果;
  • SegmentationFreeRecognizer.cpp:检测单个图像并把结果保存在mapping_table;


源代码

头文件:

/*------------------------------------------------------------------*/
/*--------------用于串联多个程序实现检测识别(头文件)----------------*/
/*------------------------------------------------------------------*/#ifndef SWIFTPR_PIPLINE_H
#define SWIFTPR_PIPLINE_H#include "PlateDetection.h"
#include "PlateSegmentation.h"
#include "CNNRecognizer.h"
#include "PlateInfo.h"
#include "FastDeskew.h"
#include "FineMapping.h"
#include "Recognizer.h"
#include "SegmentationFreeRecognizer.h"namespace pr{//可能出现的字符集合;const std::vector<std::string> CH_PLATE_CODE{"京", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑", "苏", "浙", "皖", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤", "桂","琼", "川", "贵", "云", "藏", "陕", "甘", "青", "宁", "新", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A","B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X","Y", "Z","港","学","使","警","澳","挂","军","北","南","广","沈","兰","成","济","海","民","航","空"};//定义不同的分割方法的编号;                                        const int SEGMENTATION_FREE_METHOD = 0;const int SEGMENTATION_BASED_METHOD = 1;//声明主类;class PipelinePR{public://创建车牌位置检测模型实例指针;GeneralRecognizer *generalRecognizer;//创建抠出车牌图像模型实例指针;PlateDetection *plateDetection;//创建车牌分割模型实例指针;PlateSegmentation *plateSegmentation;//创建识别模型实例指针;FineMapping *fineMapping;//创建识别单个车牌图像的模型实例指针;SegmentationFreeRecognizer *segmentationFreeRecognizer;//构造函数;PipelinePR(std::string detector_filename,std::string finemapping_prototxt,std::string finemapping_caffemodel,std::string segmentation_prototxt,std::string segmentation_caffemodel,std::string charRecognization_proto,std::string charRecognization_caffemodel,std::string segmentationfree_proto,std::string segmentationfree_caffemodel);//析构函数;~PipelinePR();//保存识别结果;std::vector<std::string> plateRes;//执行单个车牌的识别;std::vector<PlateInfo> RunPiplineAsImage(cv::Mat plateImage,int method);};
}
#endif //SWIFTPR_PIPLINE_H

主程序:

/*----------------------------------------------------------*/
/*--------------用于串联多个程序实现检测识别----------------*/
/*----------------------------------------------------------*/#include "../include/Pipeline.h"namespace pr {//定义水平方向填充参数;const int HorizontalPadding = 4;/*-----------串接多个功能(构造函数)------------@detector_filename            :                         识别模型所在路径;@finemapping_prototxt         :   抠出车牌图像模型的prototxt定义文件路径;@finemapping_caffemodel       :           抠出车牌图像模型的模型文件路径;@segmentation_prototxt        : 分割图像字符的模型的prototxt定义文件路径;@segmentation_caffemodel      :         分割图像字符的模型的模型文件路径;@charRecognization_proto      :     字符识别的模型的prototxt定义文件路径;  @charRecognization_caffemodel :             字符识别的模型的模型文件路径;@segmentationfree_proto       : 识别单个车牌的模型的prototxt定义文件路径;  @segmentationfree_caffemodel  :         识别单个车牌的模型的模型文件路径;*/ PipelinePR::PipelinePR(std::string detector_filename,std::string finemapping_prototxt, std::string finemapping_caffemodel,std::string segmentation_prototxt, std::string segmentation_caffemodel,std::string charRecognization_proto, std::string charRecognization_caffemodel,std::string segmentationfree_proto,std::string segmentationfree_caffemodel) {//创建车牌位置检测模型实例指针;plateDetection = new PlateDetection(detector_filename);//创建抠出车牌图像模型实例指针;fineMapping = new FineMapping(fnemapping_prototxt, finemapping_caffemodel);//创建车牌分割模型实例指针;plateSegmentation = new PlateSegmentation(segmentation_prototxt, segmentation_caffemodel);//创建识别模型实例指针;generalRecognizer = new CNNRecognizer(charRecognization_proto, charRecognization_caffemodel);//创建识别单个车牌图像的模型实例指针;segmentationFreeRecognizer =  new SegmentationFreeRecognizer(segmentationfree_proto,segmentationfree_caffemodel);}/*-----------析构函数------------*/PipelinePR::~PipelinePR() {//删除创建的各个实例指针;delete plateDetection;delete fineMapping;delete plateSegmentation;delete generalRecognizer;delete segmentationFreeRecognizer;}/*-----------识别车牌中各个字符------------@plateImage :  包含一个/多个车牌图像;@method     :         分割方法的编码;*/std::vector<PlateInfo> PipelinePR::RunPiplineAsImage(cv::Mat plateImage,int method) {//声明结果列表;std::vector<PlateInfo> results;//保存车牌中间信息;std::vector<pr::PlateInfo> plates;//执行车牌粗略探测位置(结果存在plates内);plateDetection->plateDetectionRough(plateImage,plates,36,700);//迭代图中每个车牌;for (pr::PlateInfo plateinfo:plates) {//获取该车牌图像(image_finemapping的finemapping是为了分割出尽量只包含单个车牌的图像);cv::Mat image_finemapping = plateinfo.getPlateImage();//对图像垂直处理;image_finemapping = fineMapping->FineMappingVertical(image_finemapping);//校正角度;image_finemapping = pr::fastdeskew(image_finemapping, 5);//选择分割车牌字符的方法;//方法一:基础方法;if(method==SEGMENTATION_BASED_METHOD){//对图像水平处理;image_finemapping = fineMapping->FineMappingHorizon(image_finemapping, 2, HorizontalPadding);//大小调整;cv::resize(image_finemapping, image_finemapping, cv::Size(136+HorizontalPadding, 36));//展示;//cv::imshow("image_finemapping",image_finemapping);//cv::waitKey(0);//设定为调整后的图像;plateinfo.setPlateImage(image_finemapping);//定义矩形框列表;std::vector<cv::Rect> rects;//对车牌图像的字符分割,结果存在rects;plateSegmentation->segmentPlatePipline(plateinfo, 1, rects);//将每个rect中的字符子图又存到plateinfo中去;plateSegmentation->ExtractRegions(plateinfo, rects);//复制图像并且制作边界;处理边界卷积(将image_finemapping的黑色边界填充);cv::copyMakeBorder(image_finemapping, image_finemapping, 0, 0, 0, 20, cv::BORDER_REPLICATE);//录入plateinfo;plateinfo.setPlateImage(image_finemapping);//进行识别;generalRecognizer->SegmentBasedSequenceRecognition(plateinfo);//解码中文字符;plateinfo.decodePlateNormal(pr::CH_PLATE_CODE);}//方法二:Segmentation-freeelse if(method==SEGMENTATION_FREE_METHOD){//对图像水平处理;image_finemapping = fineMapping->FineMappingHorizon(image_finemapping, 4, HorizontalPadding+3);//大小调整;cv::resize(image_finemapping, image_finemapping, cv::Size(136+HorizontalPadding, 36));//存储图像;//cv::imwrite("./test.png",image_finemapping);//显示图像;//cv::imshow("image_finemapping",image_finemapping);//cv::waitKey(0);//录入plateinfo;plateinfo.setPlateImage(image_finemapping);//定义矩形框列表;//std::vector<cv::Rect> rects;//对单个图像进行识别;std::pair<std::string,float> res = segmentationFreeRecognizer->SegmentationFreeForSinglePlate(plateinfo.getPlateImage(),pr::CH_PLATE_CODE);//获取置信度;plateinfo.confidence = res.second;//车牌识别字符结果;plateinfo.setPlateName(res.first);}//结果加入列表;results.push_back(plateinfo);}//遍历识别结果//for (auto str:results) {//输出;//std::cout << str << std::endl;//}//返回结果;return results;}//namespace pr
}

测试程序:

/*------------------------------------------------------*/
/*--------------用于串联多个程序(测试)----------*/
/*------------------------------------------------------*/#include "../include/Pipeline.h"using namespace std;/*-----------Levenshtein距离(度量车牌识别效果)------------编辑距离Edit Distance,又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数;Levenshtein距离算法可见:https://blog.csdn.net/qq844352155/article/details/38686549;@s1 : 字符串1;@s2 : 字符串2;
*/
template<class T>
static unsigned int levenshtein_distance(const T &s1, const T &s2){//获取s1、s2的字符长;const size_t len1 = s1.size(), len2 = s2.size();//声明col和prevCol辅助计算;//col记录的是最新的计数情况;//prevCol记录的是上一轮的计数情况;std::vector<unsigned int> col(len2 + 1), prevCol(len2 + 1);//迭代给prevCol赋值;for (unsigned int i = 0; i < prevCol.size(); i++) prevCol[i] = i;//迭代比较;扫描两字符串(n*m级的);for (unsigned int i = 0; i < len1; i++) {col[0] = i + 1;//迭代遍历s2[j] in s2;for (unsigned int j = 0; j < len2; j++)//比较是否不一样,交换代价最小方式优先;col[j + 1] = min(min(prevCol[1 + j] + 1, col[j] + 1),prevCol[j] + (s1[i] == s2[j] ? 0 : 1));//col与prevCol交换其内容(swap函数:prevCol的类型要与该vector一样,大小可以不同.);col.swap(prevCol);}//返回结果;return prevCol[len2];
}/*-----------测试函数:测试识别准确率------------*/
void TEST_ACC(){//声明PipelinePR实例;pr::PipelinePR prc("model/cascade.xml","model/HorizonalFinemapping.prototxt","model/HorizonalFinemapping.caffemodel","model/Segmentation.prototxt","model/Segmentation.caffemodel","model/CharacterRecognization.prototxt","model/CharacterRecognization.caffemodel","model/SegmenationFree-Inception.prototxt","model/SegmenationFree-Inception.caffemodel");//申明文件流;ifstream file;//图片路径;string imagename;//声明计数变量;int n = 0,correct = 0,j = 0,sum = 0;//图片名文本文件路径;char filename[] = "/Users/yujinke/Downloads/general_test/1.txt";//图片文件根目录;string pathh = "/Users/yujinke/Downloads/general_test/";//打开图片名文本文件;file.open(filename, ios::in);//读取图片名文本文件;while (!file.eof()){//读取一个图片名到imagename;file >> imagename;//该图片绝对路径;string imgpath = pathh + imagename;//输出信息;std::cout << "------------------------------------------------" << endl;cout << "图片名:" << imagename << endl;//读入图片;cv::Mat image = cv::imread(imgpath);//显示图片;//cv::imshow("image", image);//cv::waitKey(0);//申明一个存储该图片车牌信息检测结果的列表,读取结果;std::vector<pr::PlateInfo> res = prc.RunPiplineAsImage(image,pr::SEGMENTATION_FREE_METHOD);//置信度变量;float conf = 0;//置信度列表;vector<float> con ;//车牌名列表;vector<string> name;//遍历结果res;for (auto st : res) {//置信度大于0.1;if (st.confidence > 0.1) {//输出检测信息及置信度;//std::cout << st.getPlateName() << " " << st.confidence << std::endl;//加入置信度列表con;con.push_back(st.confidence);//加入车牌名列表name;name.push_back(st.getPlateName());//置信度综述累计;//conf += st.confidence;}//置信度小于0.1;elsecout << "no string" << endl;}//输出置信度总数;//std::cout << conf << std::endl;//置信度列表大小;int num = con.size();//置信度最大值变量;float max = 0;//声明存储车牌字符、车牌前两个字符、车牌正确的前两个字符的变量;string platestr, chpr, ch;//声明度量车牌识别误差的变量;int diff = 0,dif = 0;//遍历置信度列表;for (int i = 0; i < num; i++) {//寻找最大的置信度下标;if (con.at(i) > max){//最大置信度max;max = con.at(i);//platestr取"最可信"(最大置信度)的结果;platestr = name.at(i);}}//输出最大置信度;//cout << "max:"<<max << endl;//输出车牌字符;cout << "string:" << platestr << endl;//车牌前两个字符;chpr = platestr.substr(0, 2);//车牌正确的前两个字符的变量;ch = imagename.substr(0, 2);//度量距离;diff = levenshtein_distance(imagename, platestr);//dif值;dif = diff - 4;//输出;cout << "差距:" <<dif << endl;//累计;sum += dif;//错误计数;if (ch != chpr) n++;//正确计数;if (diff == 0) correct++;//总数计数;j++;}//计算汉字识别准确率;float cha = 1 - float(n) / float(j);//输出;std::cout << "------------------------------------------------" << endl;//输出车牌总数;cout << "车牌总数:" << j << endl;//输出汉字识别准确率;cout << "汉字识别准确率:"<<cha << endl;//计算字符识别准确率;float chaccuracy = 1 - float(sum - n * 2) /float(j * 8);//输出;cout << "字符识别准确率:" << chaccuracy << endl;
}/*-----------测试函数:画框------------*/
void TEST_PIPELINE(){//声明PipelinePR实例;pr::PipelinePR prc("model/cascade.xml","model/HorizonalFinemapping.prototxt","model/HorizonalFinemapping.caffemodel","model/Segmentation.prototxt","model/Segmentation.caffemodel","model/CharacterRecognization.prototxt","model/CharacterRecognization.caffemodel","model/SegmentationFree.prototxt","model/SegmentationFree.caffemodel");//读取一张图片;cv::Mat image = cv::imread("/Users/yujinke/ClionProjects/cpp_ocr_demo/test.png");//申明一个存储该图片车牌信息检测结果的列表,读取结果;std::vector<pr::PlateInfo> res = prc.RunPiplineAsImage(image,pr::SEGMENTATION_FREE_METHOD);//遍历结果;for(auto st:res) {//选择置信度大于0.75的结果;if(st.confidence>0.75) {//输出结果;std::cout << st.getPlateName() << " " << st.confidence << std::endl;//矩形框位置;cv::Rect region = st.getPlateRect();//绘制框;cv::rectangle(image,cv::Point(region.x,region.y),cv::Point(region.x+region.width,region.y+region.height),cv::Scalar(255,255,0),2);}}//显示结果;cv::imshow("image",image);//等待;cv::waitKey(0);
}/*-----------测试函数:视频流------------*/
void TEST_CAM()
{//获取视频;cv::VideoCapture capture("test1.mp4");//申明帧变量;cv::Mat frame;//声明PipelinePR实例;pr::PipelinePR prc("model/cascade.xml","model/HorizonalFinemapping.prototxt","model/HorizonalFinemapping.caffemodel","model/Segmentation.prototxt","model/Segmentation.caffemodel","model/CharacterRecognization.prototxt","model/CharacterRecognization.caffemodel","model/SegmentationFree.prototxt","model/SegmentationFree.caffemodel");//循环读取帧;while(1) {//读取下一帧//异常处理;if (!capture.read(frame)) {std::cout << "读取视频失败" << std::endl;exit(1);}//图像旋转;//cv::transpose(frame,frame);//图像翻转;//cv::flip(frame,frame,2);//大小调整;//cv::resize(frame,frame,cv::Size(frame.cols/2,frame.rows/2));//识别结果;std::vector<pr::PlateInfo> res = prc.RunPiplineAsImage(frame,pr::SEGMENTATION_FREE_METHOD);//遍历识别结果for(auto st:res) {if(st.confidence>0.75) {//输出结果;std::cout << st.getPlateName() << " " << st.confidence << std::endl;//矩形框位置;cv::Rect region = st.getPlateRect();//绘制框;cv::rectangle(image,cv::Point(region.x,region.y),cv::Point(region.x+region.width,region.y+region.height),cv::Scalar(255,255,0),2);}}//显示;cv::imshow("image",frame);//等待;cv::waitKey(1);}
}/*-----------主函数:运行------------*/
int main()
{//准确率测试;TEST_ACC();//视频画框测试;//TEST_CAM();//图片画框测试;//TEST_PIPELINE();return 0 ;
}

【深度学习模型】智云视图中文车牌识别源码解析(二)相关推荐

  1. 【深度学习实战03】——YOLO tensorflow运行及源码解析

    本文章是深度学习实战系列第三讲文章,以运行代码+源码分析 为主: 转载请注明引用自:https://blog.csdn.net/c20081052/article/details/80260726 首 ...

  2. 西安交大团队开发了一种混合深度学习模型,用于在基因组中识别启动子

    来源:ScienceAI 编辑:萝卜皮 人类的大部分细胞中,每时每刻都在进行着各种复杂的转录过程:这一过程与后续的蛋白质合成息息相关,从而会影响人体中各类酶.抗体.激素.免疫因子等生物分子的产生,最终 ...

  3. 【深度学习】谷歌云GPU服务器创建与使用指南(二)

    接上一篇:[深度学习]谷歌云GPU服务器创建与使用指南(一) 这篇介绍ssh连接及一款客户端xshell 本篇将分为以下几点讲述: 1.ssh客户端 2.ssh公钥配置 3.使用xshell连接ssh ...

  4. 一文看尽深度学习中的20种卷积(附源码整理和论文解读)

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 引言 卷积,是卷积神经网络中最重要的组件之一.不同的卷积结构有着不一样的功能,但本质上都是用于提取特征 ...

  5. 基于python+pyqt+深度学习实现图像转素描【附部分源码】

    文章目录 前言 视频演示 一.ui配置 1.left_button.py源码 2.switch_btn.py源码 3.主页面重要代码 二.界面功能 1.初始化模型 2.初始化模型 3.相机采图 4.获 ...

  6. 碉堡了!程序员用深度学习写了个老板探测器(附源码)

    如果上班的时候想放松一下,或者直说想偷偷懒,看点和工作无关的网页,这时候万一老板突然出现在背后,会不会感到很难堪呢? 有的浏览器设置了boss按键,手快的人还可以切换屏幕,不过总会显得不自然,而且经常 ...

  7. Kubernetes学习笔记之Calico CNI Plugin源码解析(二)

    女主宣言 今天小编继续为大家分享Kubernetes Calico CNI Plugin学习笔记,希望能对大家有所帮助. PS:丰富的一线技术.多元化的表现形式,尽在"360云计算" ...

  8. 百度深度学习框架paddlepaddle实战三——自家车牌识别

    微信公众号:小白图像与视觉 关于技术.关注yysilence00.有问题或建议,请公众号留言. # 查看当前挂载的数据集目录, 该目录下的变更重启环境后会自动还原 # View dataset dir ...

  9. 2021-06-26一文看尽深度学习中的20种卷积(附源码整理和论文解读)

    卷积,是卷积神经网络中最重要的组件之一.不同的卷积结构有着不一样的功能,但本质上都是用于提取特征.比如,在传统图像处理中,人们通过设定不同的算子来提取诸如边缘.水平.垂直等固定的特征.而在卷积神经网络 ...

最新文章

  1. npm如何删除node_modules文件夹
  2. vba excel 开发游戏_为什么要学习VBA?
  3. linux系统支持u盘格式,linux下U盘格式化
  4. 本地 服务器 文件传输,本地服务器文件传输
  5. 高并发秒杀系统架构解密,不是所有的秒杀都是秒杀!
  6. 千年新论:马谡的错误在于盲目创新,正确做法是死板教条
  7. 惠普136nw打印机清零_惠普136nw打印机清零_HP惠普打印机清零大全
  8. python集合排序_集合排序python
  9. Burpsuite的CA证书安装
  10. 去水印程序源码大全源码
  11. 关于RIGOL可编程电源连接说明(网口连接)
  12. UnExpected Error, Quitting
  13. 阿里云 CDN+Oss 解决方案
  14. Java 中各种DTO,POJO 等的概念
  15. linux服务器修改字体,Linux  字体修改
  16. liunx系统的根结构认识及命令学习
  17. MySQL数据库与登录注册
  18. 正向代理和反向代理区别
  19. golang data race 竞态条件
  20. 认识“Silverlight”

热门文章

  1. JTable使用Enter键代替Tab键移动单元格焦点
  2. mysql按某列计数_Mysql按条件计数的几种方法
  3. 香港贸发局香港玩具展即将于2019新年揭幕
  4. 课体回顾,杂质半导体
  5. python使用xmindparser解析xmind文件并统计测试案例个数
  6. 儿童节搞笑祝福语短信
  7. 未来十年,最赚钱的16大行业
  8. 案例03 补充:金字塔等图形边框的绘制
  9. Word基础(三十七)自动插入题注
  10. 稳态血浆药物浓度css名词解释,药理名词解释-20210629151609.docx-原创力文档