• 正文
    • 1、前言
    • 2、步驟說(shuō)明
    • 3、區(qū)域識(shí)別
    • 4、字符分割
    • 5、字符識(shí)別
  • 相關(guān)推薦
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

基于STM32F4的車牌識(shí)別(1)——車牌區(qū)域識(shí)別和字符分割

04/01 11:15
617
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

1、前言

曾經(jīng)寫過(guò)一篇文章,介紹如何利用ESP32獲取車牌數(shù)據(jù)上傳至百度云平臺(tái)識(shí)別車牌。不過(guò)這種方式既需要無(wú)線傳輸,還需要額外對(duì)車牌識(shí)別進(jìn)行繳費(fèi)。

本期我們探索如何利用STM32進(jìn)行車牌識(shí)別的本地化部署。這里疊個(gè)甲,作者做這塊純屬好奇,不涉及真正的應(yīng)。

本期硬件采用STM32F4,TFTLCD以及OV2640顯示屏,本來(lái)是想用H7的,但是由于不可抗力因素?fù)Q為使用F4,攝像頭之所以用OV2640,主要是比較便宜,其他型號(hào)手上暫時(shí)也沒(méi)有。

2、步驟說(shuō)明

如何實(shí)現(xiàn)STM32和攝像頭(DCMIPP)的通訊這里不過(guò)多贅述,我們主要介紹一下實(shí)現(xiàn)車牌識(shí)別的步驟,這里我總結(jié)為三個(gè)部分:

1.車牌區(qū)域識(shí)別

2.字符分割

3.字符識(shí)別(尚未寫完)

接下來(lái)我將逐一介紹其實(shí)現(xiàn)方式,以下是區(qū)域識(shí)別和字符分割的實(shí)現(xiàn)。

目前字符識(shí)別還沒(méi)做完,所有的流程均有不同時(shí)間的延時(shí)以便展示。

3、區(qū)域識(shí)別

首先就是要如何識(shí)別出車牌的有效區(qū)域,我看許多人的做法是進(jìn)行灰度化之后再進(jìn)行二值化,再去檢測(cè)每行中跳變點(diǎn)的個(gè)數(shù)之類的。

不過(guò)我覺得跳變點(diǎn)個(gè)數(shù)對(duì)照片的效果要求太理想了,而且單純的灰度化的話引入的噪聲又比較大。

因此我嘗試著使用藍(lán)色閾值+藍(lán)色與紅色差異值的方式來(lái)進(jìn)行二值化,總而言之就是盡可能的提取出藍(lán)色特征。

for?(x =?0; x <?RGB_X; x++) {? ? ? ??for?(y =?0; y <?RGB_Y; y++) {? ? ? ? ? ? color = rgb_buf[x][y];? ? ? ? ? ? R = (color >>?11) *?255?/?31; ?// 提取紅色分量? ? ? ? ? ? G = ((color >>?5) &?0x3f) *?255?/?63; ?// 提取綠色分量? ? ? ? ? ? B = (color &?0x1f) *?255?/?31; ?// 提取藍(lán)色分量? ? ? ? ? ??// 根據(jù)藍(lán)色和紅色、綠色的差異進(jìn)行二值化處理? ? ? ? ? ??if?(B > (R + G) *?0.8) { ?// 如果藍(lán)色比紅色和綠色的總和大一定比例? ? ? ? ? ? ? ? color =?0xffff; ?// 白色? ? ? ? ? ? }?else?{? ? ? ? ? ? ? ? color =?0x0000; ?// 黑色? ? ? ? ? ? }? ? ? ? ? ??// 更新圖像緩沖區(qū)? ? ? ? ? ? rgb_buf[x][y] = color;? ? ? ? ? ??LCD->LCD_RAM?= rgb_buf[x][y];? ? ? ? ? ??LCD_SetCursor(X_Offset + y, Y_Offset + x);? ? ? ? ? ??LCD_WriteRAM_Prepare();? ? ? ? }? ? }

將RGB三色提取出來(lái)后,比較藍(lán)色和紅綠值來(lái)進(jìn)行二值化,這樣子可以很好的提取出藍(lán)色車牌我們需要的部分。

1

2

不過(guò)這個(gè)做法也有明顯的缺點(diǎn):就是只能識(shí)別藍(lán)色的車牌~~

可以看到二值化后仍然存留著一些噪聲,這里我們可以通過(guò)濾波降噪。

void?MedianFilter(u16 (*input)[RGB_Y], u16 (*output)[RGB_Y]){? ? u16 x, y;? ? u16 median[9]; ?// 用于存儲(chǔ)3x3鄰域的像素值? ? u16 temp;
? ??// 處理內(nèi)部像素(非邊界像素)? ??for?(x =?1; x < RGB_X -?1; x++) {? ? ? ??for?(y =?1; y < RGB_Y -?1; y++) {? ? ? ? ? ??// 獲取3x3鄰域的像素值? ? ? ? ? ? median[0] = input[x-1][y-1];? ? ? ? ? ? median[1] = input[x-1][y];? ? ? ? ? ? median[2] = input[x-1][y+1];? ? ? ? ? ? median[3] = input[x][y-1];? ? ? ? ? ? median[4] = input[x][y];? ? ? ? ? ? median[5] = input[x][y+1];? ? ? ? ? ? median[6] = input[x+1][y-1];? ? ? ? ? ? median[7] = input[x+1][y];? ? ? ? ? ? median[8] = input[x+1][y+1];
? ? ? ? ? ??// 對(duì)鄰域像素值進(jìn)行排序? ? ? ? ? ??for?(u8?i?=?0; i <?9; i++) {? ? ? ? ? ? ? ??for?(u8?j?=?i +?1; j <?9; j++) {? ? ? ? ? ? ? ? ? ??if?(median[i] > median[j]) {? ? ? ? ? ? ? ? ? ? ? ? temp = median[i];? ? ? ? ? ? ? ? ? ? ? ? median[i] = median[j];? ? ? ? ? ? ? ? ? ? ? ? median[j] = temp;? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? ? ? }
? ? ? ? ? ??// 取中值作為當(dāng)前像素的值? ? ? ? ? ? output[x][y] = median[4];? ? ? ? }? ? }? ? }

采用3x3的中值濾波算法降噪,可以有效的降低噪聲。

為了找到車牌區(qū)域,我們可以掃描每行白點(diǎn)最多的一行作為基準(zhǔn),自上,自下分別尋找這個(gè)最大值80%的行為哪一行,即確定車牌的上下行。

之后在此基礎(chǔ)上,對(duì)列也進(jìn)行這種操作,從右至左和從左至右找到車牌的左右區(qū)間。

4、字符分割

得到了車牌區(qū)域我們就可以考慮如何分割字符了,這里我采用的策略是從右到左去測(cè)量空白間隙。

即利用各字符之間的空隙,這里正好也是因?yàn)檫@個(gè)川字,所以考慮從右到左,因?yàn)檫@樣子可以避免去處理川字中間的幾個(gè)空隙。

/*? ? ??? ? ? ? 尋找分割線? ? ??? ? ? ? */? ? ? ? col_threshold = max_col_white *?80?/?100;? ? ? ??for(int i = right_col;i>left_col;i--)? ? ? ? {? ? ? ? ??if(YuzhiFlag)//右邊緣? ? ? ? ? {? ? ? ? ? ??if(col_white_counts[i]<max_col_white *?70?/?100)//左邊緣? ? ? ? ? ? {? ? ? ? ? ? ? line[number++] = i;? ? ? ? ? ? ??YuzhiFlag?= !YuzhiFlag;? ? ? ? ? ? }? ? ? ? ? }? ? ? ? ??else? ? ? ? ? {? ? ? ? ? ??if(col_white_counts[i]>max_col_white *?90?/?100)//最后一個(gè)字符? ? ? ? ? ? {? ? ? ? ? ? ? line[number++] = i;? ? ? ? ? ? ??YuzhiFlag?= !YuzhiFlag;? ? ? ? ? ? }? ? ? ? ? }? ? ? ??? ? ? ? }? ? ? ? int zifunumber =?0;? ? ? ??POINT_COLOR?=?RED;? ? ? ??for(int i =?0;i<number;i++)? ? ? ? {? ? ? ? ??? ? ? ? ??? ? ? ? ??if(((line[i]-line[i+1])>(right_col-left_col)*5/100)&&zifunumber<6)? ? ? ? ? {? ? ? ? ? ? box.zifu[zifunumber][0] = line[i];? ? ? ? ? ? box.zifu[zifunumber][1] = line[i+1];? ? ? ? ? ??? ? ? ? ? ??LCD_DrawLine(box.zifu[zifunumber][0]+65,top_row+225,box.zifu[zifunumber][0]+65,bottom_row+225);? ? ? ? ? ??LCD_DrawLine(box.zifu[zifunumber][1]+65,top_row+225,box.zifu[zifunumber][1]+65,bottom_row+225);? ? ? ? ? ? zifunumber++;? ? ? ? ? ? i++;? ? ? ? ? ??delay_ms(1000);? ? ? ? ? }? ? ? ? ??else?if(number>=6)? ? ? ? ? {? ? ? ? ? ? box.zifu[zifunumber][0] = line[i];? ? ? ? ? ? box.zifu[zifunumber][1] = left_col+3;? ? ? ? ? ??? ? ? ? ? ??LCD_DrawLine(box.zifu[zifunumber][0]+65,top_row+225,box.zifu[zifunumber][0]+65,bottom_row+225);? ? ? ? ? ??LCD_DrawLine(box.zifu[zifunumber][1]+65,top_row+225,box.zifu[zifunumber][1]+65,bottom_row+225);? ? ? ? ? ??break;? ? ? ? ? ??delay_ms(1000);? ? ? ? ? }? ? ? ? }

這樣子就可以實(shí)現(xiàn)分割字符的目的了。

5、字符識(shí)別

字符識(shí)別這兩天做,大體應(yīng)該是采用模板識(shí)別的策略,利用分割出來(lái)的字符和模板的匹配程度實(shí)現(xiàn)字符的識(shí)別。

這幾天有空在鉆研一下。

相關(guān)推薦