一、ZYNQ实现数字识别整体框架

来填坑啦!前面用matlab实现了用模板匹配识别字符的全部过程,但是发现在matlab上完成一张图片需要很久的时间,因此需要将其移植到ZYNQ的PL部分实现。然后下面这个图就是整个工程的框架了,基本就可以分为这几个部分,其中OV5640驱动盒hdmi驱动是前面已经实现的了,不再过多叙述。主要是包含了图像处理(VIP)模块,边界检测(border)模块以及字符识别(recog)模块。接下来分别介绍一下三个主模块。

配置zynq从emmc启动_bc

二、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模块仿真结果

配置zynq从emmc启动_bc_02


(原始RGB图像)

配置zynq从emmc启动_FPGA_03


(原始RGB图像的Cb分量)

配置zynq从emmc启动_bc_04


(原始RGB图像的gray分量)

配置zynq从emmc启动_bc_05


(Cb分量预处理结果)

配置zynq从emmc启动_bc_06


(gray分量预处理结果)

2.3 VIP模块上板验证结果

配置zynq从emmc启动_ZYNQ_07


(rgb图片)

配置zynq从emmc启动_bc_08


(Cb分量)

配置zynq从emmc启动_sed_09


(gray分量)

配置zynq从emmc启动_FPGA_10


(Cb分量预处理)

配置zynq从emmc启动_sed_11


(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分量预处理后的图像做垂直和水平投影的结果,下面的两条模拟信号,分别是垂直投影和水平投影,通过投影可以得到左右上下边界。

配置zynq从emmc启动_配置zynq从emmc启动_12


叠加边框后的rgb图像

配置zynq从emmc启动_配置zynq从emmc启动_13

3.3 边框检测模块上板验证结果

配置zynq从emmc启动_bc_14


配置zynq从emmc启动_ZYNQ_15


分别给出了Cb分量预处理后和边框的叠加输出以及RGB与边框的叠加输出,这边不是太明显,后期我把边框加粗一些,但是结果是没问题的。

四、总结

目前为止,完成了图片的预处理以及边框的识别,后续空余时间还会去完成每个字符的边界提取,用的也是投影算法。最后再用模板来匹配每个数字。