车牌定位--颜色分割

简介:

车牌定位是车牌识别中第一步,也是最重要的一步。

由于中国车牌种类多样,颜色不一, 再加上车牌经常有污损,以及车牌周围干扰因素太多,都成为了车牌定位的难点。

这里首先使用最简单算法来描述车牌定位,以及他的缺陷和改进。

一、投影法

1、车辆图像信息获取


2、HSV颜色转换

把RGB数据转换成HSV空间图像数据

hsvzation(image,hsv,width,height);


3、HSV颜色过滤

设置蓝色车牌底色阈值范围,进行颜色过滤

蓝色车牌

H值范围:190 ~ 245

S值范围: 0.35 ~ 1

V值范围: 0.3 ~ 1

过滤后图像如下:



4、噪声处理

过滤后,一般要进行去噪处理,这里早点不明显,如果车牌周围有蓝色物体,噪点就非常明显了

这里使用平均去噪,一些孤立白点将被去除,效果如下:



5、边缘检测

去噪后,进行边缘检测,边缘检测的目的就是为了突出车牌信息的突变,因为车牌背景和字体颜色区分开了;

这样做的目的也是为了防止周围有和车牌底色相同颜色的物体干扰,尤其是车辆颜色,因为经过边缘检测后车体颜色没有那么多跳变干扰或者与车牌跳变规律不一样,这样就可以滤去车体颜色,去除干扰



6、确定车牌位置

通过水平投影和垂直投影确定车牌位置。

这里投影方法有很大缺陷,在车牌周围除了车辆还有其他背景信息时尤为明显,这在下面的另一种方法中改善



7、截取车牌图像



二、投影法定位缺陷示例

1、读取复杂背景的车牌图像



2、HSV滤波

HSV过滤后可以看到明显的干扰信息,车辆后面的栏杆,和车辆同样的颜色



3、均值去噪

去噪后,虽然大部分噪点都去除了,但是栏杆依然清晰



4、边缘检测

边缘检测后的图像,车牌区域的形状特征,给我们解决投影缺陷的一些启示



5,、 投影后错误的定位



6、车牌提取错误

后半块车身,比例也不符合车牌特征



由此看见,在复杂背景的车牌识别中,全局投影就无法抑制干扰,在下面黄色车牌示例中就更加明显;

投影法简单,但只是在只有整体车辆信息,没有复杂背景信息的时候才可以使用。


三、基于候选区域判断方法

这个方法放弃了投影,直接遍历整个图像信息,检查每个联通域的长度和宽度,当符合车牌的宽高比时,才选定为候选区域,由后面处理流程进行处理,来判断是否能够提取正常的字符。


前两个步骤还是同上面一样的。

1、HSV空间转换


2、均值去噪



3、水平膨胀

目的:尽可能的形成连通域



4、边缘检测

也可以不用边缘检测,这里主要考虑到 尽量减少 图像白点 遍历中的运算



5、候选区域筛选

候选区域筛选, 这是区别投影方法的主要部分,

从上图可以看出有几个候选区域,大概有4块, 而中间的车牌有明显矩形特征,符合一定的长宽比例, 其他三块区域不具备这样的特征,在筛选的过程中予以舍弃。

筛选的方法采用 深度优先遍历, 当遇到连通域时,记录他的长度和高度,并设定阈值,当符合长宽比时,才会选中为候选区域,否则予以舍弃,当然还可以添加别的算法,比如检测跳变,毕竟符合这一比率的不一定就是车牌区域。

下图中黄框就是筛选后的区域:



连通域筛选函数如下:

[cpp]  view plain copy
  1. int find_connected_region_location(struct BMP_img *img, unsigned char *src, int xthreashold, int ythreashold, float rateLow, float rateHigh)  
  2. {  
  3.     int i,j;  
  4.     int x1, y1, x2, y2;  
  5.     int width;  
  6.     int height;  
  7.     unsigned char *temp;  
  8.     //int queue_count;  
  9.     int head, rear;  
  10.     struct XY_Queue *queue;  
  11.     static int direction[4][2]={{1, 0}, {-1, 0}, {0, 1}, {0, -1}};  
  12.   
  13.     width = img->width;  
  14.     height = img->height;  
  15.   
  16.     queue = (struct XY_Queue *)malloc(sizeof(struct XY_Queue) * width * height);  
  17.   
  18.     temp = (unsigned char *)malloc(width * height * sizeof(unsigned char));  
  19.   
  20.     if(temp == NULL)  
  21.     {  
  22.         printf("find_connected_region_location mem alloc fail\n");  
  23.         return -1;  
  24.     }  
  25.     memcpy(temp, src, width * height);  
  26.   
  27.     head = rear = 0;  
  28.     img->region_num = 0;  
  29.   
  30.     for(i = 0; i < height; i++)  
  31.         for(j = 0; j < width; j++)  
  32.     {  
  33.         if(temp[i * width + j] == 255)  
  34.         {  
  35.                       
  36.             queue[rear].x = j;  
  37.             queue[rear].y = i;  
  38.             rear ++;  
  39.             temp[i * width + j] = 0;  
  40.   
  41.             img->pre_region[img->region_num].x1 = j;  
  42.             img->pre_region[img->region_num].x2 = j;  
  43.             img->pre_region[img->region_num].y1 = i;  
  44.             img->pre_region[img->region_num].y2 = i;  
  45.   
  46.             if(img->region_num > CAN_REGION_NUM)  
  47.             {  
  48.                 printf("over the CAN_REGION_NUM\n");  
  49.                 return -1;  
  50.             }  
  51.   
  52.             while(head < rear)  
  53.             {  
  54.                 x1 = queue[head].x;  
  55.                 y1 = queue[head].y;  
  56.                 head ++;  
  57.   
  58.                 if(x1 < img->pre_region[img->region_num].x1)  
  59.                     img->pre_region[img->region_num].x1 = x1;  
  60.                 else if(x1 > img->pre_region[img->region_num].x2)  
  61.                     img->pre_region[img->region_num].x2 = x1;  
  62.                 if(y1 < img->pre_region[img->region_num].y1)  
  63.                     img->pre_region[img->region_num].y1 = y1;  
  64.                 else if(y1 > img->pre_region[img->region_num].y2)  
  65.                     img->pre_region[img->region_num].y2 = y1;  
  66.                   
  67.       
  68.                 for(i = 0; i < 4; i++)  
  69.                 {  
  70.                     x2 = x1 + direction[i][0];  
  71.                     y2 = y1 + direction[i][1];  
  72.   
  73.                     if(x2 > 0 && x2 < width && y2 > 0 && y2 < height && temp[y2 * width + x2])  
  74.                     {  
  75.                         temp[y2 * width + x2] = 0;  
  76.                         queue[rear].x = x2;  
  77.                         queue[rear].y = y2;  
  78.                         rear ++;  
  79.                     }  
  80.               
  81.                 }  
  82.             }  
  83.             if((img->pre_region[img->region_num].x2 - img->pre_region[img->region_num].x1 > xthreashold) && (img->pre_region[img->region_num].y2 - img->pre_region[img->region_num].y1 > ythreashold))  
  84.             {  
  85.   
  86.                 img->pre_region[img->region_num].width = img->pre_region[img->region_num].x2 - img->pre_region[img->region_num].x1 + 1;  
  87.                 img->pre_region[img->region_num].height = img->pre_region[img->region_num].y2 - img->pre_region[img->region_num].y1 + 1;  
  88.                 img->pre_region[img->region_num].rate = (float)img->pre_region[img->region_num].width/img->pre_region[img->region_num].height;  
  89.                 if((img->pre_region[img->region_num].width < img->width / 2) && (img->pre_region[img->region_num].height < img->height / 2))  
  90.                 if((img->pre_region[img->region_num].rate > rateLow) && (img->pre_region[img->region_num].rate < rateHigh))  
  91.                 {  
  92.                     if(img->pre_region[img->region_num].x2 + PRE_LOCATION_BIAS > img->width)  
  93.                             img->pre_region[img->region_num].x2 = img->width;  
  94.                     else  
  95.                             img->pre_region[img->region_num].x2 += PRE_LOCATION_BIAS;  
  96.                     if(img->pre_region[img->region_num].x1 - PRE_LOCATION_BIAS < 0)  
  97.                             img->pre_region[img->region_num].x1 = 0;  
  98.                     else  
  99.                             img->pre_region[img->region_num].x1 -= PRE_LOCATION_BIAS;  
  100.                     if(img->pre_region[img->region_num].y2 + PRE_LOCATION_BIAS > img->height)  
  101.                             img->pre_region[img->region_num].y2 = img->height;  
  102.                     else  
  103.                             img->pre_region[img->region_num].y2 += PRE_LOCATION_BIAS;  
  104.                     if(img->pre_region[img->region_num].y1 - PRE_LOCATION_BIAS < 0)  
  105.                             img->pre_region[img->region_num].y1 = 0;  
  106.                     else  
  107.                             img->pre_region[img->region_num].y1 -= PRE_LOCATION_BIAS;  
  108.   
  109.                     img->pre_region[img->region_num].width = img->pre_region[img->region_num].x2 - img->pre_region[img->region_num].x1 + 1;  
  110.                     img->pre_region[img->region_num].height = img->pre_region[img->region_num].y2 - img->pre_region[img->region_num].y1 + 1;  
  111.               
  112.                     img->region_num++;  
  113.                 }  
  114.             }  
  115.         }  
  116.           
  117.           
  118.     }  
  119.     free(temp);  
  120.     temp = NULL;  
  121.     return 0;  
  122. }  

6、截取车牌区域图像




四、黄色车牌检测

1、车辆图像信息



2、HSV过滤分割

由于车牌颜色 与 车辆颜色一直,出现大量噪声信息,全局投影已不可能分割出车牌信息了,

这里只是 利用候选区域长宽比来进行矩形分割,肯定会出现一些符合比例但是不是车牌的区域,必须在后面的处理中加以区分或者添加判断跳变规律的函数



3、去噪



4、 膨胀


6、边缘检测



7、候选区域 连通域筛选

从图中可以看到黄框 部分即是符合候选区域的地方



8、截取候选区域

此候选区域只是符合长宽比,需要另行处理 除去不是车牌的区域



五、小结

车牌定位比较复杂,但对于车牌识别来说,最为重要,我认为它是影响车牌识别最大因素。虽然复杂,但是方法多种多样。

这里仅此个人爱好和研究,希望各位朋友继续提出批评和建议,大家的鼓励给了我坚持下去的勇气。

相关文章
|
Linux
【PyAutoGUI操作指南】05 屏幕截图与图像定位:截图+定位单个目标+定位全部目标+灰度匹配+像素匹配+获取屏幕截图中像素的RGB颜色
【PyAutoGUI操作指南】05 屏幕截图与图像定位:截图+定位单个目标+定位全部目标+灰度匹配+像素匹配+获取屏幕截图中像素的RGB颜色
1027 0
|
3月前
|
算法 计算机视觉
基于轮廓提取的 图像填充法
这篇文章介绍了一种基于轮廓提取的图像填充法,使用CVPR2021开源的pidinet项目进行轮廓提取,再结合OpenCV的floodFill算法实现图像的动态填充和复原功能。
|
4月前
|
文字识别
文本,文字识别,PaddleOCR,如何删除,PaddleOCR详解,检测,方向分类器,识别,检测的意思是检查字符的位置,查像素坐标,方向分类器,能够实现180度的图像,字符识别是把识别字符
文本,文字识别,PaddleOCR,如何删除,PaddleOCR详解,检测,方向分类器,识别,检测的意思是检查字符的位置,查像素坐标,方向分类器,能够实现180度的图像,字符识别是把识别字符
|
5月前
|
存储 算法 Python
查找图像轮廓
【6月更文挑战第11天】查找图像轮廓。
54 3
|
6月前
|
监控 计算机视觉
指定的颜色范围过滤出特定颜色的区域
指定的颜色范围过滤出特定颜色的区域
52 5
|
存储
通过分析 L*a*b* 颜色空间来识别织物中的不同颜色
通过分析 L*a*b* 颜色空间来识别织物中的不同颜色
121 0
ENVI:影像的规则裁剪和不规则裁剪
ENVI:影像的规则裁剪和不规则裁剪
361 0
|
6月前
|
C++
[Halcon&定位] 解决Roi区域外的模板匹配成功
[Halcon&定位] 解决Roi区域外的模板匹配成功
191 0
|
6月前
|
算法
[Halcon&定位] 形状匹配和灰度匹配对比
[Halcon&定位] 形状匹配和灰度匹配对比
217 0
|
编解码
使用遮罩提取图像中感兴趣的区域
使用遮罩隔离感兴趣区域 (ROI) 来有效地处理被阻止的图像。 某些大图像源仅在图像的一小部分中具有有意义的数据。可以通过将处理限制为包含有意义数据的 ROI 来缩短总处理时间。使用掩码定义投资回报率。蒙版是一种逻辑图像,其中像素表示投资回报率。
124 1