请选择 进入手机版 | 继续访问电脑版
[X]关闭
2

S04-CH06 Sobel算子硬件实现之HLS实现(一)

摘要: 本章介绍了一种使用HLS实现Sobel检测的方法,最后通过软件封装得到了一个可以在VIVADO上使用的硬件IP。下一章我们将使用这个IP,对此IP进行功能的验证。

软件版本: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 代码优化及仿真

       在前面几个章节中我


路过

雷人

握手

鲜花

鸡蛋
发表评论

最新评论

引用 猪猪 2021-3-11 10:28
不错,感谢
引用 wldshy 2020-1-19 01:16
不全

查看全部评论(2)

本文作者
2019-9-17 10:49
  • 1
    粉丝
  • 4054
    阅读
  • 2
    回复

关注米联客

扫描关注,了解最新资讯

联系人:汤经理
电话:0519-80699907
EMAIL:270682667@qq.com
地址:常州溧阳市天目云谷3号楼北楼201B

关注米联客

扫描关注,了解最新资讯

联系人:汤经理
电话:0519-80699907
EMAIL:270682667@qq.com
地址:常州溧阳市天目云谷3号楼北楼201B

关注米联客

扫描关注,了解最新资讯

联系人:汤经理
电话:0519-80699907
EMAIL:270682667@qq.com
地址:常州溧阳市天目云谷3号楼北楼201B
热门评论
排行榜