软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! 6.1 概述 本章介绍了一种使用HLS实现Sobel检测的方法,最后通过软件封装得到了一个可以在VIVADO上使用的硬件IP。下一章我们将使用这个IP,对此IP进行功能的验证。 6.2 Sobel原理介绍 索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量 Sobel卷积因子为: 
该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像灰度值,其公式如下: 
具体计算如下: Gx = (-1)*f(x-1, y-1) + 0*f(x,y-1) + 1*f(x+1,y-1) +(-2)*f(x-1,y) + 0*f(x,y)+2*f(x+1,y) +(-1)*f(x-1,y+1) + 0*f(x,y+1) + 1*f(x+1,y+1) = [f(x+1,y-1)+2*f(x+1,y)+f(x+1,y+1)]-[f(x-1,y-1)+2*f(x-1,y)+f(x-1,y+1)] Gy =1* f(x-1, y-1) + 2*f(x,y-1)+ 1*f(x+1,y-1) +0*f(x-1,y) 0*f(x,y) + 0*f(x+1,y) +(-1)*f(x-1,y+1) + (-2)*f(x,y+1) + (-1)*f(x+1, y+1) = [f(x-1,y-1) + 2f(x,y-1) + f(x+1,y-1)]-[f(x-1, y+1) + 2*f(x,y+1)+f(x+1,y+1)] 其中f(a,b), 表示图像(a,b)点的灰度值; 图像的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小: 
通常,为了提高效率 使用不开平方的近似值: 
如果梯度G大于某一阀值 则认为该点(x,y)为边缘点。 然后可用以下公式计算梯度方向: 
Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。 6.3 Sobel算子在HLS上的实现6.3.1 工程创建Step1:打开HLS,按照之前介绍的方法,创建一个新的工程,命名为sobel。 Step2:右单击Source选项,选择New File,创建一个名为Top.cpp的文件。 
Step3:在打开的编辑区中,把下面的程序拷贝进去: #include "top.h" void hls_sobel(AXI_STREAM& INPUT_STREAM, AXI_STREAM& OUTPUT_STREAM, int rows, int cols) { //Create AXI streaming interfaces for the core #pragma HLS INTERFACE axis port=INPUT_STREAM #pragma HLS INTERFACE axis port=OUTPUT_STREAM #pragma HLS RESOURCE core=AXI_SLAVE variable=rows metadata="-bus_bundle CONTROL_BUS" #pragma HLS RESOURCE core=AXI_SLAVE variable=cols metadata="-bus_bundle CONTROL_BUS" #pragma HLS RESOURCE core=AXI_SLAVE variable=return metadata="-bus_bundle CONTROL_BUS" #pragma HLS INTERFACE ap_stable port=rows #pragma HLS INTERFACE ap_stable port=cols RGB_IMAGE img_0(rows, cols); RGB_IMAGE img_1(rows, cols); RGB_IMAGE img_2(rows, cols); RGB_IMAGE img_3(rows, cols); RGB_IMAGE img_4(rows, cols); RGB_IMAGE img_5(rows, cols); RGB_PIXEL pix(50, 50, 50); #pragma HLS dataflow hls::AXIvideo2Mat(INPUT_STREAM, img_0); hls::Sobel<1,0,3>(img_0, img_1); hls::SubS(img_1, pix, img_2); hls::Scale(img_2, img_3, 2, 0); hls::Erode(img_3, img_4); hls::Dilate(img_4, img_5); hls::Mat2AXIvideo(img_5, OUTPUT_STREAM); } |
Step4:再在Source中添加一个名为Top.h的库函数,并添加如下程序: #ifndef _TOP_H_ #define _TOP_H_ #include "hls_video.h" // maximum image size #define MAX_WIDTH 512 #define MAX_HEIGHT 512 // I/O Image Settings #define INPUT_IMAGE "lena.jpg" #define OUTPUT_IMAGE "result.jpg" #define OUTPUT_IMAGE_GOLDEN "result_golden.jpg" // typedef video library core structures typedef hls::stream<ap_axiu<32,1,1,1> > AXI_STREAM; typedef hls::Scalar<3, unsigned char> RGB_PIXEL; typedef hls::Mat<MAX_HEIGHT, MAX_WIDTH, HLS_8UC3> RGB_IMAGE; // top level function for HW synthesis void hls_sobel(AXI_STREAM& src_axi, AXI_STREAM& dst_axi, int rows, int cols); #endif |
Step5:在Test Bench中,用同样的方法添加一个名为Test.cpp的测试程序。添加如下代码: #include "top.h" #include "opencv_top.h" using namespace std; using namespace cv; int main (int argc, char** argv) { //获取图像数据 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); hls_sobel(src_axi, dst_axi, src->height, src->width); AXIvideo2IplImage(dst_axi, dst); cvSaveImage(OUTPUT_IMAGE,dst); cvShowImage("hls_dst", dst); //使用OPENCV库进行处理 opencv_image_filter(src, dst); cvShowImage("cv_dst", dst); cvSaveImage(OUTPUT_IMAGE_GOLDEN,dst); waitKey(0); //释放内存 cvReleaseImage(&src); cvReleaseImage(&dst); } |
Step6:用同样的方法,再在Test Bench中创建一个opencv_top.cpp和opencv_top.h文件,添加如下程序: Opencv_top.cpp代码如下: #include "opencv_top.h" #include "top.h" void opencv_image_filter(IplImage* src, IplImage* dst) { IplImage* tmp = cvCreateImage(cvGetSize(src), src->depth, src->nChannels); cvCopy(src, tmp); cv::Sobel((cv::Mat)tmp, (cv::Mat)dst, -1, 1, 0); cvSubS(dst, cvScalar(50,50,50), tmp); cvScale(tmp, dst, 2, 0); cvErode(dst, tmp); cvDilate(tmp, dst); cvReleaseImage(&tmp); } void sw_image_filter(IplImage* src, IplImage* dst) { AXI_STREAM src_axi, dst_axi; IplImage2AXIvideo(src, src_axi); hls_sobel(src_axi, dst_axi, src->height, src->width); AXIvideo2IplImage(dst_axi, dst); } |
Opencv_top.h代码如下: #ifndef ___OPENCV_TOP_H___ #define ___OPENCV_TOP_H___ #include "hls_opencv.h" void opencv_image_filter(IplImage* src, IplImage* dst); void sw_image_filter(IplImage* src, IplImage* dst); #endif |
Step7:在Test Bench中添加一张名为test_1080p.bmp的测试图片,图片可以在我们提供的源程序中的Image文件夹中找到。完整的工程如下图所示: 
6.3.2 代码优化及仿真 在前面几个章节中我 |