随着科学技术的高速发展,FPGA在系统结构上为数字图像处理带来了新的契机。图像中的信息并行存在,因此可以并行对其施以相同的操作,使得图像处理的速度大大提高,这正好适合映射到FPGA架构中用硬件算法得以实现。
本篇阐述了基于FPGA设计一个能够实时采集、实时处理并实时显示的数字图像处理系统的设计思想和流程,分析了摄像头接口的时序;阐述了图像信息的捕获原理;详细介绍了图像边缘检测部分各模块的功能;重点介绍了具有去噪功能的中值滤波模块的设计;简单描述了边缘检测算子的选用;系统的介绍了SDRAM的工作原理以及控制方式;介绍了VGA时序;最后针对整个系统做了验证和总结,包括仿真波形的验证以及板级验证。
该系统基于实体FPGA开发板实现了图像数据的实时采集、实时边缘检测和实时显示,运行稳定,实时性能较高,从而也表明FPGA确实具有海量数据高速传输的能力。
本篇为本人当年的毕业设计部分整理,各位大侠可依据自己的需要进行阅读,参考学习。
第三篇内容摘要:本篇会介绍系统验证、结论以及各个模块主要代码,包括图像实时采集模块的主要代码,图像实时捕获模块的主要代码,中值滤波模块的主要代码,边缘检测模块的主要代码,图像缓存模块的主要代码,图像实时显示模块的主要代码等相关内容。
五、系统验证
在本系统设计过程中,我以自顶向下的层次化设计思想为主进行系统的顶层架构设计,明确各模块的功能以及各模块之间的握手关系,之后分模块编写代码并加以验证,调试代码使得各模块功能得以实现,最后基于顶层模块进行仿真验证,如图5-1和5-2为系统顶层模块的仿真波形,其中图5-1为全局波形,图5-2为局部放大的波形。
图5-1 系统顶层模块的全局仿真波形
图5-2 系统顶层模块的局部仿真波形
随后连接FPGA开发实验板并更新其驱动程序,按照开发板的配置文件分配引脚,全编译通过后下板进行板级测试。本系统验证时所采用的开发板是实体FPGA开发板。
实体FPGA开发板采用的是Altera Cyclone IV代系列的EP4CE10E22C8N芯片。该开发板是一款FPGA图像开发板,其核心芯片EP4CE10E22C8N拥有6272个逻辑单元和150个IO引脚,开发板上配置有VGA、USB、CMOS接口、SDRAM、按键、LED等很多种外部设备,可以作为本系统设计验证的硬件工具。
实体FPGA开发板的主要参数如下表6-1所示。
表5-1 FPGA开发板的主要参数
下板结果表明我所设计的数字图像边缘检测系统的功能已经实现,能够实时采集图像、实时处理并实时显示,这里截取的是图片,现实场景显示可以根据摄像头的移动实时显示。
六、结论
本系统设计中,我基于FPGA驱动的主要设备如下:型号为Ov7725的摄像头;具有通用性的VGA接口。同时,我研究了相关的边缘检测算法,为了数据处理结果更加准确,我还根据系统需要进行了图像数据的预处理操作:先将彩色图像转换成为灰度文件;接着采用中值滤波技术对采集到的图像数据进行了有效去噪。通过本系统的设计,我深刻理解了基于FPGA驱动外部设备的基本原理,掌握了基于FPGA、运用Verilog语言驱动外部设备和实现算法的能力,感受到了FPGA的先进,也进一步确定了自己的发展方向。在进行系统验证时,基于FPGA开发板实现了图像数据的实时采集、实时边缘检测和实时显示,系统性能良好,实时性能较高,结果证明FPGA能够轻松实现海量数据的高速传输。
附:部分主要代码
图像实时采集模块的主要代码:
1 module sccb_config_ctrl(
2 clk, //24Mhz输入时钟
3 rst_n, //系统复位
4 scl, //iic的时钟线
5 sda, //iic的数据线
6 config_done //配置完成标志
7 );
8 //系统输入
9 input clk; //外部输入时钟24Mhz
10 input rst_n; //系统复位
11 //系统输出
12 output reg scl; //iic的时钟线
13 output reg config_done; //配置完成标志
14
15
16 inout sda; //iic的数据线
17
18 reg sda_buffer; //写入数据的中间寄存器
19 reg flag; //控制系统是否占有总线控制权
20 reg [7:0] lut_cnt; //指针寄存器计数器
21 reg [15:0] lut_data; //寄存器地址和配置数据
22 reg [3:0] s;
23
24 assign sda = (flag) ? sda_buffer : 1'bz;//当flag为高电平时,系统拥有总线控制权
25 //并发送sda_buffer中的数据。当flag为低电平时,
26 //释放总线。
27
28 //----------延时1ms计数器-----------------
29 reg [31:0] delay_cnt;
30 reg delay_done;
31
32 always @ (posedge clk or negedge rst_n)
33 begin
34 if(!rst_n)
35 begin
36 delay_done <= 0;
37 delay_cnt <= 0;
38 end
39 else if(delay_cnt == 20000) //23809
40 delay_done <= 1;
41 else
42 begin
43 delay_cnt <= delay_cnt + 1;
44 delay_done <= 0;
45 end
46 end
47
48 //----------------分频产生400Khz时钟clk_sys----------
49 reg [7:0] count;//计数器
50 reg clk_sys;//系统时钟
51 reg [5:0] state;//状态寄存器
52
53 always @ (posedge clk or negedge rst_n)
54 begin
55 if (!rst_n)
56 begin
57 clk_sys <= 1'b1;
58 count <= 8'd0;
59 end
60 else
61 if (count < 100)//分频成为近200K的时钟
62 count <= count + 1;
63 else
64 begin
65 count <= 8'd0;
66 clk_sys <= ~clk_sys;
67 end
68 end
69
70 //------------------输出scl-------------
71 always @ (negedge clk_sys or negedge rst_n)
72 begin
73 if (!rst_n)
74 begin
75 scl <= 1'b1;//复位时,scl为高
76 end
77 else
78 begin
79 if(config_done == 1 || delay_done == 0)//当总线忙的时候,scl为近400K的时钟
80 scl <= 1;
81 else
82 scl <= ~scl;//空闲时,scl为高
83 end
84 end
85
86 reg [3:0] cnt;//发送或者接收数据的个数
87 reg [15:0] memory;//发送或者接受数据的中间寄存器
88
89 always @ (posedge clk_sys or negedge rst_n)
90 begin
91 if (!rst_n)
92 begin
93 config_done <= 0;
94 flag <= 1'b1; //复位时,系统获得总线的控制权
95 sda_buffer <= 1'b1; //向iic的数据线上发送高电平
96 state <= 0;
97 cnt <= 0;
98 memory <= 16'd0;
99 lut_cnt <= 2;
100 s <= 0;
101 end
102 else
103 case(state)
104 0 :if(scl)
105 begin
106 if(delay_done)//延时标志信号拉高
107 begin
108 sda_buffer <= 1'b0; //发送启动信号
109 state <= 1;
110 memory <= 16'h0042;//准备ID地址
111 end
112 else
113 state <= 0;
114 end
115 else
116 state <= 0;
117
118 1 :if((scl == 0) && (cnt < 8))//发送ID地址
119 begin
120 sda_buffer <= memory[7];
121 cnt <= cnt + 1;
122 memory = {memory[14:0],memory[15]};
123 state <= 1;
124 end
125 else
126 begin
127 if ((scl == 0) && (cnt == 8))
128 begin
129 cnt <= 0;
130 flag <= 0;//释放总线控制权
131 state <= 2;
132 end
133 else
134 begin
135 state <= 1;
136 end
137 end
138
139 2 :
140 if(scl)//在SCL高电平期间接收数据
141 begin
142 if(!sda)//检测应答信号
143 begin
144 state <= 3;
145 memory <= lut_data;//指针寄存器地址
146 end
147 else
148 begin
149 state <= 0;
150 end
151 end
152 else
153 state <= 2;
154
155 3 : if((scl == 0) && (cnt < 8)) //发送指针寄存器地址
156 begin
157 flag <= 1;//获得总线控制权
158 sda_buffer <= memory[15];
159 cnt <= cnt + 1;
160 memory = {memory[14:0],memory[15]};
161 state <= 3;
162 end
163 else
164 begin
165 if ((scl == 0) && (cnt == 8))
166 begin
167 cnt <= 0;
168 flag <= 0;//释放总线控制权
169 state &