這篇文章的基礎(chǔ)是《Windows上快速部署Vitis HLS OpenCV仿真庫》,我們使用的版本是Vitis HLS 2022.2,其他版本BUG不清楚,目前已知2021版本有BUG,只能使用其他方式,本文不適合。
這次選擇中值濾波這個(gè)常規(guī)算法作為演示算法。
算法原理
算法原理很簡單,我們先介紹均值濾波,因?yàn)榫€性濾波的基礎(chǔ)是均值濾波,中值濾波是在這個(gè)基礎(chǔ)上發(fā)展過來的。
均值濾波
圖像均值濾波是一種基本的圖像平滑處理方法,也被稱為“盒子濾波”或“平滑濾波”。它的主要思想是對(duì)圖像中的每個(gè)像素取一個(gè)局部均值,以降低圖像噪聲和細(xì)節(jié)對(duì)圖像邊緣檢測(cè)和其他計(jì)算機(jī)視覺算法的影響。
具體來說,圖像均值濾波涉及在圖像中移動(dòng)一個(gè)固定尺寸的窗口,例如 的窗口。對(duì)于每個(gè)窗口,計(jì)算窗口內(nèi)所有像素的平均值,并將該值分配給窗口中心的像素。這個(gè)過程將重復(fù)應(yīng)用于整個(gè)圖像,用于生成平滑的輸出圖像。
在進(jìn)行圖像處理時(shí),一張圖片可以看做一個(gè)矩陣,假設(shè)有個(gè)6x6圖片,如下:
處理內(nèi)核如下:
動(dòng)畫演示處理過程如下
特點(diǎn)
具有非常不具代表性的值的單個(gè)像素會(huì)顯著影響其鄰域中所有像素的平均值。
當(dāng)濾波器鄰域跨越邊緣時(shí),濾波器將為邊緣上的像素插入新值,從而模糊該邊緣。如果輸出中需要尖銳的邊緣,這可能是個(gè)問題。
這兩個(gè)問題都由中值濾波器解決,中值濾波器通常是比均值濾波器更好的降噪濾波器,但計(jì)算時(shí)間更長。
通常,均值濾波器充當(dāng)?shù)屯l率濾波器 ,因此減少了圖像中存在的空間強(qiáng)度導(dǎo)數(shù)。
上圖描繪了一個(gè)包含更廣泛不同空間頻率的場(chǎng)景。用 3×3 均值濾波器平滑一次后,我們得到
背景中的低空間頻率信息并未受到過濾的顯著影響,但前景對(duì)象的(曾經(jīng)清晰的)邊緣已被明顯平滑。用 7×7 均值濾波器過濾后,得到下圖
將此結(jié)果與通過在原始圖像上傳遞 3×3 均值濾波器三次獲得的結(jié)果進(jìn)行比較
上兩圖說明一個(gè)問題:對(duì)一幅圖像應(yīng)用大窗口的濾波器和應(yīng)用多次小窗口濾波器效果差不多。
常見變體
此處討論的均值平滑濾波器的變體包括:閾值平均,其中僅當(dāng)其原始值與平均值之間的差大于預(yù)設(shè)閾值時(shí)才改變中心像素值的條件下應(yīng)用平滑。這具有平滑噪聲的效果,圖像細(xì)節(jié)的損失較小。
其他不計(jì)算鄰域均值的卷積濾波器也經(jīng)常用于平滑。其中最常見的一種是高斯平滑濾波器。
中值濾波
圖像中值濾波是一種常用的非線性濾波方法,也被稱為排序?yàn)V波器。它的主要原理是將圖像中每個(gè)像素周圍的像素排序,并將排序后的中間值作為該像素的輸出值。
中值濾波可以有效地抑制圖像中的噪聲,同時(shí)保留圖像中細(xì)節(jié)和邊緣信息。相對(duì)于其他線性濾波器(如均值濾波器),它可以在更好地去除噪聲的同時(shí)保留圖像的細(xì)節(jié)和邊緣上提供更好的性能。
具體地,對(duì)于每個(gè)像素,中值濾波器會(huì)包括 個(gè)鄰域像素,其中 和 是正奇數(shù)。它們將以該像素為中心構(gòu)成一個(gè)矩形窗口或一個(gè)圓形窗口。
窗口大小是中值濾波器的重要參數(shù)。在選擇窗口大小時(shí),應(yīng)該考慮噪聲的特性以及需要保留的圖像細(xì)節(jié)。通常情況下,窗口大小越大,中值濾波器能夠去除的噪聲越大,但也會(huì)導(dǎo)致圖像模糊。
然后,對(duì)于每個(gè)像素,將鄰域像素按灰度值進(jìn)行排序,取排序后的中間值作為該像素的輸出值。這個(gè)輸出值將取代原始圖像中的像素值,從而產(chǎn)生一個(gè)平滑且噪聲減少的圖像。
中值濾波器的優(yōu)點(diǎn)是它可以在去除噪聲的同時(shí)保留圖像中的邊緣和細(xì)節(jié),但它的缺點(diǎn)是計(jì)算成本較高,并且可能導(dǎo)致圖像的細(xì)節(jié)丟失。此外,當(dāng)噪聲水平很高時(shí),這種濾波器可能無法完全去除噪聲。
所有平滑技術(shù)都可以有效去除信號(hào)平滑塊或平滑區(qū)域中的噪聲,但會(huì)對(duì)邊緣產(chǎn)生不利影響。通常,在降低信號(hào)噪聲的同時(shí),保留邊緣也很重要。例如,邊緣對(duì)于圖像的視覺特性至關(guān)重要。對(duì)于小到中等水平的高斯噪聲,中值濾波器在去除噪聲方面明顯優(yōu)于高斯濾波,同時(shí)為給定的固定窗口大小保留邊緣。然而,對(duì)于高水平的噪聲,它的性能并不比高斯模糊好多少,而對(duì)于散斑噪聲和椒鹽噪聲(脈沖噪聲),它特別有效。正因?yàn)槿绱耍兄禐V波在數(shù)字圖像處理中得到了非常廣泛的應(yīng)用。
OpenCV實(shí)現(xiàn)
使用OpenCV進(jìn)行算法驗(yàn)證和Matlab進(jìn)行算法驗(yàn)證其實(shí)思路差不多,先驗(yàn)證算法的效果再驗(yàn)證算法的正確性,這一步使用OpenCV和MatLab一樣,我們就使用OpenCV進(jìn)行驗(yàn)證,這一步就不實(shí)際展開了,代碼如下:
//-----------------------------------【頭文件包含部分】--------------------------------------- //描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include"opencv2/core/core.hpp" #include"opencv2/highgui/highgui.hpp" #include"opencv2/imgproc/imgproc.hpp" //-----------------------------------【命名空間聲明部分】--------------------------------------- //描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- usingnamespacecv; //-----------------------------------【main()函數(shù)】-------------------------------------------- //描述:控制臺(tái)應(yīng)用程序的入口函數(shù),我們的程序從這里開始 //----------------------------------------------------------------------------------------------- intmain() { //載入原圖 Matimage=imread("1.jpg"); //創(chuàng)建窗口 namedWindow("中值濾波【原圖】"); namedWindow("中值濾波【效果圖】"); //顯示原圖 imshow("中值濾波【原圖】",image); //進(jìn)行中值濾波操作 Matout; medianBlur(image,out,7); //顯示效果圖 imshow("中值濾波【效果圖】",out); waitKey(0); }
HLS加速和仿真
上面就完成了算法的介紹和論證,其中論證過程并沒有詳細(xì)介紹,因?yàn)楸酒恼轮攸c(diǎn)不是這個(gè),后續(xù)在介紹這個(gè)算法的時(shí)候再詳細(xì)展開。
HLS工程搭建
新建工程
如下:
第二頁和第三頁不用管,后續(xù)再進(jìn)行設(shè)置
最后一頁,需要設(shè)置兩個(gè)地方,注意一個(gè)地方
其中,Uncertainty參數(shù)含義見下,默認(rèn)不設(shè)置即可。
在UG1399的set_clock_uncertainty章節(jié)有詳細(xì)介紹。
【uncertainty】:以 ns 為單位指定,表示時(shí)鐘周期中有多少被用作余量。不確定性也可以指定為時(shí)鐘周期的百分比。默認(rèn)的不確定性是時(shí)鐘周期的 27%。
也可以使用函數(shù):
set_clock_uncertainty
【uncertainty】:以 ns 為單位指定,表示時(shí)鐘周期中有多少被用作余量。不確定性也可以指定為時(shí)鐘周期的百分比。默認(rèn)的不確定性是時(shí)鐘周期的 27%。
【clock_list】:應(yīng)用不確定性的時(shí)鐘列表。如果未提供,它將應(yīng)用于所有時(shí)鐘。
添加源文件
新建xf_median_blur_accel.cpp
#include"xf_median_blur_config.h" staticconstexprint__XF_DEPTH=(HEIGHT*WIDTH*(XF_PIXELWIDTH(TYPE,NPC1))/8)/(PTR_WIDTH/8); voidmedian_blur_accel(ap_uint*img_in,introws,intcols,ap_uint *img_out){ //clang-formatoff #pragmaHLSINTERFACEm_axiport=img_inoffset=slavebundle=gmem0depth=__XF_DEPTH #pragmaHLSINTERFACEm_axiport=img_outoffset=slavebundle=gmem1depth=__XF_DEPTH #pragmaHLSINTERFACEs_axiliteport=rowsbundle=control #pragmaHLSINTERFACEs_axiliteport=colsbundle=control #pragmaHLSINTERFACEs_axiliteport=returnbundle=control //clang-formaton xf::Mat imgInput(rows,cols); xf::Mat imgOutput(rows,cols); //clang-formatoff #pragmaHLSDATAFLOW //clang-formaton //Retrievexf::Matobjectsfromimg_indata: xf::Array2xfMat (img_in,imgInput); //RunxfOpenCVkernel: xf::medianBlur ( imgInput,imgOutput); //Convert_dstxf::Matobjecttooutputarray: xf::xfMat2Array (imgOutput,img_out); return; }//Endofkernel
添加仿真文件
新建xf_median_blur_tb.cpp
#include"common/xf_headers.hpp" #include"xf_median_blur_config.h" intmain(intargc,char**argv){ if(argc!=2){ fprintf(stderr,"Usage:%s",argv[0]); returnEXIT_FAILURE; } cv::Matin_img,out_img,ocv_ref,diff; //Readingintheimage: #ifGRAY in_img=cv::imread(argv[1],0);//readinginthegrayimage #else in_img=cv::imread(argv[1],1);//readinginthecolorimage #endif if(in_img.data==NULL){ fprintf(stderr,"ERROR:Cannotopenimage%s ",argv[1]); returnEXIT_FAILURE; } //creatememoryforoutputimage #ifGRAY ocv_ref.create(in_img.rows,in_img.cols,CV_8UC1); out_img.create(in_img.rows,in_img.cols,CV_8UC1);//creatememoryforoutputimage diff.create(in_img.rows,in_img.cols,CV_8UC1); #else ocv_ref.create(in_img.rows,in_img.cols,CV_8UC3); out_img.create(in_img.rows,in_img.cols,CV_8UC3);//creatememoryforoutputimage diff.create(in_img.rows,in_img.cols,CV_8UC3); #endif //OpenCVreference: cv::medianBlur(in_img,ocv_ref,WINDOW_SIZE); //OpenCLsection: #ifGRAY size_timage_in_size_bytes=in_img.rows*in_img.cols*1*sizeof(unsignedchar); #else size_timage_in_size_bytes=in_img.rows*in_img.cols*3*sizeof(unsignedchar); #endif size_timage_out_size_bytes=image_in_size_bytes; //Callthetopfunction median_blur_accel((ap_uint*)in_img.data,in_img.rows,in_img.cols,(ap_uint *)out_img.data); //Writedownoutputimages: cv::imwrite("hls_out.jpg",out_img);//kerneloutput cv::imwrite("ref_img.jpg",ocv_ref);//referenceimage absdiff(ocv_ref,out_img,diff); //Savethedifferenceimagefordebuggingpurpose: cv::imwrite("error.png",diff); floaterr_per; xf::analyzeDiff(diff,10,err_per); if(err_per>0.0f){ fprintf(stderr,"ERROR:TestFailed. "); return1; }else std::cout<"Test?Passed?"?<
設(shè)置仿真庫
在下面界面設(shè)置相關(guān)參數(shù):
在這個(gè)界面設(shè)置
1、Top Function
設(shè)置主函數(shù)的,點(diǎn)擊Browse進(jìn)行選擇即可。
2、設(shè)置設(shè)計(jì)文件Edit cflags,添加調(diào)用的設(shè)計(jì)頭文件
添加
-IE:/vitis_hls_image/Vitis_Libraries-2020.2/Vitis_Libraries-2020.2/vision/L1/include-std=c++0x-IH:/FILE/HLS/meanblur/src/build-I./.-D__SDSVHLS__-std=c++0x
3、設(shè)置設(shè)計(jì)文件Edit csimflags
-IE:/vitis_hls_image/Vitis_Libraries-2020.2/Vitis_Libraries-2020.2/vision/L1/include-std=c++0x-IH:/FILE/HLS/meanblur/src/build-I./.-D__SDSVHLS__-std=c++0x
接下來設(shè)置仿真庫路徑
1、設(shè)置仿真文件Edit cflags
-IE:/vitis_hls_image/opencv_lib/opencv/build_2/install/include-IE:/vitis_hls_image/Vitis_Libraries-2020.2/Vitis_Libraries-2020.2/vision/L1/include-IH:/FILE/HLS/meanblur/src/build-I.-std=c++0x-D__SDSVHLS__-std=c++0x
2、設(shè)置仿真文件Edit csimflags
-IE:/vitis_hls_image/opencv_lib/opencv/build_2/install/include-IE:/vitis_hls_image/Vitis_Libraries-2020.2/Vitis_Libraries-2020.2/vision/L1/include-IH:/FILE/HLS/meanblur/src/build-I.-std=c++0x-D__SDSVHLS__-std=c++0x
3、設(shè)置Linker Flags,調(diào)用OpenCV庫文件
-LE:/vitis_hls_image/opencv_lib/opencv/build_2/install/x64/mingw/lib-llibopencv_imgcodecs455-llibopencv_imgproc455-llibopencv_core455-llibopencv_highgui455-llibopencv_flann455-llibopencv_features2d455
4、 設(shè)置Input Arguments,這個(gè)是調(diào)用仿真圖片,可以后續(xù)再設(shè)置
H:/FILE/HLS/meanblur/src/128x128.png
綜合
點(diǎn)擊綜合按鈕即可開始綜合,結(jié)果如下:
仿真
點(diǎn)擊仿真按鈕得到下圖仿真結(jié)果
下圖從左到右分別為:OpenCV處理的結(jié)果、HLS處理的結(jié)果以及最后的兩個(gè)圖像差(無差別即全黑)。
聯(lián)合仿真
點(diǎn)擊聯(lián)合仿真按鈕后等待仿真結(jié)束,然后點(diǎn)擊下面按鈕查看波形:
導(dǎo)出IP
點(diǎn)擊導(dǎo)出IP按鈕等待導(dǎo)出即可。
總結(jié)
今天的例程演示完畢,從建立工程到最后導(dǎo)出IP,基本比較詳細(xì)。但是,上面的例程是不能直接應(yīng)用到視頻里的,原因是上面的接口沒經(jīng)過改動(dòng),需要從AXI轉(zhuǎn)成AXI-STREAM接口后再再接入到視頻架構(gòu)中即可,這部分我們后續(xù)再詳細(xì)說明。
審核編輯:劉清
-
濾波器
+關(guān)注
關(guān)注
161文章
7795瀏覽量
177996 -
計(jì)算機(jī)視覺
+關(guān)注
關(guān)注
8文章
1698瀏覽量
45977 -
OpenCV
+關(guān)注
關(guān)注
31文章
634瀏覽量
41338 -
HLS
+關(guān)注
關(guān)注
1文章
129瀏覽量
24097
原文標(biāo)題:如何用 Vitis HLS 實(shí)現(xiàn) OpenCV 仿真
文章出處:【微信號(hào):Open_FPGA,微信公眾號(hào):OpenFPGA】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論