|
|
|
|
@ -1,6 +1,6 @@
|
|
|
|
|
// 这个文件定义了EasyPR里所有plate判断的通用函数
|
|
|
|
|
// 所属命名空间为easypr
|
|
|
|
|
// 这个部分中的函数轻易不要改动
|
|
|
|
|
// 这个文件定义了EasyPR里所有plate判断的通用函数
|
|
|
|
|
// 所属命名空间为easypr
|
|
|
|
|
// 这个部分中的函数轻易不要改动
|
|
|
|
|
|
|
|
|
|
#include "../include/prep.h"
|
|
|
|
|
#include "../include/core_func.h"
|
|
|
|
|
@ -10,30 +10,30 @@ Namespace where all the C++ EasyPR functionality resides
|
|
|
|
|
*/
|
|
|
|
|
namespace easypr {
|
|
|
|
|
|
|
|
|
|
//! 根据一幅图像与颜色模板获取对应的二值图
|
|
|
|
|
//! 输入RGB图像, 颜色模板(蓝色、黄色)
|
|
|
|
|
//! 输出灰度图(只有0和255两个值,255代表匹配,0代表不匹配)
|
|
|
|
|
//! 根据一幅图像与颜色模板获取对应的二值图
|
|
|
|
|
//! 输入RGB图像, 颜色模板(蓝色、黄色)
|
|
|
|
|
//! 输出灰度图(只有0和255两个值,255代表匹配,0代表不匹配)
|
|
|
|
|
Mat colorMatch(const Mat& src, Mat& match, const Color r, const bool adaptive_minsv)
|
|
|
|
|
{
|
|
|
|
|
// S和V的最小值由adaptive_minsv这个bool值判断
|
|
|
|
|
// 如果为true,则最小值取决于H值,按比例衰减
|
|
|
|
|
// 如果为false,则不再自适应,使用固定的最小值minabs_sv
|
|
|
|
|
// 默认为false
|
|
|
|
|
// S和V的最小值由adaptive_minsv这个bool值判断
|
|
|
|
|
// 如果为true,则最小值取决于H值,按比例衰减
|
|
|
|
|
// 如果为false,则不再自适应,使用固定的最小值minabs_sv
|
|
|
|
|
// 默认为false
|
|
|
|
|
const float max_sv = 255;
|
|
|
|
|
const float minref_sv = 64;
|
|
|
|
|
|
|
|
|
|
const float minabs_sv = 95;
|
|
|
|
|
|
|
|
|
|
//blue的H范围
|
|
|
|
|
//blue的H范围
|
|
|
|
|
const int min_blue = 100; //100
|
|
|
|
|
const int max_blue = 140; //140
|
|
|
|
|
|
|
|
|
|
//yellow的H范围
|
|
|
|
|
//yellow的H范围
|
|
|
|
|
const int min_yellow = 15; //15
|
|
|
|
|
const int max_yellow = 40; //40
|
|
|
|
|
|
|
|
|
|
Mat src_hsv;
|
|
|
|
|
// 转到HSV空间进行处理,颜色搜索主要使用的是H分量进行蓝色与黄色的匹配工作
|
|
|
|
|
// 转到HSV空间进行处理,颜色搜索主要使用的是H分量进行蓝色与黄色的匹配工作
|
|
|
|
|
cvtColor(src, src_hsv, CV_BGR2HSV);
|
|
|
|
|
|
|
|
|
|
vector<Mat> hsvSplit;
|
|
|
|
|
@ -41,7 +41,7 @@ namespace easypr {
|
|
|
|
|
equalizeHist(hsvSplit[2], hsvSplit[2]);
|
|
|
|
|
merge(hsvSplit, src_hsv);
|
|
|
|
|
|
|
|
|
|
//匹配模板基色,切换以查找想要的基色
|
|
|
|
|
//匹配模板基色,切换以查找想要的基色
|
|
|
|
|
int min_h = 0;
|
|
|
|
|
int max_h = 0;
|
|
|
|
|
switch (r) {
|
|
|
|
|
@ -60,10 +60,10 @@ namespace easypr {
|
|
|
|
|
|
|
|
|
|
int channels = src_hsv.channels();
|
|
|
|
|
int nRows = src_hsv.rows;
|
|
|
|
|
//图像数据列需要考虑通道数的影响;
|
|
|
|
|
//图像数据列需要考虑通道数的影响;
|
|
|
|
|
int nCols = src_hsv.cols * channels;
|
|
|
|
|
|
|
|
|
|
if (src_hsv.isContinuous())//连续存储的数据,按一行处理
|
|
|
|
|
if (src_hsv.isContinuous())//连续存储的数据,按一行处理
|
|
|
|
|
{
|
|
|
|
|
nCols *= nRows;
|
|
|
|
|
nRows = 1;
|
|
|
|
|
@ -99,9 +99,9 @@ namespace easypr {
|
|
|
|
|
|
|
|
|
|
float Hdiff_p = float(Hdiff) / diff_h;
|
|
|
|
|
|
|
|
|
|
// S和V的最小值由adaptive_minsv这个bool值判断
|
|
|
|
|
// 如果为true,则最小值取决于H值,按比例衰减
|
|
|
|
|
// 如果为false,则不再自适应,使用固定的最小值minabs_sv
|
|
|
|
|
// S和V的最小值由adaptive_minsv这个bool值判断
|
|
|
|
|
// 如果为true,则最小值取决于H值,按比例衰减
|
|
|
|
|
// 如果为false,则不再自适应,使用固定的最小值minabs_sv
|
|
|
|
|
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)
|
|
|
|
|
@ -124,7 +124,7 @@ namespace easypr {
|
|
|
|
|
//cout << "avg_s:" << s_all / count << endl;
|
|
|
|
|
//cout << "avg_v:" << v_all / count << endl;
|
|
|
|
|
|
|
|
|
|
// 获取颜色匹配后的二值灰度图
|
|
|
|
|
// 获取颜色匹配后的二值灰度图
|
|
|
|
|
Mat src_grey;
|
|
|
|
|
vector<Mat> hsvSplit_done;
|
|
|
|
|
split(src_hsv, hsvSplit_done);
|
|
|
|
|
@ -137,9 +137,9 @@ namespace easypr {
|
|
|
|
|
|
|
|
|
|
bool bFindLeftRightBound1(Mat& bound_threshold,int& posLeft,int& posRight)
|
|
|
|
|
{
|
|
|
|
|
//从两边寻找边界
|
|
|
|
|
//从两边寻找边界
|
|
|
|
|
int span = bound_threshold.rows*0.2;
|
|
|
|
|
//左边界检测
|
|
|
|
|
//左边界检测
|
|
|
|
|
for (int i=0; i < bound_threshold.cols-span-1;i+=3)
|
|
|
|
|
{
|
|
|
|
|
int whiteCount = 0;
|
|
|
|
|
@ -162,7 +162,7 @@ namespace easypr {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
span = bound_threshold.rows*0.2;
|
|
|
|
|
//右边界检测
|
|
|
|
|
//右边界检测
|
|
|
|
|
for (int i=bound_threshold.cols-1; i > span;i-=2)
|
|
|
|
|
{
|
|
|
|
|
int whiteCount = 0;
|
|
|
|
|
@ -204,9 +204,9 @@ namespace easypr {
|
|
|
|
|
|
|
|
|
|
bool bFindLeftRightBound(Mat& bound_threshold,int& posLeft,int& posRight)
|
|
|
|
|
{
|
|
|
|
|
//从两边寻找边界
|
|
|
|
|
//从两边寻找边界
|
|
|
|
|
int span = bound_threshold.rows*0.2;
|
|
|
|
|
//左边界检测
|
|
|
|
|
//左边界检测
|
|
|
|
|
for (int i=0; i < bound_threshold.cols-span-1;i+=2)
|
|
|
|
|
{
|
|
|
|
|
int whiteCount = 0;
|
|
|
|
|
@ -229,7 +229,7 @@ namespace easypr {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
span = bound_threshold.rows*0.2;
|
|
|
|
|
//右边界检测
|
|
|
|
|
//右边界检测
|
|
|
|
|
for (int i=bound_threshold.cols-1; i > span;i-=2)
|
|
|
|
|
{
|
|
|
|
|
int whiteCount = 0;
|
|
|
|
|
@ -262,9 +262,9 @@ namespace easypr {
|
|
|
|
|
|
|
|
|
|
bool bFindLeftRightBound2(Mat& bound_threshold,int& posLeft,int& posRight)
|
|
|
|
|
{
|
|
|
|
|
//从两边寻找边界
|
|
|
|
|
//从两边寻找边界
|
|
|
|
|
int span = bound_threshold.rows*0.2;
|
|
|
|
|
//左边界检测
|
|
|
|
|
//左边界检测
|
|
|
|
|
for (int i=0; i < bound_threshold.cols-span-1;i+=3)
|
|
|
|
|
{
|
|
|
|
|
int whiteCount = 0;
|
|
|
|
|
@ -287,7 +287,7 @@ namespace easypr {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
span = bound_threshold.rows*0.2;
|
|
|
|
|
//右边界检测
|
|
|
|
|
//右边界检测
|
|
|
|
|
for (int i=bound_threshold.cols-1; i > span;i-=3)
|
|
|
|
|
{
|
|
|
|
|
int whiteCount = 0;
|
|
|
|
|
@ -318,12 +318,12 @@ namespace easypr {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//! 判断一个车牌的颜色
|
|
|
|
|
//! 输入车牌mat与颜色模板
|
|
|
|
|
//! 返回true或fasle
|
|
|
|
|
//! 判断一个车牌的颜色
|
|
|
|
|
//! 输入车牌mat与颜色模板
|
|
|
|
|
//! 返回true或fasle
|
|
|
|
|
bool plateColorJudge(const Mat& src, const Color r, const bool adaptive_minsv)
|
|
|
|
|
{
|
|
|
|
|
// 判断阈值
|
|
|
|
|
// 判断阈值
|
|
|
|
|
const float thresh = 0.45;
|
|
|
|
|
|
|
|
|
|
Mat src_gray;
|
|
|
|
|
@ -339,7 +339,7 @@ namespace easypr {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//getPlateType
|
|
|
|
|
//判断车牌的类型
|
|
|
|
|
//判断车牌的类型
|
|
|
|
|
Color getPlateType(const Mat& src, const bool adaptive_minsv)
|
|
|
|
|
{
|
|
|
|
|
if (plateColorJudge(src, BLUE, adaptive_minsv) == true) {
|
|
|
|
|
@ -394,9 +394,9 @@ namespace easypr {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//去除车牌上方的钮钉
|
|
|
|
|
//计算每行元素的阶跃数,如果小于X认为是柳丁,将此行全部填0(涂黑)
|
|
|
|
|
//X的推荐值为,可根据实际调整
|
|
|
|
|
//去除车牌上方的钮钉
|
|
|
|
|
//计算每行元素的阶跃数,如果小于X认为是柳丁,将此行全部填0(涂黑)
|
|
|
|
|
//X的推荐值为,可根据实际调整
|
|
|
|
|
bool clearLiuDing(Mat& img)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
@ -431,7 +431,7 @@ namespace easypr {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////这样的不是车牌
|
|
|
|
|
////这样的不是车牌
|
|
|
|
|
if (iCount*1.0/img.rows < 0.5)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
@ -491,7 +491,7 @@ namespace easypr {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//ok,找到上下边界
|
|
|
|
|
//ok,找到上下边界
|
|
|
|
|
for (int i = mask.rows-1; i >= mask.rows/2; i--)
|
|
|
|
|
{
|
|
|
|
|
int jumpCount = 0;
|
|
|
|
|
@ -572,7 +572,7 @@ namespace easypr {
|
|
|
|
|
return thresholdV;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//! 直方图均衡
|
|
|
|
|
//! 直方图均衡
|
|
|
|
|
Mat histeq(Mat in)
|
|
|
|
|
{
|
|
|
|
|
Mat out(in.size(), in.type());
|
|
|
|
|
@ -609,7 +609,7 @@ namespace easypr {
|
|
|
|
|
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<vhist.cols; i++)
|
|
|
|
|
{
|
|
|
|
|
@ -675,7 +675,7 @@ namespace easypr {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
// !获取垂直和水平方向直方图
|
|
|
|
|
// !获取垂直和水平方向直方图
|
|
|
|
|
Mat ProjectedHistogram(Mat img, int t)
|
|
|
|
|
{
|
|
|
|
|
int sz = (t) ? img.rows : img.cols;
|
|
|
|
|
@ -684,7 +684,7 @@ namespace easypr {
|
|
|
|
|
for (int j = 0; j<sz; j++){
|
|
|
|
|
Mat data = (t) ? img.row(j) : img.col(j);
|
|
|
|
|
|
|
|
|
|
mhist.at<float>(j) =countNonZero(data); //统计这一行或一列中,非零元素的个数,并保存到mhist中
|
|
|
|
|
mhist.at<float>(j) =countNonZero(data); //统计这一行或一列中,非零元素的个数,并保存到mhist中
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Normalize histogram
|
|
|
|
|
@ -692,7 +692,7 @@ namespace easypr {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|