目录
- 一、sobel边沿检测原理
- 二、HLS方案实现sobel边沿检测
- 三、HLS在线仿真并导出IP
- 四、Kintex7开发板vivado工程验证
- 五、zynq7100开发板vivado工程验证
- 六、板级调试验证
- 七、福利:工程源码获取
一、sobel边沿检测原理
所谓边缘是指其周围像素灰度急剧变化的那些象素的集合,它是图像最基本的特征。边缘存在于目标、背景和区域之间,所以,它是图像分割所依赖的最重要的依据。由于边缘是位置的标志,对灰度的变化不敏感,因此,边缘也是图像匹配的重要的特征。
 边缘检测和区域划分是图像分割的两种不同的方法,二者具有相互补充的特点。在边缘检测中,是提取图像中不连续部分的特征,根据闭合的边缘确定区域。而在区域划分中,是把图像分割成特征相同的区域,区域之间的边界就是边缘。由于边缘检测方法不需要将图像逐个像素地分割,因此更适合大图像的分割。边缘大致可以分为两种,一种是阶跃状边缘,边缘两边像素的灰度值明显不同;另一种为屋顶状边缘,边缘处于灰度值由小到大再到小的变化转折点处。边缘检测的主要工具是边缘检测模板。边缘检测的有很多,典型的有索贝尔算子、普里维特算子、罗伯茨交叉边缘检测等边缘检测技术,在设计中采用的是索贝尔算子。
 索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量。Sobel 卷积因子为:
 
 该算子包含两组 3x3 的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向
 的亮度差分近似值。如果以 A 代表原始图像,Gx 及 Gy 分别代表经横向及纵向边缘检测的图像灰度值,
 其公式如下:
 
 图像的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小:
 
 通常,为了提高效率 使用不开平方的近似值,但这样做会损失精度,迫不得已的时候可以如下这样子:
 
 如果梯度 G 大于某一阀值,则认为该点(x,y)为边缘点。
二、HLS方案实现sobel边沿检测
在前面的sobel边沿检测原理中详细介绍了sobel边沿检测的算法公式,看起来很复杂很NB对吧?
 然并卵!!!!!!!
 然并卵!!!!!!!
 然并卵!!!!!!!
 因为对于HLS来说,干这活儿只需要一句话一行代码即可实现;
 因为Xilinx早就帮你做好了sobel边沿检测的库,并且可以综合,既然如此,我还需要去管他怎么实现的,算法公式是怎样的吗?这就是HLS的NB之处。。。
 HLS工程如下:
 
 综合后的延时、资源占用等性能参数如下:
 
 
 头文件如下:
#ifndef _HELAI_HLS_SOBEL_H
#define _HELAI_HLS_SOBEL_H
#include "hls_video.h"
#define MAX_HEIGHT 1080    //图像最大高度
#define MAX_WIDTH  1920    //图像最大宽度
#define INPUT_IMAGE        "luoli.jpg"
#define OUTPUT_IMAGE       "luoli_hls.jpg"
typedef hls::stream<ap_axiu<24,1,1,1> > AXI_STREAM;
typedef hls::Mat<MAX_HEIGHT,MAX_WIDTH,HLS_8UC3> RGB_IMAGE;
typedef hls::Mat<MAX_HEIGHT,MAX_WIDTH,HLS_8UC1> GRAY_IMAGE;
void helai_hls_sobel(AXI_STREAM&INPUT_STREAM,AXI_STREAM&OUTPUT_STREAM,int rows,int cols);
#endif
源文件的核心代码如下:
hls::Sobel<1,0,3>(img_1,img_2);	//将灰度数据与Sobel算子卷积	
核心代码就一句话,BN吧?呵呵。。。。。。
三、HLS在线仿真并导出IP
仿真源文件如下:
#include "helai_hls_sobel.h"
#include "hls_opencv.h"
int main(void)
{
	//获取图像数据
	IplImage* src = cvLoadImage(INPUT_IMAGE);
	IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
	//使用HLS库进行处理
	AXI_STREAM src_axi,dst_axi;
	IplImage2AXIvideo(src,src_axi);
	helai_hls_sobel(src_axi,dst_axi,src->height,src->width);
	AXIvideo2IplImage(dst_axi,dst);
	//保存图像
	cvSaveImage(OUTPUT_IMAGE,dst);
	//显示图像
	cvShowImage(INPUT_IMAGE,src);
	cvShowImage(OUTPUT_IMAGE,dst);
	//等待用户按下键盘上的任一按键
	cv::waitKey(0);
}
话不多说直接看HLS仿真结果:
 
 
 仿真完整成功后即可综合再导出IP:
 
 
 
四、Kintex7开发板vivado工程验证
开发板:Xilinx Kintex7开发板;
 开发环境:HLS2019.1;vivado2019.1;
 输入:OV5640摄像头,输入分辨率1280x720;
 输出:HDMI,输出分辨率1920x1080;
 工程BD如下:
 
 生成顶层RTL如下:
 
 SDK主函数源码如下:
#include <stdio.h>
#include "xgpio.h"
#include "oak_iic.h"
#include "unistd.h"
#include "helai_vdma.h"
#include "helai_color_back.h"
#include "helai_hls_sobel.h"
XGpio_Config *XGpioCfg;
XGpio led_gpio;
#define	AXI_GPIO_DEVICE_ID	XPAR_GPIO_0_DEVICE_ID
int main(){
	XGpioCfg = XGpio_LookupConfig(AXI_GPIO_DEVICE_ID);
	XGpio_CfgInitialize(&led_gpio, XGpioCfg, XGpioCfg->BaseAddress);
	XGpio_SetDataDirection(&led_gpio, 1, 0);	//output
	XGpio_DiscreteWrite(&led_gpio, 1, 0);
	oak_i2c_init(OV5640_IIC_BASEADDR, 1000000, 0x78>>1, IIC_REG_LEN16, IIC_DATA_LEN8);
	OV5640_Init(OV5640_IIC_BASEADDR,1280,720);
	helai_hls_sobel(720,1280);
	helai_vdma();
	while(1){
		usleep(500000);
		XGpio_DiscreteWrite(&led_gpio, 1, 1);
		usleep(500000);
		XGpio_DiscreteWrite(&led_gpio, 1, 0);
	}
}
五、zynq7100开发板vivado工程验证
开发板:Xilinx zynq7100开发板;
 开发环境:HLS2019.1;vivado2019.1;
 输入:OV5640摄像头,输入分辨率1280x720;
 输出:HDMI,输出分辨率1920x1080;
 工程BD如下:
 
 生成顶层RTL如下:
 
 SDK主函数源码如下:
#include "I2C_16bit.h"
#include "xiicps.h"
#include "xil_io.h"
#include "xparameters.h"
#include "helai_vdma.h"
#include "helai_hls_sobel.h"
void main()
{
	// Initialize OV5640 regesiter
	I2C_config_init();
	helai_hls_sobel(720,1280);
	helai_vdma();
	while (1) ;
}
六、板级调试验证
K7开发板和zynq开发板实物连接如下:图中K7为连接状态
 
 运行结果静态展示:
 
 下载程序后运行结果如下:以K7开发板为例,持续运行48小时无问题
HLS图像处理sobel
七、福利:工程源码获取
福利:工程代码的获取
 代码太大,无法邮箱发送,以某度网盘链接方式发送,
 资料如下:获取方式:私。
 K7开发板网盘资料如下:
 
 zynq开发板网盘资料如下:
 



















