FPGA图像处理系列——实现窗处理
2015-06-27 12:18
253 查看
本博文参考了《FPGA嵌入式图像处理系统设计》一书。该书的英文版下载链接:http://download.csdn.net/detail/lzy272942518/6949349
窗处理是图像处理中常见的一种处理,它的思想是对于图像矩阵,通过一个固定大小(例如3*3)的小矩阵对图像进行运算操作。常用的窗处理包括Sobel边缘检测,形态学操作,模糊滤波,高斯滤波等。在基于PC的图像处理领域,可以方便的实现窗处理操作。比如,在opencv库中可以自己随意构建窗口大小,然后调用相关的函数实现窗处理。FPGA是一种可定制的逻辑电路,它拥有并行的结构特征,在设计上能实现硬件并行和流水线技术,可以实现算法的加速,而且性价比较高。本文即根据Sobel算法的理论,结合FPGA的结构特征,在FPGA上设计并尝试实现了Sobel窗处理算法方案。
Sobel边缘检测的思想是:该算子包含两组3 x 3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度查分近似值。如果以A代表原始图像,Gx及Gy分别代表经纵向向及横向边缘检测的图像,其公式如下(来源于百度图片):
对于FPGA实现Sobel,首先,是检测窗的实现。这种窗扩展了点运算,以一个局部邻域或窗口内像素值的函数运算结果作为输出:
Q[x,y] = f(I[x,y],...,I[x+△x,y+△y]), (△x,△y)∈W
其中,W是I[x,y]为中心的窗口。以3×3大小的窗口为例,如图所示:
Sobel算子所需的窗口大小为3×3。在设计过程中,窗口应当满足以下要求:
1.能同时对窗口中所有的元素进行并行操作。
2.窗口采用流水的形式遍历整个图像。
设计的思路是:因为窗口在遍历图像过程中,每一个像素都会被窗口多次使用,因此需要通过缓存来存储像素,使得它们能在后续的窗口位置被重复利用。在FPGA中,可以设计3个单口行缓存(linebuffer),借助状态机和列计数值实现这种窗口,采用流水处理的方法,实现加速计算。如图为窗口结构:
其中状态信号用环形计数器来实现(计数值0-2),其驱动时钟为每一行第一个像素的像素时钟。窗口的行0由3个移位寄存器组成;行1——行2由状态机决定和行缓存的对应关系。窗口的控制逻辑如表1所示:
表1 窗口的控制逻辑
输入行 | 状态 | 行缓存0 | 行缓存1 | 行缓存2 | 输出行 |
0 | 0 | 写 | (行2) | (行1) | (空) |
1 | 1 | 行1 | 写 | (行2) | (空) |
2 | 2 | 行2 | 行1 | 写 | 1 |
3 | 0 | 写 | 行2 | 行1 | 2 |
4 | 1 | 行1 | 写 | 行2 | 3 |
5 | 2 | 行2 | 行1 | 写 | 4 |
6 | 0 | 写 | 行2 | 行1 | 5 |
…… | …… | …… | …… | …… |
对于窗口操作,存在的一个问题是边界部分无法得到处理。不过,本系统的窗口比较小,那么边界像素的输出可以不计算。这样输出的图像比输入图像减小了1行和1列,并不会影响图像显示效果。
具体实现思路:
1.窗口模块:
3个行缓存,每个大小为640×8 bit;
状态机,状态信号(0-2),以每一行第一个像素时钟作为驱动状态信号的时钟;
3个移位寄存器,每个大小为8 bit,作为检测窗口的第一行
窗口的实现,需要建立一个像素时钟驱使的always块,根据窗口结构和表1的控制逻辑,构造窗口;
2.边缘判断模块:
通过窗口可在像素点P处得到以其为中心,周围8个点的像素值。根据Sobel算子结构,进行计算。设置一个阈值,当计算后的值大于此阈值时,判定此像素为边缘。
关键部分代码(verilog):
always@(posedge PCLK)begin//产生行时钟,作为状态机驱动时钟 begin if(VtcHCnt==0) Line_CLK <= 1; else Line_CLK <= 0; end end reg[1:0] state; initial state = 0; always@(posedge Line_CLK)begin//产生状态计数器 if(VtcVCnt==1) state <= 2'b00; else begin if(state == 2'b10) state <= 2'b00; else state <= state + 1; end end //定义窗口第0行的三个元素 reg[7:0]S_Window0; reg[7:0]S_Window1; reg[7:0]S_Window2; //定义行缓存 reg[7:0]LineBuffer0[639:0]; reg[7:0]LineBuffer1[639:0]; reg[7:0]LineBuffer2[639:0]; always@(posedge PCLK)begin case(state) 2'b00: begin <span style="white-space:pre"> </span>LineBuffer0[VtcHCnt] <= GRAY; LineBuffer1[VtcHCnt] <= LineBuffer1[VtcHCnt]; LineBuffer2[VtcHCnt] <= LineBuffer2[VtcHCnt]; S_Window0 <= GRAY; S_Window1 <= S_Window0; S_Window2 <= S_Window1; if(VtcHCnt>=2&&VtcVCnt>=3)begin if((S_Window0 + S_Window1*2 + S_Window2)>(LineBuffer1[VtcHCnt-2]+LineBuffer1[VtcHCnt-1]*2 +LineBuffer1[VtcHCnt])) DOUT_reg <= ((S_Window0 + S_Window1*2 + S_Window2 -LineBuffer1[VtcHCnt-2]-LineBuffer1[VtcHCnt-1]*2 -LineBuffer1[VtcHCnt]))/4; else DOUT_reg <= (LineBuffer1[VtcHCnt-2]+LineBuffer1[VtcHCnt-1]*2 +LineBuffer1[VtcHCnt]-(S_Window0 + S_Window1*2 + S_Window2))/4; end end 2'b01: begin LineBuffer1[VtcHCnt] <= GRAY; LineBuffer0[VtcHCnt] <= LineBuffer0[VtcHCnt]; LineBuffer2[VtcHCnt] <= LineBuffer2[VtcHCnt]; S_Window0 <= GRAY; S_Window1 <= S_Window0; S_Window2 <= S_Window1; if(VtcHCnt>=2&&VtcVCnt>=3)begin if((S_Window0 + S_Window1 *2 + S_Window2)>(LineBuffer2[VtcHCnt-2]+LineBuffer2[VtcHCnt-1]*2 +LineBuffer2[VtcHCnt])) DOUT_reg <= ((S_Window0 + S_Window1*2 + S_Window2 -LineBuffer2[VtcHCnt-2]-LineBuffer2[VtcHCnt-1] *2 -LineBuffer2[VtcHCnt]))/4; else DOUT_reg <= (LineBuffer2[VtcHCnt-2]+LineBuffer2[VtcHCnt-1] *2 +LineBuffer2[VtcHCnt]-(S_Window0 + S_Window1*2 + S_Window2))/4; end end 2'b10: begin <span style="white-space:pre"> </span> LineBuffer2[VtcHCnt] <= GRAY; LineBuffer0[VtcHCnt] <= LineBuffer0[VtcHCnt]; LineBuffer1[VtcHCnt] <= LineBuffer1[VtcHCnt]; S_Window0 <= GRAY; S_Window1 <= S_Window0; S_Window2 <= S_Window1; if(VtcHCnt>=2&&VtcVCnt>=3)begin if((S_Window0 + S_Window1*2 + S_Window2)>(LineBuffer0[VtcHCnt-2]+LineBuffer0[VtcHCnt-1] *2 +LineBuffer0[VtcHCnt])) DOUT_reg <= ((S_Window0 + S_Window1*2 + S_Window2 -LineBuffer0[VtcHCnt-2]-LineBuffer0[VtcHCnt-1]*2 -LineBuffer0[VtcHCnt]))/4; else DOUT_reg <= (LineBuffer0[VtcHCnt-2]+LineBuffer0[VtcHCnt-1]*2 +LineBuffer0[VtcHCnt]-(S_Window0 + S_Window1*2 + S_Window2))/4; end end default: begin DOUT_reg <= DOUT_reg; LineBuffer0[VtcHCnt] <= LineBuffer0[VtcHCnt]; LineBuffer1[VtcHCnt] <= LineBuffer1[VtcHCnt]; LineBuffer2[VtcHCnt] <= LineBuffer2[VtcHCnt]; end endcase end
相关文章推荐
- Reverse Integer (数字反转)
- iOS开发之使用UIView-Positioning简化页面布局
- Python中的结构化数据分析利器-Pandas简介
- 黑马程序员--Java学习日记之网络编程
- 互斥对象 事件对象 关键代码段的比较
- 数学计算
- saltstack state.sls 与 state.highstate
- ScrollView与EditText滑动冲突解决办法
- linux命令eval的用法
- org.hibernate.LazyInitializationException could not initialize proxy-no Session的解决
- MyEclipse10注释字体变小的原因
- iOS应用架构浅谈
- Android内存泄漏分析实战
- Linux_5.2_线程互斥
- 关于对2取模的误区
- Unity编辑器 设置 Pivot模式和Center模式
- Exchange 服务器 跨森林 邮件迁移案例分享 (二)
- Objective-C 快速入门--基础(二)
- Optimal Flexible Architecture(最优灵活架构)
- 黑马程序员--Java学习日记之GUI(图形化用户界面编程)