fpga 图像处理_FPGA图像处理中jv zhen

本文介绍了作者在FPGA图像处理中遇到的矩阵提取问题,特别是Line Buffer的使用。通过SpinalHDL,作者实现了一个无需用户填充边缘像素且带有Valid标志的串行输入像素到矩阵输出的IP。该IP适用于3x3矩阵,简化了FPGA中的图像处理过程,特别是在处理边缘像素时。作者提供了实现的代码,并表示该方法仅支持奇数大小的矩阵。
摘要由CSDN通过智能技术生成
06a618711b0c86f55d921fcf22b272d5.png

    对于图像处理的知识,个人仅限于研究生时上过的数字图像处理课程,而对于FPGA的数字图像处理,一直仅限于略(yan)有(gao)耳(shou)闻(di)。国庆躺尸看了点儿简单的FPGA图像处理,发现在FPGA图像处理中矩阵提取是个有趣的东东,本文仅限个人DIY,是否具有工程价值不做论述,权当一乐。

875e92f4039c28e2b596f3a6161f0003.png 21975fa25b0c0a19ffb2e3b376af6174.png

无处不在的line buffer

13b97fc61d6428fa236480b981ee2931.png

    闲暇逛知乎,发现在FPGA图像处理中,凡事牵涉到矩阵运算的算法里面基本都有line buffer的身影,而line buffer往往采用Xilinx的Ram-based Shift Register或者Altrea的Shift Register来实现:

948ddea70c21d204c30d09828338bdd9.png

    嗯,简单明了,似乎没什么难的,随后翻了翻两个厂商的IP,发现有点儿别扭:

    1、我把数据从IP的din灌入进去了,但输出数据什么时候有效没告诉我啊,虽然仿真时可以看到数据有效时的状态但设计里你还要我手动去控制判断什么时候是有效输出是不是有点儿过分了?……

    2、当年老师也讲过在进行矩阵处理时对于边缘像素提取矩阵时往往需要填充像素。软件里感觉还好但FPGA里实时地你要我补像素貌似有点儿麻烦哎?……

   也许个人太懒了吧,这种事情做起来都不复杂,但要在RTL里做这些我还是有点儿拒绝的。另辟蹊径,借助SpinalHDL里方便的电路描述符方式,魔改实现一个IP:

    1、串行输入像素,带Valid指示,输入前无需用户进行边缘像素填充。

    2、输出nxn矩阵用于做图像处理,输出数据有效带Valid标签。

    对于3x3矩阵,用户调用的RTL接口列表将会如下所示(起名有点儿随意?):

module bufWindow (  input               dataIn_valid,  input      [15:0]   dataIn_payload,  output              dataOut_valid,  output     [15:0]   dataOut_payload_0_0,  output     [15:0]   dataOut_payload_0_1,  output     [15:0]   dataOut_payload_0_2,  output     [15:0]   dataOut_payload_1_0,  output     [15:0]   dataOut_payload_1_1,  output     [15:0]   dataOut_payload_1_2,  output     [15:0]   dataOut_payload_2_0,  output     [15:0]   dataOut_payload_2_1,  output     [15:0]   dataOut_payload_2_2,  input               clk,  input               reset);endmodule
21975fa25b0c0a19ffb2e3b376af6174.png

line buffer实现

13b97fc61d6428fa236480b981ee2931.png

    首先要实现的是行缓冲器,说白了就是一连串移位寄存器,这里使用了SpinalHDL里提供的Histroy工具,它的定义是:

1588eac232763adebcb4f597c41d6241.png

    天然的实现行缓冲器的有效工具啊!!!几行代码就可以实现一个多抽头行缓冲器:

val sram=History(io.dataIn.payload,cfg.lineDepth*cfg.lineNum+1,init=U(0,cfg.dataWidth bits))for(index 0   io.dataOut.payload(index):=sram.vec((index+1)*cfg.lineDepth)}
    这里有一点需要注意的是History最后一个元素是延迟了length-1拍结果,故这里length为缓冲的像素数+1。    同时为了实现对边缘像素的处理,避免填补像素,在对外给输出Valid信号时需数据在到达缓存像素个数中间时给出有效标志(在矩阵处理时待处理像素都是在矩阵中间),同样需要借助一个缓冲器缓冲Valid标签:
val validRam=History(io.dataIn.valid,(cfg.lineNum+1)*cfg.lineDepth/2+1,init=False)
    至此行缓冲器的整体结构便有了(几行代码的事情)。 21975fa25b0c0a19ffb2e3b376af6174.png

bufWindow实现

13b97fc61d6428fa236480b981ee2931.png    有了line buffer的实现,bufWindow的实现就水到渠成了,line buffer按序输出了n行待处理的元素,接下来在bufWIndow里通过寄存器缓存实现矩阵窗口及数据有效标志位处理即可。    针对矩阵窗口的实现,由于line buffer输出已缓存的一排排数据,故在bufWidnow里只需再缓存nx(n-1)个元素即可,不多说,移位寄存(也可调整元素顺序,使得可算法描述里一一对应)~    而数据有效位的处理,则需对line buffer输出延迟(n+1)/2-1拍即可。
val windowValid=History(lineBuffers.io.dataOut.valid,(cfg.lineNum+1)/2,init=False)io.dataOut.valid:=windowValid.vec.last
21975fa25b0c0a19ffb2e3b376af6174.png

实现结果

13b97fc61d6428fa236480b981ee2931.png     对于行宽为3,行数为3,提取3x3矩阵仿真结果为(按行输入元素从左到右依次填充1,2,3……25) :
buffer window 10  0  00  1  20  4  5buffer window 20  0  01  2  34  5  6buffer window 30  0  12  3  45  6  7buffer window 40  1  23  4  56  7  8buffer window 51  2  34  5  67  8  9buffer window 62  3  45  6  78  9  0buffer window 73  4  56  7  89  0  0buffer window 84  5  67  8  90  0  0buffer window 95  6  78  9  00  0  0
      对于行宽为5,行数为5,提取5x5矩阵仿真结果为(按行输入元素从左到右依次填充1,2,3……25) :
buffer window 10  0  0  0  00  0  0  0  00  0  1  2  30  0  6  7  80  0  11  12  13buffer window 20  0  0  0  00  0  0  0  00  1  2  3  40  6  7  8  90  11  12  13  14buffer window 30  0  0  0  00  0  0  0  01  2  3  4  56  7  8  9  1011  12  13  14  15buffer window 40  0  0  0  00  0  0  0  12  3  4  5  67  8  9  10  1112  13  14  15  16buffer window 50  0  0  0  00  0  0  1  23  4  5  6  78  9  10  11  1213  14  15  16  17buffer window 60  0  0  0  00  0  1  2  34  5  6  7  89  10  11  12  1314  15  16  17  18buffer window 70  0  0  0  00  1  2  3  45  6  7  8  910  11  12  13  1415  16  17  18  19buffer window 80  0  0  0  01  2  3  4  56  7  8  9  1011  12  13  14  1516  17  18  19  20buffer window 90  0  0  0  12  3  4  5  67  8  9  10  1112  13  14  15  1617  18  19  20  21buffer window 100  0  0  1  23  4  5  6  78  9  10  11  1213  14  15  16  1718  19  20  21  22buffer window 110  0  1  2  34  5  6  7  89  10  11  12  1314  15  16  17  1819  20  21  22  23buffer window 120  1  2  3  45  6  7  8  910  11  12  13  1415  16  17  18  1920  21  22  23  24buffer window 131  2  3  4  56  7  8  9  1011  12  13  14  1516  17  18  19  2021  22  23  24  25buffer window 142  3  4  5  67  8  9  10  1112  13  14  15  1617  18  19  20  2122  23  24  25  0buffer window 153  4  5  6  78  9  10  11  1213  14  15  16  1718  19  20  21  2223  24  25  0  0buffer window 164  5  6  7  89  10  11  12  1314  15  16  17  1819  20  21  22  2324  25  0  0  0buffer window 175  6  7  8  910  11  12  13  1415  16  17  18  1920  21  22  23  2425  0  0  0  0buffer window 186  7  8  9  1011  12  13  14  1516  17  18  19  2021  22  23  24  250  0  0  0  0buffer window 197  8  9  10  1112  13  14  15  1617  18  19  20  2122  23  24  25  00  0  0  0  0buffer window 208  9  10  11  1213  14  15  16  1718  19  20  21  2223  24  25  0  00  0  0  0  0buffer window 219  10  11  12  1314  15  16  17  1819  20  21  22  2324  25  0  0  00  0  0  0  0buffer window 2210  11  12  13  1415  16  17  18  1920  21  22  23  2425  0  0  0  00  0  0  0  0buffer window 2311  12  13  14  1516  17  18  19  2021  22  23  24  250  0  0  0  00  0  0  0  0buffer window 2412  13  14  15  1617  18  19  20  2122  23  24  25  00  0  0  0  00  0  0  0  0buffer window 2513  14  15  16  1718  19  20  21  2223  24  25  0  00  0  0  0  00  0  0  0  0

    可以看到,bufWindow能够为每个元素提取相应的矩阵,不过在处理边缘像素时填充的元素不一定全为0,部分为其它边缘像素值,若在工程中这点可接收那么在处理时将减少很多工作量了~

    当然只是DIY,这里矩阵大小n只支持奇数。

47566b2fb50dd4c737807929d353aa04.png

       国庆假期要结束了,又要开启搬砖生涯了。想要源代码或者生成的RTL代码的小伙伴可私信我 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值