终于答辩结束了,这个项目忘的也差不多了,今天正巧没事准备整理一下,本人菜鸡一枚,本科毕业设计题目是《基于OpenCV的车牌识别系统》,这个项目差不多研究了半个月才看懂,当时我给导师看这个项目的时候,导师直接说这些东西都是别人的,你什么都不做,这工作量有点少,怕我答辩时候过不了,之后就是让我加功能,(你这个可以检测绿牌吗?还有你这个识别算法,用的是什么,能不能用其他的,建议加个绿牌,并且做个其他识别算法和你这个对比一下,工作量看起来多一些),还是太懒了我只加了绿牌,之后又被导师数落了一顿。
        这个项目写的听清楚的,还有开发者文档参考,作者也把各个版本的配置方式贴出来了。我自己只是用MFC画了一个界面,里面就是调作者写好的函数,我自己加了绿牌,修改了部分代码。

1.添加绿色

在枚举颜色里面添加GREEN。在config.h文件中:

enum Color { BLUE, YELLOW, WHITE, GREEN,UNKNOWN };

2.添加绿色HSV

这里我设置的是35-80,在core_func.cpp文件中colorMatch函数中添加。修改后的代码如下:

Mat colorMatch(const Mat &src, Mat &match, const Color r,const bool adaptive_minsv) {// if use adaptive_minsv// min value of s and v is adaptive to hconst float max_sv = 255;const float minref_sv = 64;const float minabs_sv = 95; //95;// H range of blue const int min_blue = 100;  // 100const int max_blue = 140;  // 140// H range of yellowconst int min_yellow = 15;  // 15const int max_yellow = 40;  // 40// H range of whiteconst int min_white = 0;   // 15const int max_white = 30;  // 40//Louis add,green  // H range of greenconst int min_green = 35;   // 35const int max_green = 80;   // 80Mat src_hsv;// convert to HSV spacecvtColor(src, src_hsv, CV_BGR2HSV);std::vector<cv::Mat> hsvSplit;split(src_hsv, hsvSplit);equalizeHist(hsvSplit[2], hsvSplit[2]);merge(hsvSplit, src_hsv);// match to find the colorint min_h = 0;int max_h = 0;switch (r) {case BLUE:min_h = min_blue;max_h = max_blue;break;case YELLOW:min_h = min_yellow;max_h = max_yellow;break;case WHITE:min_h = min_white;max_h = max_white;break;//Louis add,green  case GREEN:min_h = min_green;max_h = max_green;break;default:// Color::UNKNOWNbreak;}float diff_h = float((max_h - min_h) / 2);float avg_h = min_h + diff_h;int channels = src_hsv.channels();int nRows = src_hsv.rows;// consider multi channel imageint nCols = src_hsv.cols * channels;if (src_hsv.isContinuous()) {nCols *= nRows;nRows = 1;}int i, j;uchar* p;float s_all = 0;float v_all = 0;float count = 0;for (i = 0; i < nRows; ++i) {p = src_hsv.ptr<uchar>(i);for (j = 0; j < nCols; j += 3) {int H = int(p[j]);      // 0-180int S = int(p[j + 1]);  // 0-255int V = int(p[j + 2]);  // 0-255s_all += S;v_all += V;count++;bool colorMatched = false;if (H > min_h && H < max_h) {float Hdiff = 0;if (H > avg_h)Hdiff = H - avg_h;elseHdiff = avg_h - H;float Hdiff_p = float(Hdiff) / diff_h;float min_sv = 0;if (true == adaptive_minsv)min_sv =minref_sv -minref_sv / 2 *(1- Hdiff_p);  // inref_sv - minref_sv / 2 * (1 - Hdiff_p)elsemin_sv = minabs_sv;  // addif ((S > min_sv && S < max_sv) && (V > min_sv && V < max_sv))colorMatched = true;}if (colorMatched == true) {p[j] = 0;p[j + 1] = 0;p[j + 2] = 255;}else {p[j] = 0;p[j + 1] = 0;p[j + 2] = 0;}}}// cout << "avg_s:" << s_all / count << endl;// cout << "avg_v:" << v_all / count << endl;// get the final binaryMat src_grey;std::vector<cv::Mat> hsvSplit_done;split(src_hsv, hsvSplit_done);src_grey = hsvSplit_done[2];match = src_grey;return src_grey;}

3.getPlateType中添加绿色

这部分也在core_func.cpp文件中。

Color getPlateType(const Mat &src, const bool adaptive_minsv) {float max_percent = 0;Color max_color = UNKNOWN;float blue_percent = 0;float yellow_percent = 0;float white_percent = 0;float green_percent = 0;if (plateColorJudge(src, BLUE, adaptive_minsv, blue_percent) == true) {// cout << "BLUE" << endl;return BLUE;} else if (plateColorJudge(src, YELLOW, adaptive_minsv, yellow_percent) ==true) {// cout << "YELLOW" << endl;return YELLOW;} else if (plateColorJudge(src, WHITE, adaptive_minsv, white_percent) ==true) {// cout << "WHITE" << endl;return WHITE;}else if (plateColorJudge(src, GREEN, adaptive_minsv, green_percent) ==true) {// cout << "GREEN" << endl;return GREEN;}else {//std::cout << "OTHER" << std::endl;/*max_percent = blue_percent > yellow_percent ? blue_percent : yellow_percent;max_color = blue_percent > yellow_percent ? BLUE : YELLOW;max_color = max_percent > white_percent ? max_color : WHITE;*/// always return greenreturn GREEN;}}

4.颜色定位中添加绿色

plate_locate.cpp中plateColorLocate函数,修改后如下:

int CPlateLocate::plateColorLocate(Mat src, vector<CPlate> &candPlates,int index) {vector<RotatedRect> rects_color_blue;rects_color_blue.reserve(64);vector<RotatedRect> rects_color_yellow;rects_color_yellow.reserve(64);vector<RotatedRect> rects_color_green;rects_color_green.reserve(64);vector<CPlate> plates_blue;plates_blue.reserve(64);vector<CPlate> plates_yellow;plates_yellow.reserve(64);vector<CPlate> plates_green;plates_green.reserve(64);Mat src_clone = src.clone();Mat src_b_blue;Mat src_b_yellow;Mat src_b_green;
#pragma omp parallel sections{#pragma omp section{colorSearch(src, BLUE, src_b_blue, rects_color_blue);deskew(src, src_b_blue, rects_color_blue, plates_blue, true, BLUE);//imshow("blue", src_b_blue);}
#pragma omp section{colorSearch(src_clone, YELLOW, src_b_yellow, rects_color_yellow);deskew(src_clone, src_b_yellow, rects_color_yellow, plates_yellow, true, YELLOW);}
#pragma omp section{colorSearch(src_clone, GREEN, src_b_green, rects_color_green);deskew(src_clone, src_b_green, rects_color_green, plates_green, true, GREEN);//imshow("green", src_b_green);}}candPlates.insert(candPlates.end(), plates_blue.begin(), plates_blue.end());candPlates.insert(candPlates.end(), plates_yellow.begin(), plates_yellow.end());candPlates.insert(candPlates.end(), plates_green.begin(), plates_green.end());return 0;
}

以上处理完基本可以实现对绿牌的定位,如果需要更高的准确率,可以自己重新训练一下,加上绿牌,因为绿牌的大小,颜色特征等都和蓝牌差距太大。

5.字符分割部分

这部分主要更改个分割字符数量和二值化参数,因为绿牌是8个字符,蓝牌7个字符,并且绿牌是背景颜色浅,车牌号颜色深,蓝牌是背景颜色深,车牌号颜色浅,所以蓝牌进行反二值化,绿牌则是正二值化。如下是core.func.cpp文件中。

void spatial_ostu(InputArray _src, int grid_x, int grid_y, Color type) {Mat src = _src.getMat();int width = src.cols / grid_x;int height = src.rows / grid_y;// iterate through gridfor (int i = 0; i < grid_y; i++) {for (int j = 0; j < grid_x; j++) {Mat src_cell = Mat(src, Range(i * height, (i + 1) * height), Range(j * width, (j + 1) * width));if (type == BLUE) {cv::threshold(src_cell, src_cell, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);} else if (type == YELLOW) {cv::threshold(src_cell, src_cell, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY_INV);} else if (type == WHITE) {cv::threshold(src_cell, src_cell, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY_INV);}else if (type == GREEN) {cv::threshold(src_cell, src_cell, 0, 255, THRESH_OTSU + CV_THRESH_BINARY_INV);}else {cv::threshold(src_cell, src_cell, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);}}}}

如下是字符分割函数修改后,在chars_segment.cpp中:

int CCharsSegment::charsSegment(Mat input, vector<Mat>& resultVec, Color color) {if (!input.data) return 0x01;Color plateType = color;Mat input_grey;cvtColor(input, input_grey, CV_BGR2GRAY);//imshow("cvt", input_grey);if (0) {imshow("plate", input_grey);waitKey(0);destroyWindow("plate");}Mat img_threshold;img_threshold = input_grey.clone();spatial_ostu(img_threshold, 8, 2, plateType);//imshow("ostu", img_threshold);if (0) {imshow("plate", img_threshold);waitKey(0);destroyWindow("plate");}// remove liuding and hor lines
// also judge weather is plate use jump countif (!clearLiuDing(img_threshold)) return 0x02;Mat img_contours;img_threshold.copyTo(img_contours);vector<vector<Point> > contours;findContours(img_contours,contours,               // a vector of contoursCV_RETR_EXTERNAL,       // retrieve the external contoursCV_CHAIN_APPROX_NONE);  // all pixels of each contours//  Mat dst = input;//for (vector<Point> point : contours) {//    RotatedRect rotatedRect = minAreaRect(point);//    rectangle(dst, rotatedRect.boundingRect(), Scalar(255,0,255));//}//imshow("dst", dst);vector<vector<Point> >::iterator itc = contours.begin();vector<Rect> vecRect;while (itc != contours.end()) {Rect mr = boundingRect(Mat(*itc));Mat auxRoi(img_threshold, mr);if (verifyCharSizes(auxRoi)) vecRect.push_back(mr);++itc;}if (vecRect.size() == 0) return 0x03;vector<Rect> sortedRect(vecRect);std::sort(sortedRect.begin(), sortedRect.end(),[](const Rect& r1, const Rect& r2) { return r1.x < r2.x; });size_t specIndex = 0;if(color == GREEN)specIndex = GetSpecificRectNew(sortedRect);//new carelsespecIndex = GetSpecificRect(sortedRect);//old carRect chineseRect;if (specIndex < sortedRect.size())chineseRect = GetChineseRect(sortedRect[specIndex]);elsereturn 0x04;if (0) {rectangle(img_threshold, chineseRect, Scalar(255));imshow("plate", img_threshold);waitKey(0);destroyWindow("plate");}vector<Rect> newSortedRect;newSortedRect.push_back(chineseRect);if (color == GREEN)RebuildRectNew(sortedRect, newSortedRect, specIndex);elseRebuildRect(sortedRect, newSortedRect, specIndex);if (newSortedRect.size() == 0) return 0x05;Mat dst = input;bool useSlideWindow = true;bool useAdapThreshold = true;//bool useAdapThreshold = CParams::instance()->getParam1b();for (size_t i = 0; i < newSortedRect.size(); i++) {Rect mr = newSortedRect[i];//rectangle(dst, mr, Scalar(255, 0, 255));// Mat auxRoi(img_threshold, mr);Mat auxRoi(input_grey, mr);Mat newRoi;if (i == 0) {if (useSlideWindow) {float slideLengthRatio = 0.1f;//float slideLengthRatio = CParams::instance()->getParam1f();if (!slideChineseWindow(input_grey, mr, newRoi, plateType, slideLengthRatio, useAdapThreshold))judgeChinese(auxRoi, newRoi, plateType);}elsejudgeChinese(auxRoi, newRoi, plateType);}else {if (BLUE == plateType) {threshold(auxRoi, newRoi, 0, 255, CV_THRESH_BINARY + CV_THRESH_OTSU);}else if (YELLOW == plateType) {threshold(auxRoi, newRoi, 0, 255, CV_THRESH_BINARY_INV + CV_THRESH_OTSU);}else if (WHITE == plateType) {threshold(auxRoi, newRoi, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY_INV);}else if (GREEN == plateType) {threshold(auxRoi, newRoi, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY_INV);}else {threshold(auxRoi, newRoi, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);}newRoi = preprocessChar(newRoi);}if (0) {if (i == 0) {imshow("input_grey", input_grey);waitKey(0);destroyWindow("input_grey");}if (i == 0) {imshow("newRoi", newRoi);waitKey(0);destroyWindow("newRoi");}}resultVec.push_back(newRoi);}//imshow("dst", dst);return 0;
}

添加如下两个函数,因为字符数不同,切割函数也不相同。

int CCharsSegment::GetSpecificRectNew(const vector<Rect>& vecRect) {vector<int> xpositions;int maxHeight = 0;int maxWidth = 0;for (size_t i = 0; i < vecRect.size(); i++) {xpositions.push_back(vecRect[i].x);if (vecRect[i].height > maxHeight) {maxHeight = vecRect[i].height;}if (vecRect[i].width > maxWidth) {maxWidth = vecRect[i].width;}}int specIndex = 0;for (size_t i = 0; i < vecRect.size(); i++) {Rect mr = vecRect[i];int midx = mr.x + mr.width / 2;// use prior knowledage to find the specific character// position in 1/8 and 2/8if ((mr.width > maxWidth * 0.6 || mr.height > maxHeight * 0.6) &&(midx < int(m_theMatWidth / 8.15f) * kSymbolIndex &&midx > int(m_theMatWidth / 8.15f) * (kSymbolIndex - 1))) {specIndex = i;}}return specIndex;
}int CCharsSegment::RebuildRectNew(const vector<Rect>& vecRect,vector<Rect>& outRect, int specIndex) {int count = 7;//Louis changed 6->7, for green plate carfor (size_t i = specIndex; i < vecRect.size() && count; ++i, --count) {outRect.push_back(vecRect[i]);}return 0;
}
}

以上改完基本可以实现对绿牌的识别,我只改了我用到的部分函数,其他未修改的同理。好久没看这个项目了,应该改的就这么多了,还有就是我训练的时候只用了10几张绿牌,关键是没数据集。。。

EasyPR如何添加绿牌C++版相关推荐

  1. JDK1.7绿色解压版64位

    1.7的版本来啦,下面是version的信息了 java version "1.7.0_80" Java(TM) SE Runtime Environment (build 1.7 ...

  2. township android,township无限绿钞最新版-township无限绿钞安卓版下载-西西安卓游戏...

    township无限绿钞安卓版是一款非常火爆的手机模拟经营类游戏,游戏的画面设计的十分精致,而玩家将要扮演一座小镇的镇长,玩家可以自由设计自己的小镇,将它变得更加繁华,吸引贸易,对于有设计控的朋友来 ...

  3. 车牌识别数据集(蓝牌、黄牌、绿牌)及相关转换代码

    自己整理了一些用在车牌识别的数据集,已经人工一张一张的筛选过了,过滤掉模糊的图片.处理有歧义的区域,可以直接采用. label为labelme的json格式,目标框是polygon多边形,好处是不同角 ...

  4. Python3.6+OpenCV3中国车牌识别( 蓝牌、绿牌、黄牌)

    点击下载:Python3.6+OpenCV3中国车牌识别( 蓝牌.绿牌.黄牌) 文件大小:81M 源码说明:带中文注释 文档说明:WORD格式 PDF说明提取码:61ic 操作视频:MP4格式 视频演 ...

  5. 阴阳师电脑版一直连接不上服务器,阴阳师百闻牌电脑版 电脑版连不上怎么办...

    阴阳师百闻牌游戏时玩家们可能会遇到连接不上问题,让大家无法继续开心游戏了喔,那么阴阳师百闻牌桌面版连接不上怎么办.百闻牌pc电脑版无法连接服务器怎么办呢,18183小编为大家介绍. 阴阳师百闻牌桌面版 ...

  6. 计算机科学与技术是绿牌吗,武汉工程大学什么专业好?绿牌专业是王道!

    原标题:武汉工程大学什么专业好?绿牌专业是王道! 要说现在什么是最火的专业,相信计算机科学与技术绝对是榜上有名. 在去年的中国大学生就业报告之中,绿牌专业共七个,计算机科学与技术便位列其中.何谓绿牌专 ...

  7. windows系统给文件夹添加备注(详细版)

    windows系统给文件夹添加备注(详细版) 关于我 愤青持续码字中,每周三准时更新 每篇文章博主都会仔细来回阅读,语文不好,发现有语法错误,麻烦评论留言,一定改. 著作权归作者所有.商业转载请联系作 ...

  8. 饥荒服务器不显示管理员,饥荒联机版管理员怎么添加_饥荒联机版管理员介绍与添加方法详解_玩游戏网...

    <饥荒>联机版里面的管理员这个概念大家了解吗?我之前也不清楚管理员相关内容,下面笔者就为大家带来了饥荒联机版管理员介绍与添加方法详解,小伙伴们还不了解联机版管理员的下面跟我一起来看看吧. ...

  9. Python根据字幕文件自动给视频添加字幕(通用版)

    功能描述: 根据给定的字幕文件中的字幕信息,自动给视频添加字幕,运行程序后输入要添加字幕的视频文件和对应的字幕文件路径即可.实际使用时不需要对程序做任何修改,只需要根据实际的视频内容来修改字幕文件就可 ...

  10. uno牌的玩法图解_UNO牌标准版简介及规则说明

    UNO扑克是一种起源于欧洲流行于全世界的牌类游戏.简单易学,不用动什么脑筋,适合各年龄层人士玩."UNO"扑克是世界上最大的玩具公司美国美泰玩具公司的代表作,在全球的销售量已超过十 ...

最新文章

  1. UVa10382 - Watering Grass(贪心算法)
  2. JavaScript面向对象中的严格模式
  3. 使用四种框架分别实现百万websocket常连接的服务器--转
  4. 4G室内直放站_室内信号不太好,安装一个手机信号放大器,有效果吗?
  5. object取值_如何重写object虚方法
  6. oracle shell 登录,linux 本地账号密码无法登陆(shell可以登录),一直返回 登陆的login界面...
  7. O(n)算法得到数组中第k大的数字
  8. C#中 out、ref、params 修饰符使用方法
  9. vue获取table一列数据_vue中比较重要的小知识点
  10. libuv:多平台支持库-异步I / O
  11. bash中的算术运算
  12. 因为孤浪的关于爱情...关于婚姻...关于生活... 走进的CTO的第一天
  13. 如何用相机拍出天空漂亮的云朵
  14. 树莓派安装DLNA实现流媒体服务器
  15. hdoj1176:免费馅饼(dp基础题-数塔思想)
  16. php跨域请求post请求失败,nginx + php 跨域问题,GET可以跨域成功,POST失败
  17. 未越狱苹果设备抓包方法
  18. getMonthsetMonth方法
  19. pid的matlab仿真,MATLAB Pid仿真实验
  20. JAVA算法:解救小哈(JAVA版)

热门文章

  1. 校园热水供应系统设计思路
  2. 51单片机-PASCAL语言开发环境搭建
  3. 几种有趣的Magic Matrix
  4. w ndows 那个比较好用,DOS工具箱哪个好用?DOS工具箱盘点
  5. Moodle插件开发基础
  6. windows桌面动态主题_如何在Windows 10上安装桌面主题
  7. android 开源fc模拟器_用 Go 撸了一个 NES/FC/红白机模拟器——GoNES
  8. 单场淘汰制场次计算方法_单循环淘汰赛什么意思?
  9. Kubernetes 系统强化 Pod安全策略 PSP
  10. DisplayTag使用指南(二) DisplayTag标签库详解