基于OpenCV的车牌识别系统之三 ——字符分割与识别(川字分割)

       先前的博客之中提到要解决车牌字符识别的问题,由于博主在这俩月没有对车牌识别系统进行进一步的研究。也由于自身的C++语言能力不足。但经过两个月的语言能力提升,现在返过来解决这个问题。不多少说题外话了。

       先提思路,首先字符识别,第一步分为垂直投影和水平投影如图一所示。水平投影作用是将铆钉和边框的噪声去掉。同时也是限制其车牌字符的位置(这里没有用到垂直投影)。然后使用FindContours寻找外围轮廓,再采用凸包将其包围,然后在使用minAreaRect返回最小外接矩形,同时保存在RotatedRect类Vector数组中。Rotated详细见——非箴勿语的博客:http://blog.csdn.net/a553654745/article/details/45743063。但最小外接矩形的四个顶点并未排序。

       川字是车牌之中最容易出现分割错误的,同时也很容易将其川字分割成多块的。首先将每个RotatedRect类的返回的四个顶点值存储在Point2f的二维数组中。同时将每个RotatedRect类的Center属性成员存储在一维数组中,然后根据每个外接矩形的中心点对其排序,再将根据相邻的每一个外接矩形中心点位置的距离判断是否为一个整体。同时也要将每个RotatedRect类的四个顶点进行排序。如图所示,只需要得到四个顶点的Xmin、Xmax、Ymin、Ymax并将按照如图二所示排序,则图像必定会在框定的矩形内。然后根据每个RotatedRect的中心点(center)距离设定一个阈值,根据这个阈值判断相邻的两个或者三个RotatedRect类是否为一个整体。(本程序是阈值设置为8个像素值)。如果是一个整体则将按照下图图三红笔所示进行处理,然后将两个矩形或者多个矩形并在一起成为一个整体。

    

图一  水平投影和垂直投影



其效果图如下图四所示,已经能较好的解决这个川字分割的问题。


其程序如下图所示:

        char_sort(char_rects,char_number); //对字符排序  ********************************************原始程序从这里开始修改

vector < float > x_distance;  //用来储存各个最小外界矩形的中心点
for (int i = 0; i < char_number;i++)
{
x_distance.push_back(char_rects[i].center.x);
}
   

/*
vector <Mat> char_mat;


for (int i = 0; i<char_rects.size() ;i++ )
{
//char_mat.push_back(Mat(inputImg,char_rects[i].boundingRect())) ;
char_mat.push_back(Mat(img_threshold,char_rects[i].boundingRect())) ;
}
*/
//vector <Mat> char_mat;
vector <Point2f> rect_points; // 这个储存 最小矩形的 四个顶点。
for (int z = 0; z < char_rects.size(); z++)
{
Point2f vertex[4];
char_rects[z].points(vertex);
for (int i = 0; i < 4; i++)
{
rect_points.push_back(vertex[i]);
}
}


int rect_p_number = rect_points.size();


float x_min[20];
float x_max[20];
float y_min[20];
float y_max[20]; //用来存储坐标点的最大值和最小值;





for (int z = 0; z < char_rects.size();z++)
{
float min_x = rect_points[z * 4 ].x;
float min_y = rect_points[z * 4 ].y;
float max_x = 0;
float max_y = 0;


for (int w =0; w < 4;w++)
{

min_x = min_x < rect_points[z * 4 + w].x ? min_x : rect_points[z * 4 + w].x;


max_x = max_x > rect_points[z * 4 + w].x ? max_x : rect_points[z * 4 + w].x;


min_y = min_y < rect_points[z * 4 + w].y ? min_y : rect_points[z * 4 + w].y;

max_y = max_y > rect_points[z * 4 + w].y ? max_y : rect_points[z * 4 + w].y;
}
   x_min[z] = min_x;
   x_max[z] = max_x;
y_min[z] = min_y;
y_max[z] = max_y;
}// 得出 最大值和最小值    //这的最大最小值数组个数 必须是一个变量  





vector <Point2f> real_points; //对反馈四个顶点的值进行排序
for (int z = 0; z < char_rects.size(); z++)
    {

Point2f a, b, c, d;
a.x = x_min[z];
a.y = y_max[z];


b.x = x_min[z];
b.y = y_min[z];


c.x = x_max[z];
c.y = y_min[z];


d.x = x_max[z];
d.y = y_max[z];


real_points.push_back(a);
real_points.push_back(b);
real_points.push_back(c);
real_points.push_back(d);

  }








vector <Point2f> conbine;
int flag1 = 0; //这是合并的标志,每一次进行合并的时候,进行加1;
int center_number = 0;


for (int center_number = 0; center_number < 5; center_number++) //  这里为什么是要是char_rects.size()-1呢?是因为这里因为这个要第二个与第一个比较,所以最后一个不能再加上1与之比较;  //这里确定的一点是  我们只考虑前面三个轮廓
{
int distanst = x_distance[center_number + 1] - x_distance[center_number];
int distanst2 = x_distance[center_number + 2] - x_distance[center_number + 1];

if (distanst <= 8 && distanst2 >= 8 )
{
conbine.push_back(real_points[center_number * 4]);
conbine.push_back(real_points[center_number * 4 + 1]);
conbine.push_back(real_points[center_number * 4 + 6]);
conbine.push_back(real_points[center_number * 4 + 7]);
  center_number +=1;
  flag1 += 1;

}
if (distanst2 <= 8 && distanst2 <= 8)
{
conbine.push_back(real_points[center_number * 4]);
conbine.push_back(real_points[center_number * 4 + 1]);
conbine.push_back(real_points[center_number * 4 + 10]);
conbine.push_back(real_points[center_number * 4 + 11]);
center_number += 2;
flag1 += 2;
}


else
{
conbine.push_back(real_points[center_number * 4]);
conbine.push_back(real_points[center_number * 4 + 1]);
conbine.push_back(real_points[center_number * 4 + 2]);
conbine.push_back(real_points[center_number * 4 + 3]);


}
}

int s = (conbine.size())/4 +flag1 ;
int s1 = (real_points.size())/ 4;
for (; s < s1 ; s++)
{
conbine.push_back(real_points[s * 4]);
conbine.push_back(real_points[s * 4 + 1]);
conbine.push_back(real_points[s * 4 + 2]);
conbine.push_back(real_points[s * 4 + 3]);
}




/* int do_number = 0;
do 
{
int i = do_number;
int distanst;
if (i < char_rects.size()-1)
{
distanst = x_distance[i + 1] - x_distance[i];


if (x_distance[i+1])
{
conbine.push_back(real_points[i * 4]);
conbine.push_back(real_points[i * 4 + 1]);
conbine.push_back(real_points[i * 4 + 6]);
conbine.push_back(real_points[i * 4 + 7]);
flag1++;
}


else
{
conbine.push_back(real_points[i * 4]);
conbine.push_back(real_points[i * 4 + 1]);
conbine.push_back(real_points[i * 4 + 2]);
conbine.push_back(real_points[i * 4 + 3]);
}


}


else if (i >= char_rects.size()-1)
{
conbine.push_back(real_points[i * 4]);
conbine.push_back(real_points[i * 4 + 1]);
conbine.push_back(real_points[i * 4 + 2]);
conbine.push_back(real_points[i * 4 + 3]);
}

do_number++;
} while (do_number < char_rects.size());


*/


  Mat char_img;
vector <Mat> char_mat;
int char_rects_conbin_number = char_rects.size() - flag1;
for (int i = 0; i <char_rects_conbin_number; i++)
//for (int i = 0; i < 7; i++)
{

// char_img = inputImg(Range(conbine[i * 4+1].x, conbine[i * 4+2].x), Range(conbine[i *4+1].y, conbine[i * 4].y));
char_img = inputImg(Range(conbine[i * 4 + 1].y, conbine[i * 4].y), Range(conbine[i * 4 + 1].x, conbine[i * 4 + 2].x));//首先这个
char_mat.push_back(char_img);
}



  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值