zoukankan      html  css  js  c++  java
  • 基于Modelsim的均值滤波仿真

    一、前言

      本篇主要针对牟新刚编著《基于FPGA的数字图像图像原理及应用》中第7章第二节中的基于FPGA的均值滤波的内容进行仿真验证。2020-04-04 20:37:13

    二、算法实现原理

      整体设计

      求图像均值的步骤:

    1. 获得当前窗口所有像素。
    2. 计算当前串口所有像素之和。
    3. 将第2步结果除以当前窗口数据总数。
    4. 滑动窗口到下一个窗口,直到遍历完整幅图像。

      滤波采用滑动窗口方法来实现整幅图像的遍历,因此,采用流水线结构来设计。对于流水线结构来说,每个像素的运算方法是一致的,所需考

    虑的指示边界像素的处理问题。

        

      一般情况下,任何二维的计算步骤都可以化为一维的操作。由于行方向的数据是连续的,因此在流水线操作中,常常会首先进行行方向的操

    作。假定现在已经完成第一行的求和操作,接下来需要“等”下行的求和完成。如何进行等待?在FPGA中,等待的实现方法就是进行行缓存。二维

    操作转换为一维操作后的结构如下图所示。

      接下来的问题是,如何进行一维向量求和操作?对于1×5的向量求和而言,当前数据需要“等到”下4个数据到来之后才能得到连续5个数据,

    并执行加法操作。可以预期的是,还需要把前几个数据到来之后单独缓存起来,一个指定位宽的寄存器即可满足要求。

          

        

      最后的问题是求取窗口的均值,需要将上述计算出来的和除以一个归一化系数,也就是整个窗口的像素数目。在FPGA里面对于一方确定的除法

    操作,一般情况下不直接进行除法运算,而是通过近似的乘加方法来实现等效转换。在这里,对于固定的窗口,除法的分母是固定的。因此完全可

    以用此方法来实现等效近似。

      子模块设计

      需要设计如下几个子模块:

    1. 一维求和模块,这里记为sum_1d。
    2. 二维求和模块这里记为sum_2d。
    3. 除法转换模块,此模块比较简单,一般情况下不进行模块封装。
    4. 行缓存电路实现行列间像素对齐。

      整个顶层模块调用sum_2d模块和除法转换电路来实现求均值,记为Mean_2D。

      1.一维求和模块设计(sum_1d)

      用FPGA来求和是再简单不过的操作了,求和操作也是FPGA所擅长的事情之一。所要注意的只是求和结果不要溢出。一般情况下, 2个位宽为

    DW的数据相加,至少得用一个DW+1位宽的数据来存放。

      由于是求取连续数据流的和,最简单的办法是将数据连续打几拍,对齐后进行求和。假定窗口尺寸为5,则求和电路如下:

      图中求和电路的资源消耗为4个加法器、7个寄存器,运算开销为3个时钟。书中采用了另一种方法,利用增量更新的方式实现窗口横向求和。在

    连续两个像素求和的过程中,仅仅有头尾的两个像素不同。假定当前计算地址为n+1,计算结果为Sum(n+1),上一个地址为n,计算结果为

    Sum(n),输入数据为X(i),则有Sum(n+1) = Sum(n) + X(n+3) - X(n-2);也就是针对每一个窗口并不需要重新计算所有窗口内的像素和,可以通

    过前一个中心点的像素和再通过加法将新增点和舍弃点之间的差计算进去就可以获得新窗口内像素和。

      具体到FPGA实现方面,同样需要把数据连续打几拍,同时计算首个数据与最后一个数据的差。当前求和结果为上一个求和结果与计算之差的

    和。同样对于窗口尺寸为5的行方向求和操作,设计电路如下图所示。

         

      由图中可知,此电路只需1个加法器和1个减法器。无论窗口的尺寸多大,所需的加法器和减法器也都是1个。在窗口尺寸比较大的情况下,可得

    到比第一个设计电路更优的资源消耗的目的。不仅如此,求和电路的计算开销为1个时钟。

      2.二维求和模块设计(sum_2d)

      目前我们已经实现了窗口内一维行方向上的求和工作,现在要得到整个窗口内的像素之和,还必须将每一行的计算结果再叠加起来。那么每一

    行的计算结果是否也可以采取上面的增量更新的方法进行计算?答案显然是否定的,这是由于纵向的数据流不是流水线式的。

      同样,在进行列方向上的求和时,需要进行行缓存,并将一维行方向的求和结果打入行缓存,行缓存的个数为窗口尺寸减去1。就窗口尺寸5x5

    的情况而言,二维求和模块的电路设计如下图所示。

      

      3.除法电路设计

      对于分母固定的除法操作,可以通过泰勒展开或是移位转换等方式转换为FPGA所擅长的移位、加法与乘法操作。假定窗口尺寸为5,

    在求取窗口像素和之后需要除以25来求得均值。假定求得结果为Sum,计算后的均值为Average。则有

      Average = Sum/25

          = Sum×1/1024×1024/25

          = Sum/1024*40.96

               ≈ Sum/1024*(25 + 23 + 2-1 + 2-2 + 2-3 + 2-4 + 2-6 + 2-7)。

    三、代码实现

      代码部分参照书中的代码,针对书中代码进行补充和调整并移植到quartus平台下,芯片选用cyclone系列EP4CE115芯片;具体代码如下:

      1.一维求和模块sum_1d.v,此部分代码需要注意的增量更新求和技术的实现,同时数据输出有效的判断,依据书中代码每行数据前两个数据

    处于图像的边界,因此数据有效信号延迟两个时钟周期后进行输出。

     1 `timescale 1ps/1ps
     2 
     3 //=========================================================================//
     4 //FileName: sum_1d.v
     5 //Function: 一维求和电路的设计,设计的重点在于前端数据寄存器的设计。
     6 //Date: 2020-03-19
     7 //========================================================================//
     8 
     9 module sum_1d(
    10     clk,        //同步时钟
    11     din,        //输入数据流
    12     din_valid,    //输入数据有效
    13     dout_valid,    //输出数据有效
    14     dout        //输出数据流
    15 );
    16 
    17     parameter DW = 14;    //数据位宽参数
    18     parameter KSZ = 3;    //求和窗口参数
    19     
    20     //port declared
    21     input clk;
    22     input [DW-1:0] din;
    23     input din_valid;
    24     output dout_valid;
    25     output [2*DW-1:0] dout;
    26     
    27     //variable declared
    28     reg  [KSZ:0]     din_valid_r;
    29     integer j;
    30     
    31     //定义KSZ+1个输入寄存器
    32     reg [DW-1:0] reg_din[0:KSZ];
    33     
    34     //定义上一个求和寄存器
    35     reg [2*DW-1:0] sum;
    36     
    37     //定义中间信号
    38     wire [2*DW-1:0] sub_out;
    39     
    40     //定义减法器输出信号
    41     wire [2*DW-1:0] diff;
    42     
    43     //连续缓存KSZ拍信号,同时缓存输入有效信号
    44     always@(posedge clk)begin
    45         din_valid_r <= #1 ({din_valid_r[KSZ-1:0],din_valid});
    46         reg_din[0] <= #1 din;
    47         for(j = 1; j <= KSZ; j = j + 1)
    48             reg_din[j] <= #1 reg_din[j - 1];
    49     end
    50     
    51     //做减法计算差值
    52     assign sub_out = ((din_valid_r[0] == 1'b1 & din_valid_r[KSZ] == 1'b1)) ? 
    53                     ({{DW{1'b0}},reg_din[KSZ]}) : ({2*DW{1'b0}});
    54                     
    55     assign diff = ({{DW{1'b0}},reg_din[0]}) - sub_out;
    56     
    57     //计算最后的求和结果
    58     always@(posedge clk)begin
    59         if(din_valid == 1'b1 & ((~(din_valid_r[0]))) == 1'b1)
    60             sum <= #1 {2*DW-1 + 1{1'b0}};
    61         else if((din_valid_r[0]) == 1'b1)
    62             sum <= #1 sum + diff;
    63     end
    64     
    65     //输出信号
    66     
    67     assign dout_valid = din_valid_r[1];
    68     assign dout = sum;
    69     
    70 endmodule

      2、二维求和模块设计sum_2d.v,该部分代码需要列缓存电路的实现、行列同步电路的生成、列方向的求和及边界置零处理。具体代码如下:

      1 `timescale 1ps/1ps
      2 
      3 //========================================================================================//
      4 //FileName: sum_2d.v
      5 //Function: 将数据流接入sum_1d模块进行行方向的求和,同时将行方向的求和结果依次打入行缓存,
      6 //对齐后输出进行列方向上的求和工作。
      7 //Date: 2020-03-19
      8 //========================================================================================//
      9 
     10 module sum_2d(
     11     rst_n,            //异步复位信号
     12     clk,            //同步时钟
     13     din_valid,        //输入数据有效
     14     din,            //输入数据流
     15     dout,            //输出数据流
     16     vsync,            //输入场同步信号
     17     vsync_out,        //输出场同步信号
     18     is_boarder,        //输出边界信息
     19     dout_valid        //输出数据有效
     20 );
     21 
     22     //参数定义
     23     parameter DW = 14;                    //数据位宽参数
     24     parameter KSZ = 3;                    //求和窗口参数
     25     parameter IH = 512;                    //图像高度
     26     parameter IW = 640;                    //图像宽度
     27     parameter radius = ((KSZ >> 1));    //边界参数
     28     
     29     //port declared
     30     input                rst_n;
     31     input                clk;
     32     input                din_valid;
     33     input [DW-1:0]         din;
     34     output [2*DW-1:0]    dout;
     35     input                vsync;
     36     output                vsync_out;
     37     output                is_boarder;
     38     output                dout_valid;
     39     
     40     //variable declared
     41     reg                    rst_all;
     42     reg  [DW-1:0]        line_dinl[0:KSZ-2];
     43     wire [DW-1:0]        line_doutl[0:KSZ-2];
     44     reg     [DW-1:0]        data_temp_l[0:KSZ-2];
     45     reg  [DW-1:0]        line_dinh[0:KSZ-2];
     46     wire [DW-1:0]        line_douth[0:KSZ-2];
     47     reg     [DW-1:0]        data_temp_h[0:KSZ-2];
     48     wire                 line_emptyl[0:KSZ-2];
     49     wire                 line_fulll[0:KSZ-2];
     50     wire                 line_rdenl[0:KSZ-2];
     51     wire                 line_wrenl[0:KSZ-2];
     52     wire                 line_emptyh[0:KSZ-2];
     53     wire                 line_fullh[0:KSZ-2];
     54     wire                 line_rdenh[0:KSZ-2];
     55     wire                 line_wrenh[0:KSZ-2];
     56     wire [9:0]            line_countl[0:KSZ-2];
     57     wire [9:0]            line_counth[0:KSZ-2];
     58     
     59     //wire                din_valid_r;
     60     wire [2*DW-1:0]        sum;
     61     wire [2*DW-1:0]        sum_row;
     62     
     63     reg  [KSZ-2:0]        buf_pop_en;
     64     reg                    valid_r;
     65     
     66     reg  [10:0]            in_line_cnt;
     67     reg  [15:0]            flush_cnt;
     68     reg                    flush_line;
     69     reg  [15:0]            out_pixel_cnt;
     70     reg  [10:0]            out_line_cnt;
     71     reg  [2*DW-1:0]        dout_temp_r;
     72     reg                 dout_valid_temp_r;
     73     //wire [2*DW-1:0]        dout_temp;
     74     wire                dout_valid_temp;
     75     
     76     wire [2*DW-1:0]        sum_row1;
     77     wire [2*DW-1:0]        sum_row2;
     78     wire [2*DW-1:0]        sum_row3;
     79     wire [2*DW-1:0]        sum_row4;
     80     reg  [2*DW-1:0]        sum_1_2;
     81     reg  [2*DW-1:0]        sum_3_4;
     82     reg  [2*DW-1:0]        sum_0_1_2;
     83     reg  [2*DW-1:0]        sum_3_4_r;
     84     reg  [2*DW-1:0]        sum_row_r;
     85     reg  [2*DW-1:0]        sum_all;
     86     
     87     wire                is_boarder_tmp;
     88     reg                    is_boarder_r;
     89     wire                valid;
     90     wire                row_valid;
     91     //reg                 row_valid_r;
     92     //wire                vsync_out_temp;
     93     
     94     reg  [10:0]            line_valid_r;
     95     
     96     assign valid = din_valid | flush_line;
     97     
     98     always@(posedge clk or negedge rst_n)begin
     99         if(rst_n == 1'b0)
    100             rst_all <= #1 1'b1;
    101         else
    102         begin
    103             if(vsync == 1'b1)
    104                 rst_all <= #1 1'b1;
    105             else
    106                 rst_all <= #1 1'b0;
    107         end
    108     end
    109     
    110     /*
    111     always@(posedge clk)
    112     begin
    113         if(rst_all == 1'b1)
    114             row_valid_r <= #1 1'b1;
    115         else
    116             row_valid_r <= #1 row_valid;
    117     end
    118     */
    119     
    120     //首先例化一个行方向上的求和模块
    121     //wire [2*DW-1:0] sum_row;        //行求和信号
    122     
    123     sum_1d#(DW,KSZ)
    124         row_sum(
    125             .clk(clk),
    126             .din(din),
    127             .din_valid(valid),
    128             .dout(sum_row),                //输出行求和结果
    129             .dout_valid(row_valid)        //行求和结果有效
    130         );
    131 
    132     //例化(KSZ-1)个行缓存
    133     generate
    134     begin : line_buffer_inst
    135         genvar i;
    136         for(i = 0; i <= KSZ - 2; i = i + 1)
    137         begin : line_buf
    138             if(i == 0)
    139                 begin : row_1st    //第一行缓存,输入数据为行求和结果
    140                     always@(*) line_dinl[i] <= sum_row[DW-1:0];
    141                     always@(*) line_dinh[i] <= sum_row[2*DW-1:DW];
    142                     assign line_wrenl[i] = row_valid;
    143                     assign line_wrenh[i] = row_valid;
    144                 end
    145 
    146             if((~(i == 0)))
    147                 begin : row_others //其余行缓存,输入数据为上一行的输出
    148                     always@(*) line_dinl[i] <= line_doutl[i - 1];
    149                     always@(*) line_dinh[i] <= line_douth[i - 1];
    150                     assign line_wrenh[i] = line_rdenh[i - 1];
    151                     assign line_wrenl[i] = line_rdenl[i - 1];
    152                 end
    153 
    154             assign line_rdenl[i] = buf_pop_en[i] & row_valid;
    155             assign line_rdenh[i] = buf_pop_en[i] & row_valid;
    156             
    157             //行缓存装满一行后打出
    158             always@(posedge clk)
    159             begin
    160                 if(rst_all == 1'b1)
    161                     buf_pop_en[i] <= #1 1'b0;
    162                 else if(line_countl[i] == IW)
    163                     buf_pop_en[i] <= #1 1'b1;
    164             end
    165     
    166             //输入数据缓存
    167             always@(*) data_temp_l[i] <= line_dinl[i];
    168             
    169             //行缓存低半部分
    170                 line_buffer_row line_buf_l(
    171                     .aclr(rst_all),
    172                     .clock(clk),
    173                     .data(data_temp_l[i]),
    174                     .rdreq(line_rdenl[i]),
    175                     .wrreq(line_wrenl[i]),
    176                     .empty(line_emptyl[i]),
    177                     .full(line_fulll[i]),
    178                     .q(line_doutl[i]),
    179                     .usedw(line_countl[i])
    180                 );    
    181                 
    182             always@(*) data_temp_h[i] <= line_dinh[i];
    183 
    184             //行缓存高半部分
    185             line_buffer_row line_buf_h(
    186                     .aclr(rst_all),
    187                     .clock(clk),
    188                     .data(data_temp_h[i]),
    189                     .rdreq(line_rdenh[i]),
    190                     .wrreq(line_wrenh[i]),
    191                     .empty(line_emptyh[i]),
    192                     .full(line_fullh[i]),
    193                     .q(line_douth[i]),
    194                     .usedw(line_counth[i])
    195                 );    
    196                 
    197         end
    198     end
    199     endgenerate
    200 
    201     //列方向求和,窗口尺寸为5*5
    202     generate
    203     if(KSZ == 5)begin : sum_ksz_5
    204         //首先得到之前已经缓冲的4行的求和结果
    205         assign sum_row1 = ({line_douth[0][DW - 1:0],line_doutl[0][DW - 1]});
    206         assign sum_row2 = ({line_douth[1][DW - 1:0],line_doutl[1][DW - 1]});
    207         assign sum_row3 = (((buf_pop_en[2]) == 1'b1)) ? ({line_douth[2][DW - 1:0],line_doutl[2][DW - 1]}) : {2*DW{1'b0}};
    208         assign sum_row4 = (((buf_pop_en[3]) == 1'b1)) ? ({line_douth[3][DW - 1:0],line_doutl[3][DW - 1]}) : {2*DW{1'b0}};
    209         
    210         
    211         //运算延时为4个时钟
    212         assign dout_valid_temp = line_valid_r[2 + 2];
    213 
    214         always@(posedge clk)
    215         begin
    216             line_valid_r[4:0] <= ({line_valid_r[3:0],line_rdenl[1]});
    217             
    218             //缓存5拍行读取信号
    219             
    220             if((line_rdenl[1]) == 1'b1)
    221                 sum_row_r <= #1 sum_row;        //缓存当前行
    222             
    223             if((line_rdenl[1]) == 1'b1)
    224             begin
    225                 sum_1_2 <= #1 sum_row1 + sum_row2;    //1,2行相加
    226                 sum_3_4 <= #1 sum_row3 + sum_row4;    //3,4行相加
    227             end
    228             
    229             if((line_valid_r[1]) == 1'b1)
    230             begin
    231                 
    232                 //当前行与1,2行求和后相加
    233                 sum_0_1_2 <= #1 sum_row_r + sum_1_2;
    234                 
    235                 //3,4行求和结果缓存
    236                 sum_3_4_r <= #1 sum_3_4;    
    237                     
    238             end
    239             
    240             //得到5行的求和结果
    241             if((line_valid_r[1]) == 1'b1)
    242                 sum_all <= #1 sum_0_1_2 + sum_0_1_2 + sum_3_4_r;
    243             
    244         end
    245     end
    246     endgenerate
    247     
    248     wire [2*DW - 1:0] dout_reg;
    249     
    250     //边界设置零处理
    251     assign dout_reg = ((is_boarder_tmp == 1'b1)) ? {DW+1{1'b0}} : sum_all;
    252     
    253     assign dout = dout_temp_r;
    254     assign dout_valid = dout_valid_temp_r;
    255     assign is_boarder = is_boarder_r;
    256     
    257     //求和结果打一拍后输出
    258     always@(posedge clk)
    259     begin
    260         if(rst_all)
    261         begin
    262             dout_temp_r <= #1 {2*DW{1'b0}};
    263             dout_valid_temp_r <= #1 1'b0;
    264             valid_r <= #1 1'b0;
    265             is_boarder_r <= 1'b0;
    266         end
    267         else 
    268         begin
    269             if(dout_valid_temp == 1'b1)
    270                 dout_temp_r <= #1 dout_reg;
    271             else
    272                 dout_temp_r <= {2*DW{1'b0}};
    273                 
    274             dout_valid_temp_r <= #1 dout_valid_temp;
    275             valid_r <= #1 valid;
    276             is_boarder_r <= is_boarder_tmp;        
    277         end
    278     end
    279     
    280     /*输入行计数*/
    281     always@(posedge clk)
    282     begin
    283         if(rst_all == 1'b1)
    284             in_line_cnt <= #1 {11{1'b0}};
    285         else if(((~(valid))) == 1'b1 & valid_r == 1'b1)
    286             in_line_cnt <= #1 in_line_cnt + 11'b00000000001;
    287     end
    288     
    289     /*溢出行行列计数*/
    290     always@(posedge clk)
    291     begin
    292         if(rst_all)
    293         begin
    294             flush_line <= #1 1'b0;
    295             flush_cnt <= #1 {16{1'b0}};
    296         end
    297         else 
    298         begin
    299             
    300             //溢出行计数
    301             if(flush_cnt >= ((IW -1)))
    302                 flush_cnt <= #1 {16{1'b0}};
    303             else if(flush_line == 1'b1)
    304                 flush_cnt <= #1 flush_cnt + 16'b0000000000000001;
    305             
    306             //溢出行标记
    307             if(flush_cnt >= ((IW - 1)))
    308                 flush_line <= #1 1'b0;
    309             else if(in_line_cnt >= IH & out_line_cnt < ((IH - 1)))
    310                 flush_line <= #1 1'b1;
    311             
    312         end    
    313     end
    314     
    315     /*输出行行列计数*/
    316     always@(posedge clk)
    317     begin
    318         if(rst_all)
    319         begin
    320             out_pixel_cnt <= #1 {16{1'b0}};
    321             out_line_cnt <= #1 {11{1'b0}};
    322         end
    323         else 
    324         begin
    325             
    326             //输出行计数
    327             if(dout_valid_temp_r == 1'b1 & ((~(dout_valid_temp))) == 1'b1)
    328                 out_line_cnt <= #1 out_line_cnt + 11'b00000000001;
    329             else
    330                 out_line_cnt <= #1 out_line_cnt;
    331                 
    332             //输出像素计数
    333             if(dout_valid_temp_r == 1'b1 & ((~(dout_valid_temp))) == 1'b1)
    334                 out_pixel_cnt <= #1 {16{1'b0}};
    335             else if(dout_valid_temp == 1'b1)
    336                 out_pixel_cnt <= #1 out_pixel_cnt + 16'b0000000000000001;
    337                     
    338         end
    339     end
    340     
    341     //边界判决电路
    342     assign is_boarder_tmp = ((dout_valid_temp == 1'b1 & ((out_pixel_cnt <= (((radius - 1))))  | 
    343                                                          (out_pixel_cnt >= (((IW - radius)))) |
    344                                                          (out_line_cnt  <= (((radius - 1))))  |
    345                                                          (out_line_cnt  >= (((IH - radius))))))) ? 1'b1 : 1'b0;
    346     
    347     assign vsync_out = vsync;
    348     
    349 endmodule

      3、顶层模块设计Mean_2D.v,例化了一个二维求和模块sum_2d,并将其输出做除法处理即可。此处依然要留意边界信号的处理和有效信号的处理。具体代码如下:

      1 `timescale 1ps/1ps 
      2 
      3 //====================================================================================================//
      4 //FileName: Mean_2D.v
      5 //Function: TOP File Video_Cap -> RGB2GRAY -> HIST_EUQALIZE -> Mean_2D
      6 //Date: 2020-03-20
      7 //====================================================================================================//
      8 
      9 module Mean_2D(
     10     RSTn,                //全局复位
     11     CLOCK,                //系统时钟
     12     
     13     IMG_CLK,            //像素时钟
     14     IMG_DVD,            //像素值
     15     IMG_DVSYN,            //输入场信号
     16     IMG_DHSYN,            //输入数据有效信号
     17     Mean_DOUT,
     18     Mean_FOUT,
     19     Mean_VALID,
     20     Mean_VSYNC,
     21     Mean_BOARDER
     22 );
     23 
     24 /*image parameter*/
     25     parameter iw             = 640;        //image width
     26     parameter ih            = 512;        //image height
     27     parameter trig_value    = 400;         //250
     28     parameter tw            = 32;        //直方图统计数据位宽
     29     
     30     localparam half_width    = (tw >> 1); //将32位的数据位宽拆分为高低16位
     31     
     32     /*data width*/
     33     parameter dvd_dw     = 8;    //image source data width
     34     parameter dvd_chn    = 3;    //channel of the dvd data: when 3 it's rgb or 4:4:YCbCr
     35     parameter local_dw    = dvd_dw * dvd_chn;    //local algorithem process data width
     36     parameter cmd_dw    = dvd_dw * dvd_chn;    //local algorithem process data width
     37     parameter ksz         = 5;    //窗函数尺寸
     38     parameter latency   = ksz + 2;
     39 
     40     //Port Declared
     41     input RSTn;
     42     input CLOCK;
     43     input IMG_CLK;
     44     input [dvd_dw-1:0] IMG_DVD;
     45     input IMG_DVSYN;
     46     input IMG_DHSYN;
     47     output reg [dvd_dw-1:0] Mean_DOUT;
     48     output reg [dvd_dw-1:0] Mean_FOUT;
     49     output reg Mean_VALID;
     50     output reg Mean_VSYNC;
     51     output reg Mean_BOARDER;
     52 
     53     //Variable Declared
     54     wire GRAY_CLK;
     55     wire GRAY_VSYNC;
     56     wire GRAY_DVALID;
     57     wire [dvd_dw-1:0] Y_DAT;
     58     wire [dvd_dw-1:0] Cb_DAT;
     59     wire [dvd_dw-1:0] Cr_DAT;
     60     
     61     wire [local_dw-1:0] RGB_DAT;
     62     wire RGB_DVALID;
     63     wire RGB_VSYNC;
     64     
     65     //Mean_2D Variable
     66     wire [2*dvd_dw-1:0] sum_dout;
     67     wire sum_is_boarder;
     68     wire sum_vsync_out;
     69     wire sum_dout_valid;
     70     wire [dvd_dw-1:0] HISTEQUAL_DAT;
     71     wire HISTEQUAL_VALID;
     72     wire HISTEQUAL_VSYNC;
     73 
     74     video_cap video_cap_inst(
     75             .reset_l(RSTn),                //异步复位信号
     76             .DVD(IMG_DVD),                //输入视频流
     77             .DVSYN(IMG_DVSYN),            //输入场同步信号
     78             .DHSYN(IMG_DHSYN),            //输入行同步
     79             .DVCLK(IMG_CLK),            //输入DV时钟
     80             .cap_dat(RGB_DAT),            //输出RGB通道像素流,24位
     81             .cap_dvalid(RGB_DVALID),    //输出数据有效
     82             .cap_vsync(RGB_VSYNC),        //输出场同步
     83             .cap_clk(CLOCK),            //本地逻辑时钟
     84             .img_en(),                
     85             .cmd_rdy(),                    //命令行准备好,代表可以读取
     86             .cmd_rdat(),                //命令行数据输出
     87             .cmd_rdreq()                //命令行读取请求
     88         );
     89     
     90     defparam video_cap_inst.DW_DVD         = dvd_dw;
     91     defparam video_cap_inst.DW_LOCAL     = local_dw;
     92     defparam video_cap_inst.DW_CMD         = cmd_dw;
     93     defparam video_cap_inst.DVD_CHN     = dvd_chn;
     94     defparam video_cap_inst.TRIG_VALUE  = trig_value;
     95     defparam video_cap_inst.IW             = iw;
     96     defparam video_cap_inst.IH             = ih;
     97     
     98     RGB2YCrCb RGB2YCrCb_Inst(
     99             .RESET(RSTn),                //异步复位信号
    100             
    101             .RGB_CLK(CLOCK),            //输入像素时钟
    102             .RGB_VSYNC(RGB_VSYNC),        //输入场同步信号
    103             .RGB_DVALID(RGB_DVALID),    //输入数据有信号
    104             .RGB_DAT(RGB_DAT),            //输入RGB通道像素流,24位
    105             
    106             .YCbCr_CLK(GRAY_CLK),        //输出像素时钟
    107             .YCbCr_VSYNC(GRAY_VSYNC),    //输出场同步信号
    108             .YCbCr_DVALID(GRAY_DVALID),    //输出数据有效信号
    109             .Y_DAT(Y_DAT),                //输出Y分量
    110             .Cb_DAT(Cb_DAT),            //输出Cb分量
    111             .Cr_DAT(Cr_DAT)                //输出Cr分量
    112         );    
    113 
    114     defparam RGB2YCrCb_Inst.RGB_DW = local_dw;
    115     defparam RGB2YCrCb_Inst.YCbCr_DW = dvd_dw;
    116 
    117 
    118     hist_equalized hist_equalized_inst(
    119         .rst_n(RSTn),
    120         .clk(GRAY_CLK),
    121         .din_valid(GRAY_DVALID),        //输入数据有效
    122         .din(Y_DAT),                    //输入数据
    123         .dout(HISTEQUAL_DAT),            //输出数据
    124         .vsync(GRAY_VSYNC),                //输入场同步
    125         .dout_valid(HISTEQUAL_VALID),    //输出有效
    126         .vsync_out(HISTEQUAL_VSYNC)        //输出场同步
    127     );
    128     
    129     defparam hist_equalized_inst.DW = dvd_dw;
    130     defparam hist_equalized_inst.IH = ih;
    131     defparam hist_equalized_inst.IW = iw;
    132     defparam hist_equalized_inst.TW = tw;
    133 
    134     
    135     //例化一个二维求和模块
    136     sum_2d window_sum(
    137         .rst_n(RSTn),                        //异步复位信号
    138         .clk(GRAY_CLK),                        //同步时钟
    139         .din_valid(HISTEQUAL_VALID),        //输入数据有效
    140         .din(HISTEQUAL_DAT),                //输入数据流
    141         .dout(sum_dout),                    //输出数据流
    142         .vsync(HISTEQUAL_VSYNC),            //输入场同步信号
    143         .vsync_out(sum_vsync_out),            //输出场同步信号
    144         .is_boarder(sum_is_boarder),        //输出边界信息
    145         .dout_valid(sum_dout_valid)            //输出数据有效
    146     );
    147     
    148     defparam window_sum.DW = dvd_dw;
    149     defparam window_sum.KSZ = ksz;
    150     defparam window_sum.IH = ih;
    151     defparam window_sum.IW = iw;
    152     
    153     //除法电路设计
    154     /*首先定义中间计算寄存器*/
    155     reg [2*dvd_dw-1:0]         Mean_temp;
    156     reg [2*dvd_dw-1:0]         Mean_temp1;
    157     reg [2*dvd_dw:0]         Mean_temp2;
    158     reg [2*dvd_dw+5-1:0]     Mean_temp3;
    159     reg [2*dvd_dw+6-1:0]     Mean_temp4;
    160     reg [2*dvd_dw+1-1:0]     Mean_temp5;
    161     reg [2*dvd_dw+6-1:0]     Mean_temp6;
    162     reg [2*dvd_dw+6-1:0]     Mean_temp7;
    163     wire [2*dvd_dw+6-1:0]     Mean_temp8;
    164     wire [dvd_dw-1:0]         Mean_temp9;
    165     wire [dvd_dw+3-1:0]     Mean_temp10;
    166     wire [2*dvd_dw+6-1:0]     Mean_temp11;
    167     wire [2*dvd_dw-1:0]        Mean_out_temp;
    168     
    169     
    170     reg [2*dvd_dw-1:0] sum_dout_r[0:latency-1];
    171     reg sum_vsync_out_r [0:latency-1];
    172     reg sum_is_boarder_r [0:latency-1];
    173     reg sum_dout_valid_r [0:latency-1];
    174     
    175     generate
    176     
    177         if(ksz == 5)
    178         begin : divide_25 /*除以25操作*/
    179             always@(posedge CLOCK or negedge RSTn)
    180                 if(((~(RSTn))) == 1'b1) /*复位清零*/
    181                 begin
    182                     Mean_temp  <= {2*dvd_dw{1'b0}};
    183                     Mean_temp1 <= {2*dvd_dw{1'b0}};
    184                     Mean_temp2 <= {2*dvd_dw+1{1'b0}};
    185                     Mean_temp3 <= {2*dvd_dw+5-1+1{1'b0}};
    186                     Mean_temp4 <= {2*dvd_dw+6-1+1{1'b0}};
    187                     Mean_temp5 <= {2*dvd_dw+1-1+1{1'b0}};
    188                     Mean_temp6 <= {2*dvd_dw+6-1+1{1'b0}};
    189                 end
    190                 else
    191                 begin
    192                     
    193                     //将二维求和结果缓存到Mean_temp
    194                     if((sum_dout_valid_r[3]) == 1'b1)
    195                         Mean_temp <= #1 sum_dout_r[2];
    196                     
    197                     //下一拍开始计算
    198                     if((sum_dout_valid_r[4] == 1'b1))
    199                     begin
    200                         //计算Mean_temp (2^-6 + 2^-7)
    201                         Mean_temp1 <= #1 ({6'b000000, Mean_temp[2*dvd_dw-1:6]} +
    202                                           {7'b0000000, Mean_temp[2*dvd_dw-1:7]});
    203                                           
    204                         //计算Mean_temp (2^-3 + 2^-4)
    205                         Mean_temp2 <= #1 ({4'b0000, Mean_temp[2*dvd_dw-1:3]} +
    206                                           {5'b0000, Mean_temp[2*dvd_dw-1:4]});
    207                                           
    208                         //计算Mean_temp (2^-1 + 2^-2)
    209                         Mean_temp3 <= #1 ({6'b000000, Mean_temp[2*dvd_dw-1:1]} +
    210                                           {7'b0000000, Mean_temp[2*dvd_dw-1:2]});
    211                                           
    212                         //计算Mean_temp (2^-3 + 2^-5)
    213                         Mean_temp4 <= #1 ({1'b0, Mean_temp[2*dvd_dw-1:0],5'b0000} +
    214                                           {3'b000, Mean_temp[2*dvd_dw-1:0],3'b000});
    215                                           
    216                         //下一步开始计算上一拍的中间结果
    217                         if((sum_dout_valid_r[5]) == 1'b1)
    218                         begin
    219                             Mean_temp5 <= #1 ({1'b0,Mean_temp1} + Mean_temp2);
    220                             Mean_temp6 <= #1 ({1'b0,Mean_temp3} + Mean_temp4);
    221                         end
    222                         
    223                         //下一拍开始计算上一拍的中间结果
    224                         if((sum_dout_valid_r[6]) == 1'b1)
    225                         begin
    226                             Mean_temp7 <= #1 ({5'b00000,Mean_temp5} + Mean_temp6);
    227                         end
    228                     end
    229                 end
    230         end
    231     endgenerate
    232     
    233     //求和结果/1024得到除以25的结果
    234     assign #1 Mean_temp8 = ((sum_is_boarder_r[6] == 1'b0)) ? ((Mean_temp7 >> 10)) : {2*dvd_dw + 6 - 1 + 1{1'b0}};
    235 
    236     //四舍五入
    237     assign #1 Mean_temp9 = (((Mean_temp7[9]) == 1'b0)) ? (Mean_temp8[dvd_dw - 1:0] + 1'b1) : Mean_temp8[dvd_dw - 1:0];
    238     
    239     //以下对输出结果保存三位小数
    240     assign #1 Mean_temp11 = ((sum_is_boarder_r[6] == 1'b0)) ? ((Mean_temp7 >> 7)) : {2*dvd_dw + 6 - 1 + 1{1'b0}};
    241     
    242     assign #1 Mean_temp10 = (Mean_temp11[dvd_dw + 3 -1:0] + 1'b1);
    243     
    244     /*缓存输出求和结果,求和边界信息和求和有效信息等*/
    245     generate
    246         begin : xhd1
    247             genvar i;
    248             for(i = 0; i <= latency - 1; i = i + 1)
    249             begin : buf_cmp_inst
    250                 if(i == 0)
    251                     begin : xhd2
    252                     always@(posedge CLOCK or negedge RSTn)
    253                         if(((~(RSTn))) == 1'b1)
    254                             begin
    255                                 sum_dout_r[i]         <= #1 {2*dvd_dw{1'b0}};
    256                                 sum_vsync_out_r[i]     <= #1 1'b0;
    257                                 sum_is_boarder_r[i] <= #1 1'b0;
    258                                 sum_dout_valid_r[i] <= #1 1'b0;
    259                             end
    260                         else
    261                             begin
    262                                 sum_dout_r[i]         <= #1 sum_dout;
    263                                 sum_vsync_out_r[i]     <= #1 sum_vsync_out;
    264                                 sum_is_boarder_r[i] <= #1 sum_is_boarder;
    265                                 sum_dout_valid_r[i] <= #1 sum_dout_valid;
    266                             end
    267                     end
    268                     
    269                 if((~(i == 0)))
    270                     begin : xhd3
    271                     always@(posedge CLOCK or negedge RSTn)
    272                         if(((~(RSTn))) == 1'b1)
    273                             begin
    274                                 sum_dout_r[i]         <= #1 {2*dvd_dw{1'b0}};
    275                                 sum_vsync_out_r[i]     <= #1 1'b0;
    276                                 sum_is_boarder_r[i] <= #1 1'b0;
    277                                 sum_dout_valid_r[i] <= #1 1'b0;
    278                             end
    279                         else
    280                             begin
    281                                 sum_dout_r[i]         <= #1 sum_dout_r[i - 1];
    282                                 sum_vsync_out_r[i]     <= #1 sum_vsync_out_r[i - 1];
    283                                 sum_is_boarder_r[i] <= #1 sum_is_boarder_r[i - 1];
    284                                 sum_dout_valid_r[i] <= #1 sum_dout_valid_r[i - 1];
    285                             end
    286                     end    
    287             end        
    288         end
    289     endgenerate
    290 
    291     //输出相应信号
    292     always@(posedge CLOCK or negedge RSTn)
    293         if(((~(RSTn))) == 1'b1)
    294         begin
    295             Mean_DOUT         <= #1 {dvd_dw{1'b0}};
    296             Mean_FOUT        <= #1 {dvd_dw{1'b0}};
    297             Mean_VALID         <= #1 1'b0;
    298             Mean_VSYNC         <= #1 1'b0;
    299             Mean_BOARDER     <= #1 1'b0;
    300         end
    301         else
    302         begin
    303             Mean_DOUT         <= #1 Mean_temp9;
    304             Mean_FOUT        <= #1 Mean_temp10[7:0];
    305             Mean_VALID         <= #1 sum_dout_valid_r[6];
    306             Mean_BOARDER     <= #1 sum_is_boarder_r[6];
    307             Mean_VSYNC         <= #1 sum_vsync_out_r[6];
    308         end
    309     
    310 endmodule

      4、用于Modelsim仿真的Mean_2D_Tb.v文件,具体代码如下:

      1 `timescale 1ps/1ps
      2 
      3 module Mean_2D_Tb;
      4 
      5 
      6     /*image para*/
      7     parameter iw             = 640;        //image width
      8     parameter ih            = 512;        //image height
      9     parameter trig_value    = 400;     //250
     10 
     11     /*video parameter*/
     12     parameter h_total        = 2000;
     13     parameter v_total        = 600;
     14     parameter sync_b        = 5;
     15     parameter sync_e        = 55;
     16     parameter vld_b            = 65;
     17 
     18     parameter clk_freq         = 72;
     19 
     20     /*data width*/
     21     parameter dvd_dw     = 8;    //image source data width
     22     parameter dvd_chn    = 3;    //channel of the dvd data: when 3 it's rgb or 4:4:YCbCr
     23     parameter local_dw    = dvd_dw * dvd_chn;    //local algorithem process data width
     24     parameter cmd_dw    = dvd_dw * dvd_chn;    //local algorithem process data width
     25 
     26 
     27     /*test module enable*/
     28     parameter hist_equalized_en    = 0;
     29     parameter display_transform_en = 0;
     30     parameter mean_2d_en = 1;
     31     
     32 
     33     /*signal group*/
     34     reg pixel_clk = 1'b0;
     35     reg reset_l;
     36     reg [3:0] src_sel;
     37 
     38 
     39     /*input dv group*/
     40     wire dv_clk;
     41     wire dvsyn;
     42     wire dhsyn;
     43     wire [dvd_dw-1:0] dvd;
     44     
     45     /*dvd source data generated for simulation*/
     46     image_src image_src_inst//#(iw*dvd_chn, ih+1, dvd_dw, h_total, v_total, sync_b, sync_e, vld_b)
     47     (
     48         .clk(pixel_clk),
     49         .reset_l(reset_l),
     50         .src_sel(src_sel),
     51         .test_data(dvd),
     52         .test_dvalid(dhsyn),
     53         .test_vsync(dvsyn),
     54         .clk_out(dv_clk)
     55     );
     56         
     57     defparam image_src_inst.iw = iw*dvd_chn;
     58     defparam image_src_inst.ih = ih + 1;
     59     defparam image_src_inst.dw = dvd_dw;
     60     defparam image_src_inst.h_total = h_total;
     61     defparam image_src_inst.v_total = v_total;
     62     defparam image_src_inst.sync_b = sync_b;
     63     defparam image_src_inst.sync_e = sync_e;
     64     defparam image_src_inst.vld_b = vld_b;
     65     
     66     /*local clk: also clk of all local modules*/
     67     reg cap_clk = 1'b0;
     68         
     69     /*hist equalized operation module*/
     70     generate
     71         if(hist_equalized_en != 0)begin : equalized_operation
     72             wire equalized_dvalid;
     73             wire [dvd_dw-1:0] equalized_data;
     74             wire equalized_vsync;
     75             
     76             wire equalized_dvalid_in;
     77             wire [dvd_dw-1:0] equalized_data_in;
     78             wire equalized_vsync_in;
     79         
     80             integer fp_equalized,cnt_equalized = 0;
     81         
     82             /*video capture: capture image src and transfer it into local timing*/
     83             hist_equal hist_equal_inst(
     84                 .RSTn(reset_l),                        //全局复位
     85                 .CLOCK(cap_clk),                    //系统时钟
     86                 
     87                 .IMG_CLK(pixel_clk),                //像素时钟
     88                 .IMG_DVD(equalized_data_in),        //像素值
     89                 .IMG_DVSYN(equalized_vsync_in),        //输入场信号
     90                 .IMG_DHSYN(equalized_dvalid_in),    //输入数据有效信号
     91                 .HISTEQUAL_DAT(equalized_data),        //输出直方图统计数据
     92                 .HISTEQUAL_VALID(equalized_dvalid),    //输出直方图统计有效
     93                 .HISTEQUAL_VSYNC(equalized_vsync)    //数据读出请求
     94             );
     95             
     96             assign equalized_data_in = dvd;
     97             assign equalized_dvalid_in = dhsyn;
     98             assign equalized_vsync_in = dvsyn;
     99     
    100             always@(posedge cap_clk or posedge equalized_vsync)begin
    101                 if((~(equalized_vsync)) == 1'b0)
    102                     cnt_equalized = 0;
    103                 else begin
    104                     if(equalized_dvalid == 1'b1)begin
    105                         fp_equalized = $fopen("E:/Modelsim/hist_equalized/sim/equalized.txt","r+");
    106                         $fseek(fp_equalized,cnt_equalized,0);
    107                         $fdisplay(fp_equalized,"%02X",equalized_data);
    108                         $fclose(fp_equalized);
    109                         cnt_equalized <= cnt_equalized + 4;
    110                     end
    111                 end
    112             end
    113         end
    114     endgenerate
    115     
    116     /*hist linear transform module*/
    117     generate
    118         if(display_transform_en != 0) begin: display_transform_operation
    119             wire dis_trans_dvalid;
    120             wire [dvd_dw-1:0] dis_trans_data;
    121             wire dis_trans_vsync;
    122             wire dis_trans_dvalid_in;
    123             wire [dvd_dw-1:0] dis_trans_data_in;
    124             wire dis_trans_vsync_in;
    125             
    126             integer fp_dis_trans,cnt_dis_trans = 0;
    127             
    128             hist_transform hist_transform_inst(
    129                 .RSTn(reset_l),                                //全局复位
    130                 .CLOCK(cap_clk),                            //系统时钟
    131     
    132                 .IMG_CLK(pixel_clk),                        //像素时钟
    133                 .IMG_DVD(dis_trans_data_in),                //像素值
    134                 .IMG_DVSYN(dis_trans_vsync_in),                //输入场信号
    135                 .IMG_DHSYN(dis_trans_dvalid_in),            //输入数据有效信号
    136                 .HISTTRANS_DAT(dis_trans_data),                //输出直方图线性拉伸数据
    137                 .HISTTRANS_VALID(dis_trans_dvalid),            //输出直方图线性拉伸数据有效信号
    138                 .HISTTRANS_VSYNC(dis_trans_vsync)            //输出直方图线性拉伸场有效信号
    139             );
    140             
    141             assign dis_trans_data_in = dvd;
    142             assign dis_trans_dvalid_in = dhsyn;
    143             assign dis_trans_vsync_in = dvsyn;
    144             
    145             always@(posedge cap_clk or posedge dis_trans_vsync)begin
    146                 if((~(dis_trans_vsync)) == 1'b0)
    147                     cnt_dis_trans = 0;
    148                 else 
    149                 begin
    150                     if(dis_trans_dvalid == 1'b1)
    151                     begin
    152                         fp_dis_trans = $fopen("E:/Modelsim/hist_transform/sim/dis_trans.txt","r+");
    153                         $fseek(fp_dis_trans,cnt_dis_trans,0);
    154                         $fdisplay(fp_dis_trans,"%02x",dis_trans_data);
    155                         $fclose(fp_dis_trans);
    156                         cnt_dis_trans <= cnt_dis_trans + 4;    
    157                     end
    158                 end
    159             end    
    160         end
    161     endgenerate
    162     
    163     /*Mean Operation Module*/
    164     generate
    165         if(mean_2d_en != 0)begin : mean_operation
    166             
    167             /*mean data*/
    168             wire         mean_dvalid;
    169             wire [dvd_dw-1:0] mean_data;
    170             wire [dvd_dw-1:0] mean_data_frac;
    171             wire mean_vsync;
    172             
    173             /*mean data input*/
    174             wire        mean_dvalid_in;
    175             wire [dvd_dw-1:0] mean_data_in;
    176             wire        mean_vsync_in;
    177         
    178             integer fp_mean,cnt_mean = 0;
    179         
    180             Mean_2D Mean_2D_New(
    181                 .RSTn(reset_l),                    //全局复位
    182                 .CLOCK(cap_clk),                //系统时钟
    183     
    184                 .IMG_CLK(pixel_clk),            //像素时钟
    185                 .IMG_DVD(mean_data_in),            //像素值
    186                 .IMG_DVSYN(mean_vsync_in),        //输入场信号
    187                 .IMG_DHSYN(mean_dvalid_in),        //输入数据有效信号
    188                 .Mean_DOUT(mean_data),
    189                 .Mean_FOUT(mean_data_frac),
    190                 .Mean_VALID(mean_dvalid),
    191                 .Mean_VSYNC(mean_vsync),
    192                 .Mean_BOARDER()
    193             );
    194         
    195             assign mean_data_in     = dvd;
    196             assign mean_dvalid_in     = dhsyn;
    197             assign mean_vsync_in     = dvsyn;
    198         
    199             always@(posedge cap_clk or posedge mean_vsync)begin
    200                 if(((~(mean_vsync))) == 1'b0)
    201                     cnt_mean = 0;
    202                 else 
    203                 begin
    204                     if(mean_dvalid == 1'b1)
    205                     begin
    206                         fp_mean = $fopen("E:/Modelsim/Mean_2D/sim/mean.txt","r+");
    207                         $fseek(fp_mean,cnt_mean,0);
    208                         $fdisplay(fp_mean,"%02x",mean_data);
    209                         $fclose(fp_mean);
    210                         cnt_mean <= cnt_mean + 4;    
    211                     end
    212                 end
    213             end
    214         end
    215     endgenerate
    216         
    217     initial
    218     begin: init
    219         reset_l <= 1'b1;
    220         src_sel <= 4'b0000;
    221         #(100);            //reset the system
    222         reset_l <= 1'b0;
    223         #(100);    
    224         reset_l <= 1'b1;
    225     end
    226     
    227     //dv_clk generate
    228     always@(reset_l or pixel_clk)begin
    229         if((~(reset_l)) == 1'b1)
    230             pixel_clk <= 1'b0;
    231         else 
    232         begin
    233             if(clk_freq == 48)            //48MHz
    234                 pixel_clk <= #10417 (~(pixel_clk));
    235             
    236             else if(clk_freq == 51.84)    //51.84MHz
    237                 pixel_clk <= #9645 (~(pixel_clk));
    238             
    239             else if(clk_freq == 72)        //72MHz
    240                 pixel_clk <= #6944 (~(pixel_clk));
    241         end
    242     end
    243     
    244     //cap_clk generate: 25MHz
    245     always@(reset_l or cap_clk)begin
    246         if((~(reset_l)) == 1'b1)
    247             cap_clk <= 1'b0;
    248         else
    249             cap_clk <= #20000 (~(cap_clk));    
    250     end
    251     
    252 endmodule
    253     

    四、仿真结果

      1、一维求和模块,sum_1d。从仿真结果中可以看出,数据输出有效信号比输入有效信号延迟了两个时钟。书中说由于前面两个时钟的像素处于边界,因此头两个时钟数据无效。比较难理解哈,另外需要注意的是前面六个时钟,减法运算的处理上设置sub_out的值为0,这个也属于边界处理的手段,避免了行与行之间的干扰。

      2、二维求和模块sum_2d仿真结果,分为如下几个模块分析:

      (1)行求和数据的缓存,从仿真结果中可以看出行缓存的写使能与一维求和模块数据有效信号同步;行求和数据存满一行后,行缓存读出有效直至下一帧图像的输入。

      (2)列求和运算消耗4个时钟的延迟,其中以考虑到边界处理的因素,从第二行数据读出有效起始进行求和运算。

       

       (3)溢出行标记,当输入行技术大于512,且输出行技术小于511时,输出溢出行标记有效,其实也就是最后两行的输出数据记为边界行数据。

       3、除法运算仿真分析:

      从仿真结果中可以看出,输出的前两列为边界数据被置零处理。计算分析如下:

      第一个时钟:

      Mean_temp1 = 2-6 * 5187 + 2-7 * 5187 = 121.57

      Mean_temp2 = 2-3 * 5187 + 2-4 * 5187 = 972.5625

      Mean_temp3 = 2-1 * 5187 + 2-2 * 5187 = 3890.25

      Mean_temp4 = 23 * 5187 + 25 * 5187 = 207480

      第二个时钟:

      Mean_temp5 = Mean_temp1 + Mean_temp2 = 1094.1325

      Mean_temp6 = Mean_temp3 + Mean_temp4 = 211370.25

      第三个时钟:

      Mean_temp7 = Mean_temp5 + Mean_temp6 = 212464.3825

      除以1024得到最终结果:

      Mean_temp8 = Mean_temp7 / 1204 = 207.484

     

     五、结论

      如下图示为图像处理结果,原始灰度图像经过直方图均衡和均值滤波后图像亮度明显增强同时细节处可以看出均值滤波后图像变的光滑,同时可以看到在边界处理上外围的两行两列被置零处理。

      

    初入江湖,天下无敌;再学三年,寸步难行。
  • 相关阅读:
    C51中的 xbyte的使用
    使用正则表达式替换日期格式
    C#制作windows窗体的图书管理系统
    《短码之美》读书笔记3
    VS2019创建第一个ASP.NET网站
    观影大数据分析(上)
    Git提交文件报错解决
    软件设计简单工厂模式
    记录一次MySQL启动异常的解决
    将本机web项目映射到公网访问
  • 原文地址:https://www.cnblogs.com/huangwei0521/p/12639373.html
Copyright © 2011-2022 走看看