概述
目前实时图像处理的硬件主要是 FPGA、GPU 和 DSP 三类。从笔者的开发经验来看,FPGA 以其实时性和灵活性占据主流;GPU 虽然不及DSP应用广泛,但是随着开发技术逐步升级和性能逐步提升,以及 DSP 技术自身的没落(个人观点,不讨论),GPU 在某些特定场景下可能是更优于 FPGA 的首选。
本系列文章主要说明基于 Xilinx FPGA 的实时图像处理。虽然 FPGA 开发用的 HDL 语言与 Intel FPGA(前身 Altera)通用,但是比较开发工具软件差异的话,还是 Xilinx 开发效率更高。
相关程序的开发软件环境为:
- Vivado 2018.2.1 System Edition
- Matlab 2017b
算法中的计算部分主要使用 Vivado 中的 System Generator 工具软件(下文简称sysgen),其具体使用方法见Xilinx官方文档:UG897 和 UG958。
sysgen 的开发基于 Matlab 的 Simulink 环境,使用 Xilinx 提供的功能模块在图形化界面进行 FPGA 开发,从原理上来说是使用图像化的功能模块来模拟 HDL 语言的功能。
Xilinx 的原文说的是 Model Based DSP Design,虽然主要应用于 DSP(数字信号处理),不是ISP(Image Signal Processing),但是数字图像也是数字信号的一种,计算方法和原理差异不大。
使用 sysgen 的好处在于直观的图形开发环境以及与 Matlab 环境的完美融合,在仿真激励的生成和仿真结果分析时可以直接使用 Matlab 强大的数学计算库。相比较传统的基于 HDL 的仿真使用数据文件进行数据导入导出后才能进行仿真处理,sysgen 可以将这部分过程直接融入仿真流程,大幅减少了仿真的工作量。但是 sysgen 相比较灵活的 HDL 语言,也有一个比较大的劣势在于很难实现复杂的 FPGA 逻辑(比如状态机)。
除了 sysgen 以外,Xilinx 还有许多基于高级语言(c 语言,相较于 HDL 语言)的新的开发工具软件,如 HLS、SDSoc 等,笔者接触不多(无实际项目经验),但是直觉上认为这些软件只是用于降低 FPGA 的入门难度,提升开发效率,却在运行效率上做出了较大的妥协。随着编译器(或者综合工具)技术的提升,未来一定会成为 FPGA 开发的主流,但是现阶段还是有限使用为好。
本系列文章主要分为3个部分,首先说明了基本设计原则,包括代码、端口定义和数据缓冲等;之后是的主要内容,包括常用功能模块和常用算法模块。
注意:全部文章内容源于笔者自身的设计经验,并非“标准答案”,也许有更好的设计方法,欢迎各位朋友讨论。
基本设计原则
Verilog + sysgen
本系列全部设计使用 Verilog 语言,每个算法模块都以 Verilog 语言模块包含 sysgen IP 的方式构成。
根据 Verilog 和 sysgen 各自的开发优势,由 Verilog 负责复杂的逻辑处理(数据缓冲、状态机、参数更新等),由 sysgen 负责数值计算。
图像数据流水线格式
所有的图像处理算法按顺序串联成流水线依次执行,流水线上的图像数据使用统一的格式。
//输入图像数据 input [7:0] in_pix;//输入像素值,如果单通道灰度则只有1个端口in_gray,如果3通道RGB,则有3个并行端口in_r/in_g/in_b;数据位宽根据实际情况设置 input in_fv;//输入高电平有效帧同步,表示in_pix在1帧图像内的范围;上升沿与1帧内首个lv上升沿对齐,下降沿与1帧内最后1个lv下降沿对齐;2帧之间fv至少有1个时钟周期的低电平 input in_lv;//输入高电平有效行同步,表示in_pix在1行图像数据内的范围;2行之间lv至少有1个时钟周期的低电平 input [15:0] in_x;//输入列坐标,如果列数目为COLS,则数值范围0~(COLS-1);为保证通用性,数据位宽固定为16位;在fv与lv同时有效时数值有效,不考虑非有效情况下的坐标值 input [15:0] in_y;//输入行坐标,如果行数目为ROWS,则数值范围0~(ROWS-1);为保证通用性,数据位宽固定为16位;在fv与lv同时有效时数值有效,不考虑非有效情况下的坐标值 //输出图像数据 output [7:0] out_pix; output out_fv; output out_lv; output [15:0] out_x; output [15:0] out_y;
参数更新流程
如果对于单帧图像数据精确性要求不高,在不会导致进出算法模块数据流错误的情况下(即不影响上下游算法模块),算法模块可以从模块端口直接取用参数。
但是如果对于单帧图像数据精确性较高要求,则参数更新流程应当保证在一帧图像计算过程中参数值固定不变。
典型的算法模块参数端口定义如下:
input param_valid;//高有效参数有效标记,在外部模块或者外围设备更新参数开始之前,将valid信号置为低电平无效,所有参数更新完成后将valid信号回复高电平有效 input param_en;//高有效算法使能,在算法非使能情况下,将输入图像数据直接送出至输出端口;在非使能情况下,是否与使能情况下保持一致的数据延迟根据项目需求而定 input [7:0] param_a;//根据算法原理定义的1个或者多个算法参数;如果有浮点数参数,在Verilog中不作特殊处理,而是参数进入sysgen后将其定义为浮点数 input [31:0] param_b;
外部模块或者外围设备更新参数的流程:
① valid 信号置为低电平;
② 更新全部参数值;
③ valid 信号置为高电平,表示参数有效。
算法模块内,对包括算法使能参数在内的全部算法参数定义对应的参数寄存器,算法模块使用参数寄存器中的参数值,而不是模块端口的参数值。在**输入 fv(in_fv)的下降沿(不是输出fv)**处检查 valid 信号是否有效:如果为高电平有效,则将当前模块端口的参数值写入参数寄存器;如果为低电平无效,则保持当前参数寄存器值。
注意:valid 信号即可以针对当前项目中所有的算法参数,也可以为每个算法单独定义 valid 信号。但是每个算法独立的 valid 信号没有必要,因为在单独更新某一个算法的参数过程中,如果其它算法模块发现 valid 无效依然会保持其原有的参数寄存器值,不受参数更新影响,在参数更新完成后,也只有指定的算法模块参数被新参数替换。
片外缓冲设计
许多图像处理算法或者输入输出逻辑都需要进行数据缓冲,如果 FPGA 片上 RAM 资源足够,使用 RAM 缓冲数据当然是最理想的情况,但是大多数情况需要缓冲的数据量实在太大。
因此片外 DDR 数据缓冲基本上是 FPGA 图像处理的标配。
这种情况下 DDR 缓冲的数据读写,及其与算法或者输入输出流程的匹配将是除图像算法以外最复杂的逻辑设计。
DDR 缓冲逻辑为了保证读写效率,必须与算法及数据流深度耦合,因此几乎没有太大的通用性考量,但是所有的片外缓冲设计必须包含数据流反压,数据流下游模块在处理不及时的情况下必须要求上游模块暂停数据下传,否则将造成数据丢失,甚至破坏整个图像处理的数据流水线。
版权声明:本文为CSDN博主「bt_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/botao_li/article/details/100520386