将学习过程记录下来,结合自己的理解,并附上代码,目的是为了使更多像我一样的初学者可以收益,少走弯路。以下是笔者总结,仅供参考,如有错误,望指正!
一.定义
Sobel算子是计算机视觉领域的一种重要处理方法。多用于图像的边缘检测。
二.原理
Sobel算子利用离散的一阶差分(离散函数中连续相邻两项之差,定义X(k),则Y(k)=X(k+1)-X(k)就是此函数的一阶差分)算子,模拟图像亮度函数一阶梯度(可以近似理解为导数,具体内容自己去百度)的近似值。
一阶差分其实是一阶导数的近似,那么求边缘为什么要用到导数呢?我们先回归一下导数的概念,还记得我们第一次接触导数就在什么时候吗,老师会告诉我们,导数反映的是函数变化的快慢(大小)。图像中的每个像素点可以类比函数图像中一个个点,那么图像的导数(如果可以求导)反映的就是图像像素值的变化吗。那么变化大的(比如,连续的三个像素点从20->200->20)像素点就是所谓的边界点。而变化大小的标准可以根据实际的图像设定一个阈值。这就是为什么可以用差分算子来做边缘检测。那么该算子究竟是什么呢?
该算子包含两组3*3的矩阵,一个是x方向、一个是y方向,如下图Gx,Gy所示。利用目标图像分别与这两个算子做卷积(两个变量在某范围内相乘后求和的结果),就得到了图像亮度在x、y方向的差分近似值。
-1 0 1 1 2 1
-2 0 2 0 0 0
-1 0 1 -1 -2 -1
Gx Gy
三.通过一个实例来说明,并附上代码
该实例将一 200*200的灰度图像 通过 串口 发送给FPGA,调用FIFO做卷积运算,运算结果存入ram中,最后通过VGA显示出来。
首先送上实验效果
原始图像(bmp) 处理后图像
流程如下:
RS232 -> FIFO -> SOBEL -> RAM -> VGA
具体步骤如下:
1)Matlab生成数据图像
将图像矩阵变换成1*m*n大小(m:图像行数 n:图像列数)写入txt文本,以两位十六进制(%02x)格式保存数据。
matlab代码:
2)串口模块接收数据rx_data
串口数据是一位一位接收,接收的数据每8位保存在rx_data中,rx_data的位宽为8.
接收模块接口如下:(由于篇幅限制,这里只给出接口与内部变量)
3)利用FIFO同时取图像三行,Sobel算子参与运算
控制FIFO的输出,使得同时控制三行数据,将每行读出的数据依次保存在a、b、c中,a、b、c组成的3*3的矩阵,我们叫做A,A与Gx,Gy分别作卷积,分别得到目标图像在Gx,Gy方向的边界。卷积公式如下:
Gx = a1-c1+(a2-c2)<<1+a3-c3;
Gy = a1-a3+(b1-b3)<<1+c1-c3;
Gxy = |Gx| + |Gy|;
Gxy表示两个方向差分绝对值的和。
Sobel主要变量的时序图(手写)
4.创建一个双口ram,将Gxy保存到双口ram中
这里值得注意的是,保存到ram中的图像大小实际上是198*198(原始图像是200*200),图像周围边框没有处理。
写使能控制好拉高的时间,通过计数器来控制。
5.读出ram中的数据,并在VGA中显示
实验过程中出现的问题:
1.再次发送图像,图像会偏移。
观察仿真波形图发现,使能信号拉高时间错误。
83642879_827020636 2015-9-28 08:13
83642879_827020636 2015-9-26 22:29
83642879_827020636 2015-9-26 22:27
用户377235 2015-9-26 09:50
问一下,用到实际项目中了吗?
zcf287 2015-9-20 07:06
东莞元宝代理Microchip长电二三极管 2015-9-19 12:08