1 系统概述
如图所示,这是整个视频采集系统的原理框图。 
 
 
上电初始,FPGA 需要通过 IIC 接口对 CMOS Sensor 进行寄存器初始化配置。这些初始化的基本参数,即初始化地址对应的初始化数据都存储在一个预先配置好的 FPGA 片内 ROM 中。在初始化配置完成后,CMOS Sensor 就能够持续输出标准 RGB 的视频数据流,FPGA 通过对其同步信号,如时钟、行频和场频进行检测,从而从数据总线上实时的采集图像数据。MT9V034 摄像头默认初始化数据就能输出正常的视频流,因此 FPGA 中实际上未作任何 IIC 初始化配置。
 
在 FPGA 内部,采集到的视频数据先通过一个 FIFO,将原本 25MHz 频率下同步的数据流转换到 50MHz 的频率下。接着将这个数据再送入写 DDR3 缓存的异步 FIFO 中,这个 FIFO 中的数据一旦达到一定数量,就会通过 AXI HP0 总线写入 DDR3 中。与此同时,AXI HP0 总线也会读取 DDR3 中缓存的图像数据,缓存到 FIFO 中,并最终送往 LCD 驱动模块进行显示。LCD 驱动模块不断的发出读图像数据的请求,并驱动液晶显示器显示视频图像。
 
本实例除了前面提到对原始图像做 DDR3 缓存和显示,还会在原始图像缓存到 DDR3 之前,会对当前图像做直方图统计(以帧为单位做统计),统计后的直方图结果做归一化处理,便于后续液晶屏显示的直方图绘制,归一化的直方图结果取值范围是 0~448,用 256 个 10bit 数据表示,存入双口 RAM 中。根据 LCD 显示模块的请求,从双口 RAM 读取实时图像的归一化直方图统计结果进行显示。最终在 VGA 液晶显示器上,可以看到左侧图像是原始的图像,右侧图像是经过归一化处理的直方图图像。
 
2 直方图统计与归一化处理
工程文件夹 at7_img_ex09\at7.srcs\sources_1\new 下的 histogram_calculation.v 模块实现了图像的直方图统计与归一化处理。该模块有一个包含 6 个状态的状态机,以这个状态机为主轴的设计思路如下:
 
1 上电初始状态 STATE_IDLE,复位结束后即进入下一状态 STATE_HIST。
 
2STATE_HIST 状态下,进行实时图像的 256 级直方图统计,统计结果存放在寄存器 histogram_cnt[255:0][19:0]中;图像接收信号 i_image_ddr3_frame_end 拉高时,切换到下一个状态 STATE_FMAX。
 
3STATE_FMAX 状态下,遍历一遍直方图统计结果寄存器 histogram_cnt[255:0][19:0],找出最大值存放在寄存器 max_histogramcnt[19:0]中;找到最大值后,切换到下一状态 STATE_CNTC。
 
4STATE_CNTC 状态下,直接转换到下一个状态 STATE_OUTP;该状态主要为了清零计数器 dlycnt。
 
5STATE_OUTP 状态下,依次将 256 个直方图统计结果乘以 448(=256+128+64),作为被除数,实际乘以 448 是通过 3 个移位结果进行累加实现。而 max_histogramcnt[19:0]则作为除数,依次输出 256 个进行除法归一化后的直方图统计结果(o_image_hc_wren 拉高时 o_image_hc_wrdb[9:0]有效)。完成后进入下一状态 STATE_WAIT。
 
6STATE_WAIT 状态下,直接切换到 STATE_IDLE。
 
在第 5 步进行的归一化处理,其基本思想是找到 256 个直方图统计结果的最大值,作为归一化的 1(其他值都小于 1);而其他结果都会以此为标准获取对应的归一化值;例如最大值若为 40000,那么归一化后为 1,某个统计结果是 1000,那么归一化后是 0.025;而实际我们需要将这个归一化后的直方图结果显示到液晶屏上,液晶屏上我们可以希望最高的直方图可以取 448pix 来显示,那么我们用 448 乘以归一化后的结果即可。
 
实际液晶屏是 720p 的驱动分辨率,最大可以给到 720pix 的高度,但是因为左侧的原始采集图像显示是 640*480,为了显示美观,我们最好给出一个不超过 480pix 的最高直方图高度显示,而取 448 其实是考虑到它等于 256+128+64,可以不消耗 FPGA 的乘法器资源,用移位累加来实现。
 
3 FPGA 与 Matlab 协同仿真验证 3.1 直方图统计与归一化结果仿真
在 at7_img_ex09\at7.srcs\sources_1\new\testbench 文件夹下,测试脚本 sim_histogram_calculation.v 用于对模块 histogram_calculation.v 进行仿真。
 
Vivado 打开 at7_img_ex09 工程,在 Sources 面板中,展开 Simulation Sources à sim_1,将 sim_histogram_calculation.v 文件设置为 top module。在 Flow Navigator 面板中,展开 Simulation,点击 Run Simulation,弹出菜单中点击 Run Behavioral Simulation 进行仿真。
 
测试脚本中,读取 at7_img_ex09\at7.sim 文件夹下的 640*480 图像数据 image_in_hex.txt(该文件由 at7_img_ex09\matlab 文件夹下的 image_txt_generation.m 产生,原始图像为 test.bmp)。一组完整的图像数据经过 histogram_calculation.v 模块处理后,产生 256 个归一化直方图结果,写入到 histogram_result.txt 文本中(仿真测试结果位于 project\at7_img_ex09\at7.sim\sim_1\behav 文件夹下)。
 
使用 at7_img_ex09\matlab 文件夹下的 draw_histogram_from_FPGA_result.m 脚本,可以同时比对 Matlab 和 FPGA 统计的直方图输出结果。由于 FPGA 统计结果是一个归一化结果,所有和 Matlab 实际统计结果的数值可能不一样,但是从比对图上看,他们的趋势和分布完全一致。 
 

 

 
3.2 图像与直方图显示结果仿真
在 at7_img_ex09\at7.srcs\sources_1\new\testbench 文件夹下,测试脚本 sim_at7.v 用于对模块 histogram_calculation.v、dual_ram_cache.v 和 lcd_driver.v 进行仿真。
 
Vivado 打开 at7_img_ex09 工程,在 Sources 面板中,展开 Simulation Sources à sim_1,将 sim_zstar.v 文件设置为 top module。在 Flow Navigator 面板中,展开 Simulation,点击 Run Simulation,弹出菜单中点击 Run Behavioral Simulation 进行仿真。
 
测试脚本中,读取 at7_img_ex09\at7.sim 文件夹下的 640*480 图像数据 image_in_hex.txt(该文件由 at7_img_ex09\matlab 文件夹下的 image_txt_generation.m 产生,原始图像为 test.bmp)。一组完整的图像数据经过 histogram_calculation.v 模块处理后,产生 256 个归一化直方图结果,缓存到 dual_ram_cache.v 模块的双口 RAM 中,lcd_driver.v 模块根据显示驱动需要,读取双口 RAM 中的数据,将直方图显示在液晶屏的右侧。测试脚本中,根据 lcd_driver.v 模块的显示驱动信号,将一帧的显示图像写入到 monitor_display_image.txt 文本中(仿真测试结果位于 project\at7_img_ex09\at7.sim\sim_1\behav 文件夹下)。
 
使用 at7_img_ex09\matlab 文件夹下的 draw_image_from_FPGA.m 脚本,可以打印 monitor_display_image.txt 文本中输出的图像。这就是最终我们的 VGA 显示器中将会显示的界面示意,左侧是原始图像,右侧是其直方图分布。可以看到,这个直方图分布情况和前面 Matlab 计算出来的也是一致的。 
 
 
4 装配说明
如图所示,这是 STAR 开发板和摄像头转接板、摄像头模块、VGA 模块的连接示意图。SF-AT7 开发板的连接位置也是一样的。
 
 
5 板级调试
本实例对应 at7_img_ex09 实例工程,做好装配连接,上电,将 at7_img_ex09\at7.runs\impl_1 文件夹下的 at7.bit 文件烧录到板子上,可以看到 VGA 显示器同时显示左右两个图像,左侧图像为原始图像,右侧图像为直方图。
 
实物效果如下图所示。