仿真系統搭建
1 系統框圖
2 VGA時序發生器
由於圖像處理電路都是基於VGA時序,所以在仿真平臺中,需要有一個源VGA信號發生器,模仿VGA的時序。其模塊基本屬性如下所示:
`define pix_800_600
module vga_ctl
(
input pix_clk,
input reset_n,
input [23:0] VGA_RGB,
output VGA_CLK,
output [11:0] hcount,
output [11:0] vcount,
output [7:0] VGA_R,
output [7:0] VGA_G,
output [7:0] VGA_B,
output VGA_HS,
output VGA_VS,
output VGA_DE,
output BLK
);
`include "vga_parameter.vh"
對應不同分辨率,我們需要不同的VGA標準參數,這些參數定義在vga_parameter.vh文件中,例如本仿真平臺處理的圖像數據爲800*600:則該文件中應有如下參數的定義:
`ifdef pix_800_600
//---------------------------------//
// 800*600 60HZ pixel clock 40.00MHZ
//--------------------------------//
parameter H_Total = 1056;
parameter H_Sync = 128;
parameter H_Back = 88;
parameter H_Active = 800;
parameter H_Front = 40;
parameter H_Start = 216;//H_Sync+H_Back
parameter H_End = 1016;//H_Sync+H_Back+H_Active
//-------------------------------//
// 800*600 60HZ
//-------------------------------//
parameter V_Total = 628;
parameter V_Sync = 4;
parameter V_Back = 23;
parameter V_Active = 600;
parameter V_Front = 1;
parameter V_Start = 27;//V_Sync+V_Back
parameter V_End = 627;//V_Sync+V_Back+V_Active
`endif
3 圖像數據轉換
我們需要將待處理的圖像,轉換成爲VGA能夠解析的數據流,這部分利用Matlab實現數據格式的轉換。在工作目錄執行img_txt.m腳本,腳本執行結束之後,有如上圖所示效果。其中img爲拍攝的原圖,R、G、B爲三個通道的灰度圖。並在工作目錄下生成如下圖所示的文件:
爲了讀取這些文件,我們需要編寫verilog軟件程序,把它們轉換成RGB格式輸出到VGA的RGB輸出端。其模塊基本屬性如下:
`timescale 1ns/1ps
`define NULL 0
module imread_frame1(
input pixel_clk,
input reset_n,
input de,
input [11:0] frame_cnt,
output [23:0] rgb
);
經過上述幾個步驟,我們已經能夠把一幅圖像以VGA時序進行輸出,至此已經搭建出了圖像仿真系統的雛形,並且爲了將經過verilog處理的圖像以可視化的形式展現,還需要有verilog寫入圖像數據的軟件程序,其模塊基本屬性如下:
`timescale 1ns/1ps
`define NULL 0
module imwrite_frame4(
input pixel_clk,
input reset_n,
input de,
input [11:0] frame_cnt,
input [23:0] rgb
);
該程序會在圖像處理的過程中,將數據緩存到工作目錄,並且例化多個寫圖像的模塊,即可觀察到圖像處理的過程,其緩存結果如下:
最後,我們需要將verilog保存的文件利用matlab腳本txt_img.m轉換成可視化的圖片,觀察verilog處理過程是否正確。最後顯示處理結果如下
圖像處理仿真
1 RGB轉YCbCr
爲了方便進行圖像閾值的提取,利用verilog實現了RGB到YCbCr的色域轉換,計算式可以百度:
其效果如下圖所示
rgb2ycbcr U_rgb2ycbcr(
.pixelclk(pixel_clk),
.i_rgb(VGA_RGB),
.i_hsync(VGA_HS),
.i_vsync(VGA_VS),
.i_de(VGA_DE),
.o_rgb(y_rgb),
.o_ycbcr(y_ycbcr),
.o_gray(y_gray),
.o_hsync(y_o_hsync),
.o_vsync(y_o_vsync),
.o_de(y_o_de));
2 閾值確定與二值化
首先將車牌從複雜的環境中提取出來。確定車牌的閾值,二值化。
ycbcr_location#( //Paramter Define such as threshold
)U_ycbcr_location(
.pixelclk(pixel_clk),
.reset_n(reset_n),
.i_rgb(y_rgb),
.i_ycbcr(y_ycbcr),
.i_gray(y_gray),
.i_hsync(y_o_hsync),
.i_vsync(y_o_vsync),
.i_de(y_o_de),
.binary_image(yl_binary),
.rgb_image(yl_rgb),
.gray_image(yl_gray),
.o_hsync(yl_o_hsync),
.o_vsync(yl_o_vsync),
.o_de(yl_o_de)
);
3 鎖定車牌位置
通過水平垂直投影,可以將車牌框選出來,並且爲了便於識別數字,我們將車牌以外的顏色轉換成近似車牌的底色,便於進行第二次的垂直投影與閾值提取。此外,框選車牌的同時,削掉了一部分上下邊界,去除了定孔。
Vertical_Projection#( //Paramter Define such as threshold
)U_Vertical_Projection(
.pixelclk(pixel_clk),
.reset_n(reset_n),
.i_binary(HV_dout),
.i_hs(HV_o_hsync),
.i_vs(HV_o_vsync),
.i_de(HV_o_de),
.i_hcount(hcount),
.i_vcount(vcount),
.hcount_l(hcount_l),
.hcount_r(hcount_r),
.vcount_l(vcount_l),
.vcount_r(vcount_r));
可在modelsim中觀察仿真波形圖如下:
可以看到,車牌的水平邊界和垂直邊界都被取出,分別對應爲hcount_l, hcount_r, vcount_l, vcount_r這幾個信號。
4 提取車牌數字
這次,我們重複進行一次色域的轉換,在YCbCr色域下提取出車牌內的字符,效果如下圖所示,至此我們已經提取出了複雜場景下的車牌字符。
5 水平垂直投影
對已經經過二值化的車牌字符圖像,我們例化一個能夠檢測八個邊界的水平垂直投影模塊。其垂直投影后的效果如下圖所示
至此,我們可以將八個字符一個一個的分割,進行單獨的數字識別處理,極大的簡化了處理的難度。接下來介紹本工程中採用的兩種數字識別的方案。
6 方案一:數字特徵識別
本方案已經上板實現,但是仍然存在缺陷,比如說僅僅能識別數字,且識別條件較爲苛刻,需要現場調試一段時間。
7 方案二:5X8維矩陣檢測
對單個數字進行畫框操作,並且統計出每個小格子的像素點數目,超過該格子的一半則認爲是1,少於則認爲是0。下圖爲5的畫框仿真。
在modelsim中觀察仿真波形,則5的數字模型被正確識別,並且對於同一字體其數字特徵值應相同。
相關工程文件可以去我的個人博客下載: 點擊前往