Verilog下的图像处理--第二话--downsample

来源:互联网 发布:深圳关键词排名软件 编辑:程序博客网 时间:2024/04/27 18:02

在FPGA上做图像处理时,常需要down sample来减少计算量。


如上图所示:row和column都是隔1个格取值,所以大小是原来的25%。

在C++里面直接用

for(r=0; r<row; r+2){

for(c=0; c<col; c+2)

dout = img[r*col+c];

}

到Verilog里面就要用2个状态来表达,一个是负责给row加2,另一个负责给col加2。 

注意:row在每加一次就跳到col的state来循环,当col加满时,调回到row的state,将row+2,然后又跳到col的state来循环加。




附上代码:

/*Module: DownSampler       "ds.v"Function: get data from buf, and downsample the img by 2 for row/col so the size is 25% of originalDate: Mar 26, 2014Version: 0.02*//*@din: get row-major data from buf@addr: used as enable pin to the buf@dout: shows the output// since 7500 x 8 bits, so the addr is log2(7500) = 13*/module DownSampler(//input [7:0] din,input clk,input start,input rst,output [12:0] addr,  // send addr to imagebuffer to retrive dataoutput finished);// 7-1 , 10-2 is find the closest %2 number;parameter row = 75-1, col = 100-2, len = 7500;reg [3:0] test ;reg [7:0] r, c;reg [7:0] ro;reg [7:0] co;// only sample the even-th row and col//assign valid = (start) && (r<row)&&(r%2==0) && (c<col)&&(c%2==0);assign valid_r = (start) && (r<row)&&(r%2==0);assign valid_c = (start) && (c<col)&&(c%2==0);assign finished = (r>row+1) || (c>col+2);assign addr = ro * (col+2) + co;/*always @ * beginro = r;co = c;end*/always @ * beginif (!finished) beginro = r;co = c;endelse beginro = 0;co = 0;endend//state:localparam  S0 = 0,S1 = 1,  // valid, update rowS2 = 2,  // valid, update columnS3 = 3;  // empty// State Reg:reg [1:0] next_s, curr_s;// followed Cumming registered output style:always @ (posedge clk) begincase (curr_s)S0: beginr <= 0;c <= 0;//test <= 0;endS1: beginr <= (c==0)?0:r+2;c <= (c<col)?c:0;//test <= 1;endS2: beginr <= r;c <= c+2;//test <= test + 3;endS3: beginr <= 99;c <= 100;//test <= 19;endendcaseend// State sync transitionalways @ (posedge clk or negedge rst) beginif(!rst)curr_s <= S0;elsecurr_s <= next_s;end// Conditional state transitionalways @ * beginnext_s = curr_s;case (curr_s)S0: beginif(start) next_s = S1;else next_s = S0;endS1: begin  // outter loop r++;if(valid_r) next_s = S2;else next_s = S3;endS2: begin  // inner loop c++; if(valid_c) next_s = S2;else next_s = S1;endS3: beginnext_s = S3;endendcaseendendmodulemodule tb_ds;reg clk;reg start;reg rst;wire [12:0] addr;wire finished;DownSampler ds(//din,clk,start,rst,addr,  // send addr to imagebuffer to retrive datafinished);always #5 clk = ~clk;initial begin$dumpfile("w.vcd");$dumpvars(0, tb_ds);//$monitor("addr= %d, time = %g", addr, $time);clk = 0;rst = 1;start = 0;#5 rst = 0;#1 rst = 1;#5 start = 1;#9990 $finish;endendmodule

从waveform里面可以很明显的看出是呈阶梯状,因为他的循环基数是col=100;这和CUDA里面的公式一样:row*col_size+col;



还有就是注意状态机的输出部分的写法:

UCB 的FSM规范里面说输出要用always@*,但是这样的话,就在col递增的循环里面定在第一次+2,后面就不加了,也因此不能退出这个状态返回到row的状态。然后看了Cumming的FSM规范里面说输出要用寄存器存起来,也就是用always@(posedge clk), 然后就可以了。

// output:always @ * begincase (curr_s)S0: beginr = -2;c = 0;ro = 0;co = 0;endS1: beginro = r+2;co = 0;endS2: beginro = r;co = c+2;endS3: beginro = 0;co = 0;endendcaseend
如图所示,虽然state是在col自家循环里面,但是并没有自加:



0 0
原创粉丝点击