潮男公社

数码 导航
潮男公社 > 数码 > 电脑 > 正文

Sobel算子原理介绍与实现方法

编辑:首席新闻菌2022-10-23 13:10:46

Sobel 原理介绍

索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量Sobel 卷积因子为:

ed34c6c8-04a1-11ed-ba43-dac502259ad0.png

该算子包含两组 3x3 的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以 A 代表原始图像,Gx 及 Gy 分别代表经横向及纵向边缘检测的图像灰度值,其公式如下:

ed476f3a-04a1-11ed-ba43-dac502259ad0.png

具体计算如下:

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)点的灰度值;

图像的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小:

ed64d85e-04a1-11ed-ba43-dac502259ad0.png

通常,为了提高效率 使用不开平方的近似值

ed72c252-04a1-11ed-ba43-dac502259ad0.png

Sobel 算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。

Sobel 算子在 HLS 上的实现

工程创建

Step1:打开Vivado HLS开发工具,单击Creat New Project创建一个新工程,设置好工程路径和工程名,一直点击 Next 按照默认设置

ed8913e0-04a1-11ed-ba43-dac502259ad0.png

Step2:出现如下图所示界面,时钟周期Clock Period按照默认10nsUncertaintlySolution Name均按照默认设置,点击红色箭头部分选择芯片类型,然后点击 OK。

ed9a241e-04a1-11ed-ba43-dac502259ad0.png

edad5fe8-04a1-11ed-ba43-dac502259ad0.png

edc20aec-04a1-11ed-ba43-dac502259ad0.png

点击Finish,出现如下界面

eddfd31a-04a1-11ed-ba43-dac502259ad0.png

Step4:右单击Source选项,选择New File,创建一个名为Top.cpp的文件。(一定要加cpp后缀)

Step5:打开刚刚新建的cpp文件,进入编辑状态,输入以下代码

ede74794-04a1-11ed-ba43-dac502259ad0.png

Top.cpp代码

#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)
}

Step6:再在Source中添加一个名为Top.h的库函数,并添加如下程序:

edfb2232-04a1-11ed-ba43-dac502259ad0.png

Top.h代码

#ifndefTOP_H
#defineTOP_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> AXI_STREAM;
typedef hls::Scalar<3, unsigned char> RGB_PIXEL;
typedef hls::MatRGB_IMAGE;
// top level function for HW synthesis
void hls_sobel(AXI_STREAM& src_axi, AXI_STREAM& dst_axi, int rows, int cols);
#endif

Step7:在Test Bench中,用同样的方法添加一个名为Test.cpp测试程序。添加如下代码

ee09b36a-04a1-11ed-ba43-dac502259ad0.png

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);
}

Step8:用同样的方法,再在Test Bench中创建一个opencv_top.cppopencv_top.h文件,添加如下程序:

ee22ec86-04a1-11ed-ba43-dac502259ad0.png

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::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代码

#ifndefOPENCV_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中添加一张名为lena.jpg的测试图片

ee2d0f86-04a1-11ed-ba43-dac502259ad0.png

接下来对工程进行编译和仿真。

Step1:单击Project-Project settings或直接单击快捷按钮。

ee3fd6e8-04a1-11ed-ba43-dac502259ad0.png

Step2选择Synthesis选项,然后点击Browse..指定一个顶层函数,选定hls_sobel为顶层函数,

ee4c0062-04a1-11ed-ba43-dac502259ad0.png

单击开始综合

ee604dd8-04a1-11ed-ba43-dac502259ad0.png

ee6dd868-04a1-11ed-ba43-dac502259ad0.png

eea38d78-04a1-11ed-ba43-dac502259ad0.png

eeabb6a6-04a1-11ed-ba43-dac502259ad0.jpg

在协议类型里面我们可以看到我们主要使用了三种协议,分别是axisap_stableap_ctrl_hs三种,这些协议的详细解释我们均可以在官方手册ug902中找到,其中ap_ctrl_hs的时序操作如下图所示,说简单点就是复位完成等待ap_start信号开始进行操作

综合完毕,我们对代码进行仿真测试,单击开始仿真

eec59d00-04a1-11ed-ba43-dac502259ad0.png

仿真结果如下,与通过OPENCV实现的Sobel检测结果基本一致。

eecf51b0-04a1-11ed-ba43-dac502259ad0.png

审核编辑:汤梓红

展开更多
标签: HLS sobel 算子
推荐信息
相关阅读
热门视频
精彩专题
热点推荐
取消