以前有篇文章,讲《让你的软件飞起来》,讲的是怎么用C语言实现RGB转YUV的方法,从浮点乘法到定点乘法,最后再到查找表等方法进行加速,整体提升了几百倍的提升。
那么FPGA进行图像加速也有异曲同工之笔。由于FPGA的数字电路结构,没有CPU线程的概念,更没有浮点的概念,那么直观的想,我想可以通过以下几个方面进行运算的加速:
1)面积换速度:也就是串转并运算,可以多个模块同时计算;
2)时间换空间:时序收敛下通过频率提高性能,虽然面积可能稍微加大点;
3)流水线操作:让整个“生产线”全速运行,等同于n倍线程效率;
4)乒乓操作:等同关于2个模块的并行运算,读写互不冲突;
5)浮点转定点:采用乘法 移位的方式转换;
6)查找表换计算:采用查找表替代某些有限固定值的运算;
7)等等各种别的技巧。
整体的思路和《让你的软件飞起来》有点相似,那就是不要用浮点,能用查找表的不要计算,能并行(多线程)的不要单线程,当然Pipeline CPU做不到。我们在使用FPGA进行加速时候,讲的是硬件加速,那么要充分发挥硬件的性能,就需要充分使用这些技巧,于是乎用FPGA实现并不是最难的,最难得是如何设计FPGA硬件架构(实现只是个翻译而已)。有一本我也没啃破的书《Computer Architecture》,如果你能沉得下心,建议去看看英文版。
所谓硬件架构,就是如何用最优的方式去实现,在理论基础和经验的前提下,结合FPGA本身的固有特性,设计出基于FPGA的实现方案,这本身思维非常重要,因为是和硬件强相关的。拿Sobel边缘检测来说事,首先罗列一下工作量,我们需要完成如下功能:
1)CMOS摄像头的驱动与数据的采集(灰度相机直接跳(4))
2)可选的Bayer转RGB(ISP领域叫做Demosaic,但这个内容太多此处不展开,本教程制作简单的Bayer转RGB)
3)可选的RGB转YUV并提取灰度图像流
4)进行必要的中值滤波进行噪声的去除以提升质量
5)进行3*3 Sobel边缘检测算法,同时计算H与V方向的梯度,得到结果
6)进行必要的腐蚀/膨胀运算
7)SDR/DDR外部存储介质的图像的乒乓缓存
8)HDMI/VGA接口显示器的实时显示驱动
9)必要的一些控制单元,包括复位、Sobel阈值、LED指示灯等等
完成以上功能,如果采用CPU实现,需要进行多次内存读写进行每一个模块的计算,并且每一个模块也只能按从前到后点顺序进行,不能Pipeline运算,这使得内存和计算非常耗时。简单的画了一下实现的框图,如下所示,感觉徘徊的好累好心塞。
但如果采用FPGA实现,就不一样了,首先前面模块计算完几行的值,后面的模块就可以紧接着进行计算,那么流水线可以High起来;其次前面讲到的浮点转定点,乒乓操作,面积换速度等等思维可以全部用上;最后数据只进一次内存,读写乒乓后就显示器实时显示。采用FPGA实现的框图,分别如下所示:
需要注意的是,要实时显示就得缓存,因为摄像头的时序并不一定或者一般都一定不会和显示器匹配,这就是我们所谓的“显卡”。我曾经用FPGA做了一个显卡,让小朋友们可以用51单片机驱动VGA显示。
使用FPGA就是要充分利用电路的优势,在资源足够的情况下尽可能的流水线或者并行运算,最后达到实时处理的效果。曾经有一个哥们说他用DSP做了640*480 3次滤波就卡的只有15FPS了(估计没优化),但让我用FPGA完成上面所有的图像处理,做到300FPS也是轻而易举的事情,这就是FPGA的优势。至于具体的实现,在上图框架定下来的前提下,剩下的就是具体的实现以及翻译工作了。本教程全文都是在讲解如何实现每一个模块,以及最终流水线完成实时图像处理的功能。
,