欢迎大家多提宝贵意见,如果对大家有所帮助,不胜荣幸:)
视频算法的FPGA原型验证(一)
上一篇 /
下一篇 2008-05-05 13:56:19
/ 个人分类:工作小结
这篇将要总结一下一种比较简单的视频scale算法--------cubic6在FPGA里实现情况。主要包括模块划分,算法简化,代码实现的一点技巧和测试仿真等。
图像缩放在各种图像处理应用领域中,发挥着极其重要的作用。图像的分辨率调整和格式变换等,都需要用到图像缩放技术。综合考虑硬件实现与插值效果,对于分辨率较高的视频图像格式转换(如计算机显示中的VESA标准的视频图像),我们拟采用6点三次插值(简称为Cubic 6点)方法实现任意倍数缩放。
本模块拟采用cubic6点插值把800*600和1024*768两种格式的视频图像统一放大到17寸液晶显示器物理尺寸1280*1024,并通过17寸液晶显示器显示,分析缩放前后,和不同缩放尺寸,以及和显示器自带scale交叉比较。验证算法的性能。
根据cubic原理,对于水平和竖直两个方向的视频信号,我们采取分别放大的方式进行处理。两个方向的缩放模块在逻辑实现上会有所不同。后面的章节中会详细讲到。
单对算法实现来讲,只有水平缩放cubic6_1280和竖直缩放cubic6_1024两大模块。而对于整个系统而言,还包括输入视频格式识别模块mode_delect,有效数据捕捉模块variable_capture_window,FPGA外部存储器控制模块DDR_controler, 时钟信号产生模块,包括输出点频产生模块DCM,内部处理系统时钟产生模块clk100_130等(可参见6.5.1顶层模块功能框图)。
理论研究:
在图像插值的过程中,双线性插值的平滑作用可能会使图像的细节产生退化,尤其在放大倍数较大的情况下,这种现象更为明显。同时,双线性插值的斜率不连续会产生不希望的结果。这种情况都可以通过高阶插值得到修正,三次多项式插值即是一种高阶插值方法。
由于三次多项式具有二阶连续性,因此它常被用于实现多段曲线的光滑连接。许多逼近函数都是由三次多项式分段构造而来,例如B样条逼近函数,拉格朗日插值函数等。
1、四点插值
用四个像素点进行三次插值时,有八个系数需要确定,根据边界约束条件确定法可以把八个待定系数化简为仅与一个自由度a有关的插值函数式,如式(1)

(1)
参数a可以根据不同的要求确定。例如当要求插值模板从0到1区间必须为正,从1到2的区间必须为负,那么可以推出一种插值模板。
Keys通过将sinc离散函数进行泰勒级数展开后,使三次分段多项式和原始信号的泰勒级数展开式尽可能多项吻合,以此推导出a=-1/2。采用这个参数时,输入信号的泰勒级数展开式和内插函数的前三项都相同。分析此时插值函数的频域特性可知,此时的四点三次插值模板在通带内不存在过冲,在截止频率以内的频谱平坦,两个旁瓣的最大幅值都低于1%。

2.六点插值
一般而言,插值模板大小N的增加会提高重采样后的图像质量。而根据上面定义的边界条件可以知道大小为N的插值模板有2N个变量需要确定。所以,当N=6时,依据相关的边界条件,可以求得6点三次插值方法的滤波器系数确定方程如式(2)所示。
(2)

Cubic6点插值示意图如图3所示,将插值点与邻近6点的对应位置代入式(2)所示Cubic6滤波器方程,算出原始象素t1~t6所对应的滤波器系数r1~r6,注意这里的r1 + r2 + r3 + r4 + r5 + r6 ==1,因此相当于已经做了归一化处理。
(3)
把6个系数代入相应的Cubic6滤波器公式中,然后分别和t1~t6相乘,然后将这6个值相加,就是最后输出的插值结果。
(4)
3.Cubic6点插值算法的近似形式
从硬件实现角度考虑,如果采用Cubic6点精确插值算法放大,插值点在原始图像中两点之间的位置可能是任意的,这样势必需要一个乘法器一直来算这个位置,计算量很大。如果把插值点位于原始图像中两点之间的位置固定在0,1/8, 2/8 , 3/8 , 4/8, 5/8, 6/8, 7/8 8个位置(即当实际位置不在这8个点上时,也把它移到这8个点上),那么滤波系数就是8组固定值。只需要一个大小为6×8的LUT就可以存储了。实际插值时,根据插值点的实际位置调用查找表中的对应系数,通过简单的乘加运算就可以完成缩放。Cubic6点插值的硬件实现得到大幅度简化。
当然也可以考虑量化为16个点或32个点以提高精度,但实验证实8点精度已经可以得到良好的效果了。
确定x所处的区间之后,选择对应的滤波器参数,代入式(6):
(6)
为方便理解,以下举例说明。当插值点与原始图像点的对应距离大于6/8,小于7/8时,读取预先计算好的x=6/8的滤波系数,完成Cubic6滤波。

预先把x=6/8代入Cubic6滤波器公式,计算出当x=6/8时的滤波参数,并求出插值点:
(7)
4.插值象素点与原象素点位置关系的确定
要完成Cubic6算法插值,需要确定滤波系数以及与插值点邻近的6个像素点亮度值。滤波系数的确定是根据插值点与其近邻的6个原始像素点的距离,从8组滤波系数中选出某一组作为最后的滤波系数。
判断垂直方向上插值象素点与原象素点之间的位置关系与水平方向的做法类似,下面仅就水平方向位置关系的判断及其实现方法做分析说明。假设水平方向的放大倍数为k,则第一个插值点距离第一个原始象素点的距离为1/k,且按行方向扫描,前进步长也为1/k。如图5,行方向的第n个插值点的横坐标是n/k。n/k值的整数部分代表离该插值点最近的左原象素点横坐标,小数部分表示离最近的原象素点的距离。

若an为第n个插值点的横坐标值,则an=n/k=n×an。当插值不是逐点进行时,即n值并非步进1时,求取an的过程可以通过移位、相加来简化。对于任意的an都可以通过移位、相加得到:首先把n写为二进制数u,若u的第i位上数值为1,则将a1左移i位作为最后求和的加数之一。写为公式:
将an连续累加,累加值为C[20:0],通过分析可以知道,累加值C的高11位C[20:10]可以作为读输入数据buffer的读地址rd_addr[10:0],累加值C的低10位C[9:0]则为Cubic6点插值算法中提到的x值。得到x值后可以用图6的结构查找到相应的系数,进而计算得到水平方向的Cubic6插值输出。
得到x值后,通过查找表得到相应的六个系数值,将C[9:0](即为x×1024)分别与八个常数比较,得出的结果用于查找相应的滤波系数。
下面介绍该算法在FPGA中的实现:
cubic_6模块接口描述:


对于水平和竖直两个方向的视频信号分别放大,两个方向的缩放模块在逻辑实现上会有所不同。如下图所示,cubic6_1280是对视频图像进行水平方向的放大,cubic6_1024是对进行过水平放大之后的图像再进一步竖直放大。

cubic_6水平放大模块:


cubic_6竖直放大模块接口描述:


由于篇幅限制,在下一级的子模块就不再描述了,这里总结一下当初做时收获的一点经验:
本节对以上设计工作过程中出现的问题作一下总结,包括最终解决方案和在寻找问题但按过程中的经验教训。
工作中收获的相关经验:
1) 在功能仿真做完后,由于我们做的是FPGA的设计,在设计时已经基本保证RTL级代码的综合结果和功能仿真结果的一致性,只要综合布局布线后的静态时序报告没有违反时序约束的警告,就可以下到板子上去调试了。事实上,在华为中兴,他们做FPGA的设计时也是不做时序仿真的,因为做时序仿真很花时间,且效果也不见得比看静态时序分析报告好。当然后防还是有它的作用的,当从报告上发现不了问题,而问题又确实存在的情况下,后仿真还是有必要的。这取决于设计者的设计能力。这里注意,我们以前用了很多时间去做后仿真,浪费精力了,以后要吸取教训。另外要更深入的学学怎么看静态时序分析报告了。
后记:个人感觉后仿还是必要的,尤其是在高频情况下。
2) 一个模块尽量只用一个时钟,这里的一个模块是指一个module。在多时钟域的设计中涉及到跨时钟域的设计中最好有专门一个模块做时钟域的隔离。这样做可以让综合器综合出更优的结果,同时避免很多不稳定的情况发生。
后记:多时钟问题确实在设计中要格外关注。除上述方法之外,可用打两拍方式的方式把一个时钟域中的数据传递给另一个时钟域。还要注意是从高频到低频还是从低频到高频。
3) 代码完成后,功能仿真,一切正常。后仿真时却很多波形出错。这时候不应该考虑从约束和手动布局布线入手解决问题。多数情况下要从代码入手进行修改。最初阶段一些代码写得过于理想化,后仿真时发现很难满足时序要求。以后需要提高些代码的质量。举例说明,设计之初只考虑到800*600格式的放大,当加入1024*768格式放大之后,处理模块系统时钟从120提高到130,发现水平放大部分产生的读始能信号非常不稳定,有毛刺。从而引起后续信号wr1280en和lineselecte都出错。又引起1024放大模块内其它信号问题,导致最终显示效果极差。这就是当初设计考虑不周造成的,当把该信号的生成重新修改之后,目前完全满足两种格式放大的要求,还可以适应更高频率时钟下工作。
4) 显示器上效果还显示竖直方向总又细细的有规律的噪声线恒产整个屏幕,再带马上反复检查和修改均得不到解决的情况下,回头分析参考资料,发现由滤波系数判断参加运算的参数时,用了filter的10bit数据进行判断,可能是十位判断过于精确,本应选择A组系数的时候,只因为最低位比判断条件大1,就会选择成B组的系数,当把十位判断改为高三位判断时,问题解决。而为什么水平放大模块同样是filter的10bit为进行比较就不会出错,经过分析发现,说平方向虽然也是十位参与比较,但他的放大倍数刚好为1.6倍,涉及到的只是高三位数据,也就是只有高三位在变化,低七位前敲没有参与比较。所以理论上的百密一疏。在实践过程中导致图像有规律的选错系数。类似问题也出现在前期的实验中,显示图像有均匀矩形线条的噪声,初步判断为系统噪声,可能是设计是逻辑错误,也可能是理论上的问题,最终严格检查逻辑之后排除该方面原因。结果确实是所参考的论文中系数出现笔误导致的。修正后问题解决。看来尽信书不如无书。从中吸取教训,以后再遇到问题时,不能一味的在逻辑实现上找错,要从现象的噪声类型上分析是理论造成的还是时序上不符合造成的。
5) 当做完两种格式视频自识别发达时,发现1024*768的放大已经很好了,但是800*600格式的放大效果还不稳定,同样的代码,不同的效果,唯一不同的是几个参数的设置上不同。经过漫长的反复实验性修改参数,发现都不能解决问题。开始怀疑是图像处理模块之外的问题,最终发现问题出在自动识别格式模块,产生vdisp_counter的方式非常不稳定,导致显示最终的出错。该模块式另一个人设计的。接个问题给我的教训是让我深刻体会到了团队合作的重要性,同一个工程中模块设计者不同,一定要仔细确定各自模块的正确性,做好接口部分信号功能的详细说明。
6) 虽然都是些工作笔记,整理完贴上来还是蛮辛苦的,本来还打算写(二)的,想想算了,有做这方面的朋友感兴趣的话,直接联系我好了:)
导入论坛
收藏
分享给好友
推荐到圈子
管理
举报
TAG: