FPGA图像处理缓存处理方式

在FPGA进行图像处理的过程中,存储单元往往是比较宝贵的,如果使用外部存储,又会存在读取速度较慢的掣肘。
图像缓存

1.前言

一般情况下,在FPGA中进行处理图像时,我们总是希望能够处理更大的图像,但是FPGFA中的存储单元往往是较为宝贵的资源,尤其是图像尺寸很大的时候,就变得更加不现实,那么此时,对于整幅图像的处理根据其大小就分为两种方式, 帧缓存或者行缓存。

2.帧缓存

假如我们在图像处理过程中,我们需要对 n-2 、n-1、 ns三帧图像进行求平均值处理,那么我们就需要至少缓存三帧图像以供处理。
如下所示:

1
2
3
4
5
din----------->FB1 -----------> FB2 --------->| |
| | | | |
| | ----->|+ |----->dout
| --------------------->| |
------------------------------------->| |

在此种处理方式下,如果图像尺寸较大,就需要将图像存储在外部存储器中 :SRAM或DDR:

  • SRAM,如果对成本不太敏感,那么最好使用SRAM,相比于DDR来说,接口较为简单、速度较快、功耗比较低。
  • DDR,如果使用DDR作为外部存储的话,那么我们需要设计读地址发生器,写地址发生器以及读写时序控制,使用DDR适用于对读取速度没有太高要求的情景。

3.行缓存

如果对读取速度很敏感并且图片较大的情况下,那我们只能转换策略,用时间换空间,换言之,我们在读取图像的时候以行为单位进行处理。比如进行二维 3*3图像卷积处理,那么依据卷积的处理方法,我们需要使用三行帧缓存进行处理进行处理,如下所示:
行缓存
正如前面所示,行缓存会放在片内,每一个行缓存有效地将输入延迟了一行,那么在我们我们在进行卷积计算时就可以使用蓝色区域内的寄存器进行卷积计算。下面使用一个FIFO实现一个行缓存实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
module line_buffer{
rst,
clk,
din,
dout,
wr_en,
rd_en,
empty,
full,
count
};
parameter DW = 14; //数据位宽为14
paremeter IW = 640; //
parameter DEPTH = 1024; //宽度为1024
parameter DW_DEPTH = 10; //需要Depth = 10 , 2^10 = 1024,即是下方count的计数
localparam DW_PER_FIFO = 8; //假设FIFO的位宽为8,那么对于位宽大于8的数据,我们需要"并联"数据使用
localparam DW_PER_FIFO_LOG2 =3; //log为3,2^3=8,下面使用移位进行,而不是除法运算
localparam FIFO_NUM = ((DW + DW_PER_FIFO -1) >> DW_PER_FIFO_LOG2 );
//计算FIFO的数目(数据位宽为14,所以FIFO数目为 (14+8-1)/8 = 2)
input rst;
input clk;
input [DW-1:0] din;
output [DW-1:0] dout;
input wr_en;
input rd_en;
output empty;
output full;
output [DW_DEPTH-1:0] count; //2^10 = 1024
wire [DW_PER_FIFO-1:0] din_tmp[0:FIFO_NUM-1]; //定义输入暂存
wire [DW_PER_FIFO*FIFO_NUM-1:0] dout_tmp; //输出暂存
assign din_tmp[0] = din[DW_PER_FIFO-1-:DW_PER_FIFO];
altera_fifo_640 #(DW_PER_FIFO, DEPTH, DW_DEPTH)
buf_lsb(
.aclr(rst),
.clock(clk),
.data(din_tmp[0]),
.rdreg(rd_en),
.wrreg(wr_en),
.q(dout_temp[DW_PER_FIFO-1:0]),
.usedev(count),
.empty(empty),
.full(full)
);
assign dout = dout_tmp[DW-1:0];
generate
begin: fifo_generate
genvar i;
genvar j;
for(j=1; j<FIFO_NUM-2; j= j+1)
begin :xhdll
assign din_temp[j] = din[DW_PER_FIFO*(j+1)-1-:DW_PER_FIFO];
end
if(FIFO_NUM > 1)
assign din_temp[FIFO_NUM-1] = {{DW_PER_FIFO*FIFO_NUM-DW{1'b0}}, din[DW_PER_FIFO*(FIFO_NUM-1)]};
for(i = 1; i<= FIFO_NUM - 1; i = i + 1)
begin :xhd12
altera_fifo_640 #(DW_PER_FIFO,DEPTH, DW_DEPTH)
buf_others(
.aclr(rst),
.clock(clk),
.data(din_temp[i]),
.rdreg(rd_en),
.wrreg(wr_en),
.q(dout_tmp[DW_PER_FIFO*(i+1) -1-:DW_PER_FIFO])
);
end
emd
endgenerate
endmodule

版权声明:本文为博主原创文章,转载需声明为转载内容并添加原文地址。

原文地址:http://coderdock.com

Dock wechat
欢迎您扫一扫上面的微信公众号,订阅我的公众号