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