Sobel 原理介紹
索貝爾算子(Sobel operator)主要用作邊緣檢測(cè),在技術(shù)上,它是一離散性差分算子,用來(lái)運(yùn)算圖像亮度函數(shù)的灰度之近似值。在圖像的任何一點(diǎn)使用此算子,將會(huì)產(chǎn)生對(duì)應(yīng)的灰度矢量或是其法矢量Sobel 卷積因子為:
該算子包含兩組 3x3 的矩陣,分別為橫向及縱向,將之與圖像作平面卷積,即可分別得出橫向及縱向的亮度差分近似值。如果以 A 代表原始圖像,Gx 及 Gy 分別代表經(jīng)橫向及縱向邊緣檢測(cè)的圖像灰度值,其公式如下:
具體計(jì)算如下:
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)點(diǎn)的灰度值;
圖像的每一個(gè)像素的橫向及縱向灰度值通過(guò)以下公式結(jié)合,來(lái)計(jì)算該點(diǎn)灰度的大?。?/p>
通常,為了提高效率 使用不開(kāi)平方的近似值
Sobel 算子根據(jù)像素點(diǎn)上下、左右鄰點(diǎn)灰度加權(quán)差,在邊緣處達(dá)到極值這一現(xiàn)象檢測(cè)邊緣。對(duì)噪聲具有平滑作用,提供較為精確的邊緣方向信息,邊緣定位精度不夠高。當(dāng)對(duì)精度要求不是很高時(shí),是一種較為常用的邊緣檢測(cè)方法。
Sobel 算子在 HLS 上的實(shí)現(xiàn)
工程創(chuàng)建
Step1:打開(kāi)Vivado HLS開(kāi)發(fā)工具,單擊Creat New Project創(chuàng)建一個(gè)新工程,設(shè)置好工程路徑和工程名,一直點(diǎn)擊 Next 按照默認(rèn)設(shè)置
Step2:出現(xiàn)如下圖所示界面,時(shí)鐘周期Clock Period按照默認(rèn)10ns,Uncertaintly和Solution Name均按照默認(rèn)設(shè)置,點(diǎn)擊紅色箭頭部分選擇芯片類(lèi)型,然后點(diǎn)擊 OK。
點(diǎn)擊Finish,出現(xiàn)如下界面
Step4:右單擊Source選項(xiàng),選擇New File,創(chuàng)建一個(gè)名為Top.cpp的文件。(一定要加cpp后綴)
Step5:打開(kāi)剛剛新建的cpp文件,進(jìn)入編輯狀態(tài),輸入以下代碼
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中添加一個(gè)名為Top.h的庫(kù)函數(shù),并添加如下程序:
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
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中,用同樣的方法添加一個(gè)名為Test.cpp的測(cè)試程序。添加如下代碼:
Test.cpp代碼
#include "top.h"
#include "opencv_top.h"
using namespace std;
using namespace cv;
int main (int argc, char** argv)
{
//獲取圖像數(shù)據(jù)
IplImage* src = cvLoadImage(INPUT_IMAGE);
IplImage* dst = cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
//使用HLS庫(kù)進(jìn)行處理
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庫(kù)進(jìn)行處理
opencv_image_filter(src, dst);
cvShowImage("cv_dst", dst);
cvSaveImage(OUTPUT_IMAGE_GOLDEN,dst);
waitKey(0);
//釋放內(nèi)存
cvReleaseImage(&src);
cvReleaseImage(&dst);
}
Step8:用同樣的方法,再在Test Bench中創(chuàng)建一個(gè)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::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的測(cè)試圖片
接下來(lái)對(duì)工程進(jìn)行編譯和仿真。
Step1:?jiǎn)螕?/span>Project-Project settings或直接單擊快捷按鈕。
Step2:選擇Synthesis選項(xiàng),然后點(diǎn)擊Browse..指定一個(gè)頂層函數(shù),選定hls_sobel為頂層函數(shù),
單擊開(kāi)始綜合
在協(xié)議類(lèi)型里面我們可以看到我們主要使用了三種協(xié)議,分別是axis、ap_stable和ap_ctrl_hs三種,這些協(xié)議的詳細(xì)解釋我們均可以在官方手冊(cè)ug902中找到,其中ap_ctrl_hs的時(shí)序操作如下圖所示,說(shuō)簡(jiǎn)單點(diǎn)就是復(fù)位完成等待ap_start信號(hào)開(kāi)始進(jìn)行操作
綜合完畢,我們對(duì)代碼進(jìn)行仿真測(cè)試,單擊開(kāi)始仿真
仿真結(jié)果如下,與通過(guò)OPENCV實(shí)現(xiàn)的Sobel檢測(cè)結(jié)果基本一致。
審核編輯:湯梓紅
-
算子
+關(guān)注
關(guān)注
0文章
16瀏覽量
7253 -
HLS
+關(guān)注
關(guān)注
1文章
129瀏覽量
24113 -
sobel
+關(guān)注
關(guān)注
0文章
12瀏覽量
7907
原文標(biāo)題:Sobel 算子在 HLS 上的實(shí)現(xiàn)
文章出處:【微信號(hào):zhuyandz,微信公眾號(hào):FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論