(2)滤波处理。分辨率降低后,图像中仍有很多的突兀点,这是因为铁轨上各种电磁信号的存在,摄像头采集到的图像不可避免地受到高斯噪声、系统噪声的污染。考虑到图像特征,选用中值滤波,它在平滑脉冲噪声方面非常有效,同时可以保护图像尖锐的边缘。
(3)边缘提取。利用边缘检测算子检查每个像素的邻域并对灰度变化率进行量化,包括方向的确定。Sobel边缘检测算子方向性灵活,可以设置不同的系数,抑制噪声效果较好,使用范围广泛,因此选用Sobel算子。同时铁轨图像横向变化不大,而在纵向有很大的延伸,故也只考虑图像垂直边缘响应。
(4)连通域搜索。二值化处理后边缘图包含了铁轨信息,也含有很多非铁轨边缘。使用八连通区域搜索法,进行标号处理,记录相互独立的连通区域个数并进行标号。对连通区域按照长度大小进行排列,直到搜索出纵向最长的两根铁轨,然后判断并标记左右两铁轨,之后进行区域填充,最终可以看到标记的铁轨区域。
3.2 OpenCV仿真结果
本项目程序首先实现OpenCV仿真,然后移植到FPGA中。OpenCV提供的图像处理算法非常丰富,并且部分程序以C语言编写,处理得当,不需要添加新的外部支持就可以完整的编译连接生成执行程序进行算法移植。本次仿真只运用“cv.h”和“highhui.h”两个OpenCV库,主要是运用其图像加载、图像显示等函数,而中值滤波、边缘检测、铁轨搜索函数自行编写。仿真结果如图4所示。
图4 铁轨图像仿真结果
3.3 FPGA程序移植过程
3.3.1 图像输入与显示
本项目把图像数据转换为.ELF文件格式,烧录到NOR-Flash,在XPS的菜单下点击Program Flash Memory,选择自动格式转换,即可进行烧录,而且可以指定烧录数据的位置。数据格式转换利用Matlab软件完成,程序如下:
由于是灰度图像,只读取其亮度值。图像分辨率为640×480。写数据可以用fprintf函数或fwrite函数,但是实验表明使用fprintf函数写数据,文件大小302 kB,显示图像不正常;而使用fwrite函数写数据文件仅300 kB,显示图像正常。说明两种函数写数据方式本质不同,造成写入数据格式不同。
图像显示过程:先从Flash中每次一行把数据读入BRAM,然后把每一位亮度值移位变为R、G、B三位,再从BRAM读数据到SDRAM显存,如此循环480次,用以显示图片。由于R、G、B值相同,显示的便是灰度图像。如果直接从Flash读数据到SDRAM显存,显示图像每行有不规则不连续的黑点,甚至显示不正常。显存的设置在TFT-Controller IP中完成,显存空间为2 MB,起始地址与SDRAM起始地址相同。
3.3.2 图像处理程序移植
由于开发环境不同,移植后程序在独立系统上运行,需要对OpenCV仿真程序做一些改正。FPGA编程系统支持C语言标准库函数,所以打印输出显示函数print()、动态内存分配函数malloc()可以直接使用。尽管printf()函数也可以用于打印输出结果,但目的是把程序放入大小为32 KB的BRAM,实验表明它比print()函数占用空间大一倍。在OpenCV中,可以直接使用cvShowImage()、cvReleaseImage()、cvDestroyWindow()函数显示图像和释放内存空间,在移植程序中要自行设计这些函数。移植程序中subplot()函数用于在屏幕上显示4幅图像(降低分辨率源图像、滤波图像、阈值分割图像、铁轨检测图像),DeleteAllPointElems()函数用于释放内存空间。其他函数,例如降低分辨率函数Dec()、滤波函数filter()、边缘检测函数edge(),可以完全使用OpenCV中的程序,不需要做修改。移植后主程序如下: