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)点的灰度值;
图像的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小:
通常,为了提高效率 使用不开平方的近似值
Sobel 算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。
Sobel 算子在 HLS 上的实现
工程创建
Step1:打开 Vivado HLS 开发工具,单击 Creat New Project 创建一个新工程,设置好工程路径和工程名,一直点击 Next 按照默认设置
Step2:出现如下图所示界面,时钟周期 Clock Period 按照默认 10ns,Uncertaintly 和 Solution Name 均按照默认设置,点击红色箭头部分选择芯片类型,然后点击 OK。
点击 Finish,出现如下界面
Step4:右单击 Source 选项,选择 New File,创建一个名为 Top.cpp 的文件。(一定要加cpp后缀)
Step5:打开刚刚新建的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 的库函数,并添加如下程序:
#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
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 的测试程序。添加如下代码:
#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.cpp 和 opencv_top.h 文件,添加如下程序:
#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);
}
#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 中添加一张名为 lena.jpg的测试图片
接下来对工程进行编译和仿真。
Step1:单击 Project-Project settings 或直接单击快捷按钮。
Step2:选择 Synthesis 选项,然后点击 Browse..指定一个顶层函数,选定 hls_sobel 为顶层函数,
单击 开始综合
在协议类型里面我们可以看到我们主要使用了三种协议,分别是 axis、ap_stable 和 ap_ctrl_hs 三种,这些协议的详细解释我们均可以在官方手册 ug902 中找到,其中 ap_ctrl_hs 的时序操作如下图所示,说简单点就是复位完成等待 ap_start 信号开始进行操作
综合完毕,我们对代码进行仿真测试,单击 开始仿真
仿真结果如下,与通过 OPENCV 实现的 Sobel 检测结果基本一致。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !