一、ZYNQ实现数字识别整体框架
来填坑啦!前面用matlab实现了用模板匹配识别字符的全部过程,但是发现在matlab上完成一张图片需要很久的时间,因此需要将其移植到ZYNQ的PL部分实现。然后下面这个图就是整个工程的框架了,基本就可以分为这几个部分,其中OV5640驱动盒hdmi驱动是前面已经实现的了,不再过多叙述。主要是包含了图像处理(VIP)模块,边界检测(border)模块以及字符识别(recog)模块。接下来分别介绍一下三个主模块。
二、Video image process module
2.1 VIP模块顶层代码
这个模块主要包含了三个子模块,分别是RGB转YUV、CB分量预处理以及gray分量预处理,预处理模块包含了对图像的滤波、二值化以及腐蚀膨胀运算。这边直接给出这个模块的顶层代码了,因为其中滤波开操作什么的我在前面文章已经都实现过了,就一个地方需要注意,仿真时候BMP图片是BGR排列的,而实际OV5640输出时RGB排列的,所以仿真和上板验证要注意转换一下格式。
module video_image_process(
input clk,
input rst_n,
//input key,
input [23:0] per_data,
input per_vsync,
input per_href,
input per_clken,
/*
output [23:0] post_data,
output post_vsync,
output post_href,
output post_clken,
*/
output [23:0] post_data_rgb,
output post_vsync_rgb,
output post_href_rgb,
output post_clken_rgb,
output [23:0] post_data_cb_data,
output post_vsync_cb_data,
output post_href_cb_data,
output post_clken_cb_data,
output [23:0] post_data_gray_data,
output post_vsync_gray_data,
output post_href_gray_data,
output post_clken_gray_data,
output [23:0] post_data_cb_pretreat_data,
output post_vsync_cb_pretreat_data,
output post_href_cb_pretreat_data,
output post_clken_cb_pretreat_data,
output [23:0] post_data_gray_pretreat_data,
output post_vsync_gray_pretreat_data,
output post_href_gray_pretreat_data,
output post_clken_gray_pretreat_data
);
parameter THRESHOLD_DATA=8'd150;
//-----------------------------
// rgb to ycbcr
//-----------------------------
wire [23:0] rgb_data;
wire [23:0] gray_data;
wire [23:0] cb_data;
wire [23:0] cr_data;
wire ycbcr_clk_en;
wire ycbcr_href;
wire ycbcr_vsync;
//assign rgb_data={per_data[7:0],per_data[15:8],per_data[23:16]};//bgr to rgb when sim
rgb2yuv u_rgb2yuv(
.pclk ( clk ),
.rst_n ( rst_n ),
.rgb_data ( per_data ),
.rgb_data_vaild ( per_href ),
.rgb_vsync ( per_vsync ),
.rgb_clk_en ( per_clken ),
.gray_data ( gray_data ),
.cb_data ( cb_data ),
.cr_data ( cr_data ),
.ycbcr_data_vaild ( ycbcr_href ),
.ycbcr_vsync ( ycbcr_vsync ),
.ycbcr_clk_en ( ycbcr_clk_en )
);
//-----------------------------
// cb img pretreat
//-----------------------------
wire [23:0] cb_pretreat_data;
wire cb_pretreat_clken;
wire cb_pretreat_href;
wire cb_pretreat_vsync;
pretreat#(
.THRESHOLD_DATA ( THRESHOLD_DATA )
)u1_pretreat(
.clk ( clk ),
.rst_n ( rst_n ),
.per_data ( cb_data ),
.per_clken ( ycbcr_clk_en ),
.per_href ( ycbcr_href ),
.per_vsync ( ycbcr_vsync ),
.post_data ( cb_pretreat_data ),
.post_clken ( cb_pretreat_clken ),
.post_href ( cb_pretreat_href ),
.post_vsync ( cb_pretreat_vsync )
);
//-----------------------------
// gray img pretreat
//-----------------------------
wire [23:0] gray_pretreat_data;
wire gray_pretreat_clken;
wire gray_pretreat_href;
wire gray_pretreat_vsync;
pretreat#(
.THRESHOLD_DATA ( THRESHOLD_DATA )
)u2_pretreat(
.clk ( clk ),
.rst_n ( rst_n ),
.per_data ( gray_data ),
.per_clken ( ycbcr_clk_en ),
.per_href ( ycbcr_href ),
.per_vsync ( ycbcr_vsync ),
.post_data ( gray_pretreat_data ),
.post_clken ( gray_pretreat_clken ),
.post_href ( gray_pretreat_href ),
.post_vsync ( gray_pretreat_vsync )
);
//-----------------------------
// output data
//-----------------------------
assign post_data_rgb=per_data;
assign post_vsync_rgb=per_vsync;
assign post_href_rgb=per_href;
assign post_clken_rgb=per_clken;
assign post_data_cb_data=cb_data;
assign post_vsync_cb_data=ycbcr_vsync;
assign post_href_cb_data=ycbcr_href;
assign post_clken_cb_data=ycbcr_clk_en;
assign post_data_gray_data=gray_data;
assign post_vsync_gray_data=ycbcr_vsync;
assign post_href_gray_data=ycbcr_href;
assign post_clken_gray_data=ycbcr_clk_en;
assign post_data_cb_pretreat_data=cb_pretreat_data;
assign post_vsync_cb_pretreat_data=cb_pretreat_vsync;
assign post_href_cb_pretreat_data=cb_pretreat_href;
assign post_clken_cb_pretreat_data=cb_pretreat_clken;
assign post_data_gray_pretreat_data=gray_pretreat_data;
assign post_vsync_gray_pretreat_data=gray_pretreat_vsync;
assign post_href_gray_pretreat_data=gray_pretreat_href;
assign post_clken_gray_pretreat_data=gray_pretreat_clken;
endmodule
2.2 VIP模块仿真结果
(原始RGB图像)
(原始RGB图像的Cb分量)
(原始RGB图像的gray分量)
(Cb分量预处理结果)
(gray分量预处理结果)
2.3 VIP模块上板验证结果
(rgb图片)
(Cb分量)
(gray分量)
(Cb分量预处理)
(gray分量预处理)
三、边框检测
3.1 边框检测模块代码
边框检测这边主要是使用了水平投影和垂直投影算法,这个在前面matlab仿真中就使用到了,这边不过多讲述原理,给出水平投影和垂直投影的代码。
(垂直投影检测左右边界)
module ver_projection
#(
parameter H_DISP=11'd1024,
parameter V_DISP=11'd768
)
(
input clk,
input rst_n,
input per_vsync,
input per_clken,
input per_href,
input [23:0] per_data,
input [10:0] v_start,
input [10:0] v_end,
//output post_vsync,
//output post_clken,
//output post_href,
//output [23:0] post_data,
output reg [9:0] max_left,
output reg [9:0] max_right,
output [10:0] x_cnt_test,
output [10:0] y_cnt_test,
output [9:0] max_line_left_test,
output [9:0] max_line_right_test,
output [9:0] max_data_left_test,
output [9:0] max_data_right_test,
output [9:0] data_out_test,
output [9:0] rd_data1_test,
output [9:0] rd_data2_test,
output [9:0] rd_data3_test
);
//-----------------------------
// signal delay
//-----------------------------
reg per_vsync_d1;
reg per_href_d1;
reg per_clken_d1;
reg [23:0] per_data_d1;
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
per_vsync_d1<=1'd0;
per_href_d1<=1'd0;
per_clken_d1<=1'd0;
per_data_d1<=24'd0;
end
else begin
per_vsync_d1<=per_vsync;
per_href_d1<=per_href;
per_clken_d1<=per_clken;
per_data_d1<=per_data;
end
end
//----------------------------------------
// posedge start and negedge end
//----------------------------------------
wire vsync_pos_start;
wire vsync_neg_end;
assign vsync_neg_end=per_vsync & (~per_vsync_d1);
assign vsync_pos_start=(~per_vsync) & per_vsync_d1;
//----------------------------------------
// x_cnt and y_cnt
//----------------------------------------
reg [10:0] x_cnt;
reg [10:0] y_cnt;
reg [10:0] x_cnt_d1;
reg [10:0] y_cnt_d1;
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
x_cnt<=11'd0;
y_cnt<=11'd0;
end
else if(vsync_pos_start==1'b1)begin
x_cnt<=11'd0;
y_cnt<=11'd0;
end
else if(per_clken & per_href) begin
if(x_cnt<H_DISP-1'b1)begin
x_cnt<=x_cnt+1'b1;
y_cnt<=y_cnt;
end
else begin
x_cnt<=11'd0;
y_cnt<=y_cnt+1'b1;
end
end
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
x_cnt_d1<=11'd0;
y_cnt_d1<=11'd0;
end
else begin
x_cnt_d1<=x_cnt;
y_cnt_d1<=y_cnt;
end
end
//----------------------------------------
// ver projection algo
//----------------------------------------
reg wr_en;
wire [9:0] data_in;
wire [9:0] data_out;
assign data_in=(y_cnt==11'd0)?10'd0:
(y_cnt>v_start && y_cnt<v_end)?per_data_d1[0]+data_out:
data_out;
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
wr_en<=1'b0;
end
else begin
wr_en<=per_clken & per_href;
end
end
//these has a bug, that is when x_cnt=1023, the data_out is brust
blk_mem_gen_1 u_blk_mem_gen_1(
.clka (clk), // input wire clka
.wea (wr_en), // input wire [0 : 0] wea
.addra (x_cnt_d1), // input wire [9 : 0] addra
.dina (data_in), // input wire [9 : 0] dina
.clkb (clk), // input wire clkb
.addrb (x_cnt), // input wire [9 : 0] addrb
.doutb (data_out) // output wire [9 : 0] doutb
);
//----------------------------------------
// find the border of left and rignt
//----------------------------------------
reg [9:0] rd_data1;
reg [9:0] rd_data2;
reg [9:0] rd_data3;
reg [9:0] max_data_left;
reg [9:0] max_data_right;
reg [9:0] max_line_left;
reg [9:0] max_line_right;
reg [9:0] max_d_left;
reg [9:0] max_d_right;
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
rd_data1<=10'd0;
rd_data2<=10'd0;
rd_data3<=10'd0;
end
else if(per_clken_d1 & per_href_d1 & x_cnt>4'd10 & x_cnt<H_DISP-4'd10)begin
rd_data1<=data_out;
rd_data2<=rd_data1;
rd_data3<=rd_data2;
end
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
max_data_left<=10'd0;
max_data_right<=10'd0;
max_line_left<=10'd0;
max_line_right<=10'd0;
end
else if(y_cnt==V_DISP-1'b1)begin
if( (rd_data3==10'd0) && (rd_data1>=10'd60) )begin
max_data_left<=rd_data1-rd_data3;
max_line_left<=x_cnt+3'd3;//offset
end
if( (rd_data3>=10'd60) && (rd_data1==10'd0) )begin
max_data_right<=rd_data3-rd_data1;
max_line_right<=x_cnt-4'd12;//offset
end
end
else if(vsync_pos_start)begin
max_data_left<=10'd0;
max_data_right<=10'd0;
max_line_left<=10'd0;
max_line_right<=10'd0;
end
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
max_left<=10'd0;
max_right<=10'd0;
max_d_left<=10'd0;
max_d_right<=10'd0;
end
else if(vsync_neg_end)begin
max_left<=max_line_left;
max_right<=max_line_right;
max_d_left<=max_data_left;
max_d_right<=max_data_right;
end
end
assign x_cnt_test=x_cnt;
assign y_cnt_test=y_cnt;
assign max_line_left_test=max_line_left;
assign max_line_right_test=max_line_right;
assign max_data_left_test=max_data_left;
assign max_data_right_test=max_data_right;
assign data_out_test=data_out;
assign rd_data1_test=rd_data1;
assign rd_data2_test=rd_data2;
assign rd_data3_test=rd_data3;
endmodule
(水平投影检测上下边界)
module hor_projection
#(
parameter H_DISP=11'd1024,
parameter V_DISP=11'd768
)
(
input clk,
input rst_n,
input per_vsync,
input per_clken,
input per_href,
input [23:0] per_data,
input [10:0] h_start,
input [10:0] h_end,
//output post_vsync,
//output post_clken,
//output post_href,
//output [23:0] post_data,
output reg [9:0] max_up,
output reg [9:0] max_down
);
//-----------------------------
// signal delay
//-----------------------------
reg per_vsync_d1;
reg per_href_d1;
reg per_clken_d1;
reg [23:0] per_data_d1;
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
per_vsync_d1<=1'd0;
per_href_d1<=1'd0;
per_clken_d1<=1'd0;
per_data_d1<=24'd0;
end
else begin
per_vsync_d1<=per_vsync;
per_href_d1<=per_href;
per_clken_d1<=per_clken;
per_data_d1<=per_data;
end
end
//----------------------------------------
// posedge start and negedge end
//----------------------------------------
wire vsync_pos_start;
wire vsync_neg_end;
assign vsync_neg_end=per_vsync & (~per_vsync_d1);
assign vsync_pos_start=(~per_vsync) & per_vsync_d1;
//----------------------------------------
// x_cnt and y_cnt
//----------------------------------------
reg [10:0] x_cnt;
reg [10:0] y_cnt;
reg [10:0] x_cnt_d1;
reg [10:0] y_cnt_d1;
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
x_cnt<=11'd0;
y_cnt<=11'd0;
end
else if(vsync_pos_start==1'b1)begin
x_cnt<=11'd0;
y_cnt<=11'd0;
end
else if(per_clken & per_href) begin
if(x_cnt<H_DISP-1'b1)begin
x_cnt<=x_cnt+1'b1;
y_cnt<=y_cnt;
end
else begin
x_cnt<=11'd0;
y_cnt<=y_cnt+1'b1;
end
end
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
x_cnt_d1<=11'd0;
y_cnt_d1<=11'd0;
end
else begin
x_cnt_d1<=x_cnt;
y_cnt_d1<=y_cnt;
end
end
//----------------------------------------
// hor projection algo
//----------------------------------------
reg wr_en;
wire [9:0] data_in;
wire [9:0] data_out;
wire [9:0] addra;
wire [9:0] addrb;
assign data_in=(y_cnt==11'd0)?10'd0:
(x_cnt>h_start && x_cnt<h_end && y_cnt!=V_DISP-1'b1)?per_data_d1[0]+data_out:
data_out;
assign addra=(y_cnt_d1==11'd0 || y_cnt_d1==V_DISP-1'b1)?x_cnt_d1:y_cnt_d1;
assign addrb=(y_cnt==11'd0 || y_cnt==V_DISP-1'b1)?x_cnt:y_cnt;
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
wr_en<=1'b0;
end
else if(y_cnt!=V_DISP-1'b1) begin
wr_en<=per_clken & per_href;
end
else begin
wr_en<=1'b0;
end
end
//write and read data meanhwile by a same address will make mistake
blk_mem_gen_1 u_blk_mem_gen_1(
.clka (clk), // input wire clka
.wea (wr_en), // input wire [0 : 0] wea
.addra (addra), // input wire [9 : 0] addra
.dina (data_in), // input wire [9 : 0] dina
.clkb (clk), // input wire clkb
.addrb (addrb), // input wire [9 : 0] addrb
.doutb (data_out) // output wire [9 : 0] doutb
);
//----------------------------------------
// find the border of left and rignt
//----------------------------------------
reg [9:0] rd_data1;
reg [9:0] rd_data2;
reg [9:0] rd_data3;
reg [9:0] max_data_up;
reg [9:0] max_data_down;
reg [9:0] max_line_up;
reg [9:0] max_line_down;
reg [9:0] max_d_up;
reg [9:0] max_d_down;
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
rd_data1<=10'd0;
rd_data2<=10'd0;
rd_data3<=10'd0;
end
else if(per_clken_d1 && y_cnt==V_DISP-1'b1)begin
rd_data1<=data_out;
rd_data2<=rd_data1;
rd_data3<=rd_data2;
end
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
max_data_up<=10'd0;
max_data_down<=10'd0;
max_line_up<=10'd0;
max_line_down<=10'd0;
end
else if(y_cnt==V_DISP-1'b1)begin
if( (rd_data3==10'd0) && (data_out>=10'd60) )begin
max_data_up<=data_out-rd_data3;
max_line_up<=x_cnt+3'd3;//offset
end
if( (rd_data3>=10'd60) && (data_out==10'd0) )begin
max_data_down<=rd_data3-data_out;
max_line_down<=x_cnt-4'd12;//offset
end
end
else if(vsync_pos_start)begin
max_data_up<=10'd0;
max_data_down<=10'd0;
max_line_up<=10'd0;
max_line_down<=10'd0;
end
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
max_up<=10'd0;
max_down<=10'd0;
max_d_up<=10'd0;
max_d_down<=10'd0;
end
else if(vsync_neg_end)begin
max_up<=max_line_up;
max_down<=max_line_down;
max_d_up<=max_data_up;
max_d_down<=max_data_down;
end
end
endmodule
(边框检测的顶层模块)
module border_projection
#(
parameter H_DISP=11'd1024,
parameter V_DISP=11'd768
)
(
input clk,
input rst_n,
input key,
input [23:0] per_data_rgb,
input per_vsync_rgb,
input per_href_rgb,
input per_clken_rgb,
input [23:0] per_data_cb_data,
input per_vsync_cb_data,
input per_href_cb_data,
input per_clken_cb_data,
input [23:0] per_data_gray_data,
input per_vsync_gray_data,
input per_href_gray_data,
input per_clken_gray_data,
input [23:0] per_data_cb_pretreat_data,
input per_vsync_cb_pretreat_data,
input per_href_cb_pretreat_data,
input per_clken_cb_pretreat_data,
input [23:0] per_data_gray_pretreat_data,
input per_vsync_gray_pretreat_data,
input per_href_gray_pretreat_data,
input per_clken_gray_pretreat_data,
input [10:0] v_start,
input [10:0] v_end,
input [10:0] h_start,
input [10:0] h_end,
output [9:0] max_left,
output [9:0] max_right,
output [9:0] max_up,
output [9:0] max_down,
output [23:0] post_data,
output post_clken,
output post_href,
output post_vsync,
//test pin
output [10:0] x_cnt_test,
output [10:0] y_cnt_test,
output [9:0] max_line_left_test,
output [9:0] max_line_right_test,
output [9:0] max_data_left_test,
output [9:0] max_data_right_test,
output [9:0] data_out_test,
output [9:0] rd_data1_test,
output [9:0] rd_data2_test,
output [9:0] rd_data3_test
);
//-----------------------------
// ver projection
//-----------------------------
ver_projection#(
.H_DISP ( H_DISP ),
.V_DISP ( V_DISP )
)u_ver_projection(
.clk ( clk ),
.rst_n ( rst_n ),
.per_vsync ( per_vsync_cb_pretreat_data ),
.per_clken ( per_clken_cb_pretreat_data ),
.per_href ( per_href_cb_pretreat_data ),
.per_data ( per_data_cb_pretreat_data ),
.v_start ( v_start ),
.v_end ( v_end ),
.max_left ( max_left ),
.max_right ( max_right ),
.x_cnt_test (x_cnt_test),
.y_cnt_test (y_cnt_test),
.max_line_left_test (max_line_left_test),
.max_line_right_test (max_line_right_test),
.max_data_left_test (max_data_left_test),
.max_data_right_test (max_data_right_test),
.data_out_test (data_out_test),
.rd_data1_test (rd_data1_test),
.rd_data2_test (rd_data2_test),
.rd_data3_test (rd_data3_test)
);
//-----------------------------
// hor projection
//-----------------------------
hor_projection#(
.H_DISP ( H_DISP ),
.V_DISP ( V_DISP )
)u_hor_projection(
.clk ( clk ),
.rst_n ( rst_n ),
.per_vsync ( per_vsync_cb_pretreat_data ),
.per_clken ( per_clken_cb_pretreat_data ),
.per_href ( per_href_cb_pretreat_data ),
.per_data ( per_data_cb_pretreat_data ),
.h_start ( h_start ),
.h_end ( h_end ),
.max_up ( max_up ),
.max_down ( max_down )
);
//-----------------------------
// find border
//-----------------------------
reg [10:0] x_cnt;
reg [10:0] y_cnt;
reg per_vsync_rgb_d1;
wire vsync_pos_start;
wire vsync_neg_end;
reg flag;
assign vsync_neg_end=per_vsync_rgb & (~per_vsync_rgb_d1);
assign vsync_pos_start=(~per_vsync_rgb) & per_vsync_rgb_d1;
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
per_vsync_rgb_d1<=1'd0;
end
else begin
per_vsync_rgb_d1<=per_vsync_rgb;
end
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
x_cnt<=11'd0;
y_cnt<=11'd0;
end
else if(vsync_pos_start==1'b1)begin
x_cnt<=11'd0;
y_cnt<=11'd0;
end
else if(per_clken_rgb & per_href_rgb) begin
if(x_cnt<H_DISP-1'b1)begin
x_cnt<=x_cnt+1'b1;
y_cnt<=y_cnt;
end
else begin
x_cnt<=11'd0;
y_cnt<=y_cnt+1'b1;
end
end
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
flag<=1'b0;
end
else begin
if( (x_cnt==max_left || x_cnt==max_right) && y_cnt>max_up && y_cnt<max_down)begin
flag<=1'b1;
end
else if( (y_cnt==max_up || y_cnt==max_down) && x_cnt>max_left && x_cnt<max_right)begin
flag<=1'b1;
end
else begin
flag<=1'b0;
end
end
end
//-----------------------------
// output data
//-----------------------------
wire key_flag;
reg [2:0] cnt;
wire [23:0] per_data_rgb1;
assign per_data_rgb1={per_data_rgb[23:16],per_data_rgb[7:0],per_data_rgb[15:8]};
key_filter u_key_filter(
.clk ( clk ),
.rst_n ( rst_n ),
.key_in ( key ),
.key_flag ( key_flag )
);
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
cnt<=3'd0;
end
else if(key_flag==1'b1)begin
cnt<=cnt+1'b1;
end
else cnt<=cnt;
end
assign post_data = (cnt==3'd0)? per_data_rgb1:
(cnt==3'd1)?per_data_cb_pretreat_data:
(cnt==3'd2 & flag==1'b1)?24'hff_00_00://white when sim and red when test
(cnt==3'd2 & flag==1'b0)?per_data_rgb1:
(cnt==3'd3 & flag==1'b1)?24'hff_00_00://white when sim and red when test
(cnt==3'd3 & flag==1'b0)?per_data_cb_pretreat_data:
(cnt==3'd4)?per_data_cb_data:
(cnt==3'd5)?per_data_gray_data:
(cnt==3'd6)?per_data_gray_pretreat_data:
per_data_rgb1;
assign post_vsync = (cnt==3'd0)? per_vsync_rgb:
(cnt==3'd1)?per_vsync_cb_pretreat_data:
(cnt==3'd2 & flag==1'b1)?per_vsync_rgb:
(cnt==3'd2 & flag==1'b0)?per_vsync_rgb:
(cnt==3'd3 & flag==1'b1)?per_vsync_cb_pretreat_data:
(cnt==3'd3 & flag==1'b0)?per_vsync_cb_pretreat_data:
(cnt==3'd4)?per_vsync_cb_data:
(cnt==3'd5)?per_vsync_gray_data:
(cnt==3'd6)?per_vsync_gray_pretreat_data:
per_vsync_rgb;
assign post_href = (cnt==3'd0)? per_href_rgb:
(cnt==3'd1)?per_href_cb_pretreat_data:
(cnt==3'd2 & flag==1'b1)?per_href_rgb:
(cnt==3'd2 & flag==1'b0)?per_href_rgb:
(cnt==3'd3 & flag==1'b1)?per_href_cb_pretreat_data:
(cnt==3'd3 & flag==1'b0)?per_href_cb_pretreat_data:
(cnt==3'd4)?per_href_cb_data:
(cnt==3'd5)?per_href_gray_data:
(cnt==3'd6)?per_href_gray_pretreat_data:
per_href_rgb;
assign post_clken = (cnt==3'd0)? per_clken_rgb:
(cnt==3'd1)?per_clken_cb_pretreat_data:
(cnt==3'd2 & flag==1'b1)?per_clken_rgb:
(cnt==3'd2 & flag==1'b0)?per_clken_rgb:
(cnt==3'd3 & flag==1'b1)?per_clken_cb_pretreat_data:
(cnt==3'd3 & flag==1'b0)?per_clken_cb_pretreat_data:
(cnt==3'd4)?per_clken_cb_data:
(cnt==3'd5)?per_clken_gray_data:
(cnt==3'd6)?per_clken_gray_pretreat_data:
per_clken_rgb;
/*
wire [23:0] per_data_rgb1;
assign per_data_rgb1={per_data_rgb[23:16],per_data_rgb[7:0],per_data_rgb[15:8]};
assign post_data=(flag==1'b1)?24'hff_ff_ff:per_data_rgb1;
assign post_clken=per_clken_rgb;
assign post_vsync=per_vsync_rgb;
assign post_href=per_href_rgb;
*/
//tets pin
endmodule
3.2 边框检测模块仿真结果
下面这张图是对Cb分量预处理后的图像做垂直和水平投影的结果,下面的两条模拟信号,分别是垂直投影和水平投影,通过投影可以得到左右上下边界。
叠加边框后的rgb图像
3.3 边框检测模块上板验证结果
分别给出了Cb分量预处理后和边框的叠加输出以及RGB与边框的叠加输出,这边不是太明显,后期我把边框加粗一些,但是结果是没问题的。
四、总结
目前为止,完成了图片的预处理以及边框的识别,后续空余时间还会去完成每个字符的边界提取,用的也是投影算法。最后再用模板来匹配每个数字。