参考文献:手把手教你学FPGA设计:基于大道至简的至简设计法 基于VIP_Board Big的FPGA入门进阶及图像处理算法开发教程-V3.0 整个系列文章如下:
这部分内容,请移步: 基于FPGA的图像边缘检测系统(一)-原理
如上图所示,设置 CMOS 摄像头的各种模式,主要模式如下所示:
一般我们采用 RGB565 模式, YUV 模式会在后面解说;使用内部 LDO比外部更加稳定, FPGA 速度够快,因此 PCLK 都不用经过任何分频,直接输出,挑战 OV 的极限。
计算算 PCLK 的参数,如下所示:
VSYNC: 510* Line = 3*tLine + 15*tLine +480*tLine
HREF: 784*tP = 640*tP + 144*tP
HSYNC: 784*tP = 80*tP + 45*tP + 640*tP + 19*tP
VGA RGB565, YUV 30fps:
PCLK = 784 * 510 * 30 * 2(byte) = 23990400 = 24MHz
因此手册才推介 24MHz 的 XCLK 输入。 简单的说 CMOS 图像的时序跟 VGA 时序非常雷同, 只不过 VGA 时序使我们主动产生的, 而 CMOS 时序是我们被动接受的。 这需要我们根据固定的协议,时序,来准确接受每一个像素的数据。 以下是 RGB565 下的 OV 摄像头的图像时序图, PCLK 是连续的(这根 Micron的摄像头一样),每一行有行有效信号,每一场有场有效信号,在场有效信号开始, 第一个行有效信号的第一个数据便是第一个像素的高八位数据。 每一个像素要分两次送。
在 SignalTap 中也调试过,可以清晰的看得到,数据流的规则, PCLK 上升呀对准的是每个数据的稳定期(当然 PCLK 的边沿可以在寄存器中调节),因此可以将 PCLK 作为整个时序逻辑的驱动时钟,直接作为 DFF 的使能时钟。
如下是将 OV7670 输出设置为移位 1 模式,可从 SignalTap 中看出,这些时序对于前期的调试,认知有很大的帮助,至少心里有了底
如果你用 STM32 玩过不带 FIFO 的 OV7670 ,你肯定知道 STM32 的能力,能在 80 接口的 LCD 显示, 坦白说是作弊了。 首先你们用 MCU 初始化 OV7670,同时初始化 LCD 为 8Bit 模式,然后,直接将 OV7670 RGB565 的数据输出给LCD, LCD 内部经过捕获, 叠加, 直接输出视频。 整个数据流没有经过单片机,这不属于你,可望而不可及。当然, 就算你用了带 FIFO 的摄像头, 可以通过关断来读取整幅图像, 但是效率和速度就大大打折扣了,而且你休想实现 VGA。
在场信号(默认低有效),和行信号有效的同时,开始捕获数据;寄存第一个数据, 拼接到第二个数据, 实现一个完整像素的输出。 同时在第二个数据有效的同时,输出一个使能信号给 FIFO,作为 SDRAM 的异步缓存。当然,场有效信号,作为 SDRAM 的地址清零信号。真的有那么简单吗? 答案是是的,因为 FPGA 太强大了。 当然这部分中的数据拼接,也可以通过 FIFO 实现,异步 FIFO 有字节拼接功能, 刻意按照您的设置拼接数据, 如下图所示:
OV 明确指出, 在配置完寄存器之后, 保守估计, 前 10 帧图像将会不稳定,介意舍弃。为此必须舍弃这 10 帧的数据,以保证后续图像处理的可靠(直接视频显示当然没关系,假设你看不到,当然我为了严谨,还是设计上了),如下:
因此在 CMOS_Cpture 中,刻意设置了 Frame 的就算,以至丢弃前 10 帧的数据,如下:
看下面一下图像, 你会发现图像偏移了, 尽管我已经做了时序约束。
当然也不是杜邦线的问题, 因为我是直插的。 这部分当时猜想是因为 PCLK并不是全局时钟, 由于电路, 布局布线上的不严谨, 导致了时序的便宜, 尽管布线已经 OK 了。猜想如果 PCLK 设置成全局时钟输入,那将会解决问题。 最后,自行设计了电路,直接将 PCLK 输入到全局时钟,图像如此的稳定,不再出现任何偏移,抖动等 bug,非常低 perfpect。
当然,这也不是唯一的解决方案,你完全可以用一个较高的时钟,去采样PCLK 的上升沿, 用边沿检测技术, 来捕获使能, 有效读取数据, 这个, 有待升级吧,反正现在 perfect 了。
对于彩色转灰度,有一个著名的色彩心理学公式为
上式是浮点运算,对于FPGA会浪费较多资源,所以需要整数算法。 系数都是3位精度,我们可以将他们缩放1000倍来实现整数算法,调整后为:
RGB一般是8位精度,现在缩放1000倍,所以上面的额运算是32位整型的运算。注意,后面那个除法是整数除法,所以需要加上500来实现四舍五入。
上面的整数算法相对而言,已经很快了,但是有一点仍然制约速度,就是最后的那个除法。移位比除法快很多,所以可以将系数缩放成2的整数幂。比如,使用16位精度,2的16次方位65536,这样计算系数为:
此处所使用的舍入方式不是四舍五入。四舍五入会有较大的误差,应该将以前的计算结果的误差一起计算进去,舍入方式是去尾法。写成表达式为
以下是2~16位精度的系数:
仔细观察上面的表格,某些精度实际上是一样的:3与4、7与8、10与11、13与14。其中2位精度的系数非常有意思,完全可以移位优化:
由于误差很大,所以做图像处理绝不用该公式(最常用的是16位精度)。但对于游戏编程,场景经常变换,用户一般不可能观察到颜色的细微差别,所以最常用的是2位精度。 而本次设计采用的计算公式是使用8位精度:
消除图像中的噪声成分称为图像的平滑化或滤波操作。信号或图像的能量大部分集中在幅度谱的低频段和中频段,而在较高频段,感兴趣的信息经常被噪声淹没。因此,一个能降低高频成分幅度的滤波器就能够减弱噪声的影响。 滤波的目的有两个:一是抽出对象的特征作为图像识别的特征模式;另一个是为满足图像处理的要求,消除图像数字化时所混入的噪声。 对滤波处理的要求有两条:一是不能损坏图像的轮廓及边缘等重要信息;二是使图像清晰视觉效果好。 图像的滤波方法很多,主要可以分为频率域法和空间域法两大类。频率域法的处理实在图像的某种变换域内,对图像的变换系数值进行运算,然后通过逆变换获得增强图像。这是一种间接的图像滤波方法。空间滤波方法是一类直接的滤波方法,他在处理图像时直接对图像灰度作运算。 频率域滤波是将图像从空间域或时间域转换到频率域,再利用变换系数反应某些图像特征的性质进行图像滤波的方法。傅里叶变换是一种常用的变换。在傅里叶变换域,频谱的直流分量正比于图像的平均亮度,噪声对应于频率较高的区域,图像实体位于频率较低的区域。图像在变换时所具有的这些内在特性可用于图像滤波。可以构造一个低通滤波器,使低频分量顺利通过而有效地阻止高频分量,即可滤除图像的噪声,在经过反变换来取得平滑的图像。 低通的数学表达式如下式:
低通滤波滤除高频成分,而低频信息基本无损地通过。经滤波后,经傅里叶变换反变换可得平滑图像,选择适当的传递函数H(u,v),与频率域低通滤波的效果关系很大。常用的传递函数有梯形函数、指数函数、巴特沃斯函数等。这些传递函数,都能在图像内有噪声干扰成分时起到改善的作用。 常用的平面空间域滤波法有两类:一类是拟合图像的方法,包括n阶多项式拟合、离散正交多项式拟合、二次曲面拟合等多种方法;另一类是平滑图像的方法,包括领域平局法、中值滤波法、梯度倒数加权法、选择式掩膜法等。 高斯滤波器是平滑线性滤波器的一种,线性滤波器很适合于去除高斯噪声。而非线性滤波则很适合用于去除脉冲噪声,中值滤波就是非线性滤波的一种。平滑滤波器就是用滤波掩膜确定的邻域内像素的平均灰度值去替代图像的每个像素点的值,这很容易用硬件实现。而高斯滤波器是带有权重的平均值,即加权平均,中心的权重比邻近像素的权重更大,这样就可以克服边界效应。高斯滤波采用的3*3掩膜的具体公式为:
G(x,y)={f(x-1,y-1)+f(x-1,y+1)+f(x+1,y-1)+f(x+1,y+1)+[f(x-1,y)+f(x,y-1)+f(x+1,y)+f(x,y+1)]*2+f(x,y)*4}/16
式中: f(x,y)为原图像中(x,y)像素的灰度值;g(x,y)为经过高斯滤波后的值。
上诉的公式可以结构化为3*3的掩膜如图所示。从结构化掩膜中可以看出,处于掩膜中心的位置比其他任何像素的权限都大,因此在均值计算中给定的这一像素显得更为重要。而距离掩膜中心较远的像素就显得不太重要,这样做是为了减小平滑处理的模糊。虽然可以采取其他权重达到相同的目的,但是由于1、2、4、16都是2的整数次幂,很方便硬件实现,其中16=1+2+1+2+4+2+1+2+1。
索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,她是一种离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,都会产生对应的灰度矢量或是其法矢量。Sobel卷积因子Gx、Gy如图所示:
该算子包含两组3*3的矩阵,分别为横向和纵向,将之与图像作平面卷积,即可分贝得出横向和纵向的亮度差分近似值。如果以A代表原始图像,Gx、Gy分别代表横向和纵向边缘检测的图像灰度值,其卷积因子计算公式如下:
式中:f(a,b)表示图像(a,b)点的灰度值。图像的每一个像素点的横向和纵向灰度值均通过以下公式来计算:
使用Sobel算子根据像素点上下、左右邻点灰度的加权差,在边缘处达到极值这一现象来检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,但是边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。
乒乓操作是一种完成数据无缝缓冲与处理的技巧,典型的乒乓操作如图所示。
存储单元是具有存储功能的模块,本项目使用SDRAM作为存储单元。乒乓操作可以分为三个阶段:
按此顺序不断循环。