日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

input自适应_【正点原子FPGA连载】第十一章基于OV5640的自适应二值化实验-领航者ZYNQ之HLS 开发指南...

發(fā)布時間:2024/10/12 编程问答 70 豆豆
生活随笔 收集整理的這篇文章主要介紹了 input自适应_【正点原子FPGA连载】第十一章基于OV5640的自适应二值化实验-领航者ZYNQ之HLS 开发指南... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1)摘自【正點原子】領航者ZYNQ之HLS 開發(fā)指南

2)平臺購買地址:https://item.taobao.com/item.htm?&id=606160108761

3)全套實驗源碼+手冊+視頻下載:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html

4)對正點原子FPGA感興趣的同學可以加群討論:876744900

5)正點原子資料更新和新品發(fā)布,請加正點原子公眾號:正點原子 關注方法:微信→添加好友→公眾號→輸入:正點原子

第十一章基于OV5640的自適應二值化實驗


在數(shù)字圖像分析與處理中,一幅圖片通常含有人們感興趣和不感興趣的兩部分。為了提取或突出人們感興趣的目標,常用的方法就是對圖像進行二值化分割。二值化的方法有很多,其中自適應二值化(OTSU)是圖像二值化最常用的一種算法。本章我們將在HLS中實現(xiàn)圖像的自適應二值化。
本章包括以下幾個部分:
1111.1簡介
11.2實驗任務
11.3HLS設計
11.4IP驗證
11.5下載驗證
11.1簡介
圖像二值化(Image Binarization)就是將圖像上的像素點的灰度值設置為最大(白色)或最小(黑色),也就是將整個圖像呈現(xiàn)出明顯的黑白效果的過程。這里我們以8bit表示的灰度圖像為例(灰度值的范圍為0~255),二值化就是通過選取適當?shù)拈撝?#xff0c;與圖像中的256個灰度等級進行比較。亮度高于閾值的像素點設置為白色(255),低于閾值的像素點設置為黑色(0),從而明顯地反映出圖像的整體和局部特征。
我們把圖像進行二值化是為了將感興趣目標和背景分離,在數(shù)字識別和指紋識別等場景中,二值化應用非常廣泛。

圖 11.1.1 指紋識別


在指紋識別中,由于我們只關注圖像的指紋信息,所以我們需要將背景信息全部清除掉,如上圖所示,圖像經過二值化處理后只保留了關鍵的指紋信息。
二值化在數(shù)字圖像處理中占有非常重要的地位,特別是在實時的圖像處理中,通過二值圖像處理實現(xiàn)而構成的系統(tǒng)是很多的。要進行二值圖像的處理與分析,首先要把灰度圖像二值化,得到二值化圖像,這樣有利于在對圖像做進一步處理時,圖像的集合性質只與像素值為0或255的點的位置有關,不再涉及像素的多級值,使處理變得簡單,而且數(shù)據(jù)的處理和壓縮量小。為了得到理想的二值圖像,一般采用封閉、連通的邊界定義不交疊的區(qū)域。所有灰度大于或等于閾值的像素被判定為屬于特定物體,其灰度值為255表示,否則這些像素點被排除在物體區(qū)域以外,灰度值為0,表示背景或者例外的物體區(qū)域。
實現(xiàn)二值化有兩種方法,一種是手動指定一個閾值,通過閾值來進行二值化處理;另一種是一個自適應閾值二值化方法(OTSU算法等)。使用第一種方法計算量小速度快,但是在處理不同圖像時顏色分布差別很大;使用第二種方法適應性強,能直接觀測處圖像的輪廓,但相對計算更復雜。當圖像的直方圖分布沒有明顯的低峰和高峰時,直接指定閾值可能會導致圖像中某些像素的關鍵信息丟失,所以我們在本章采用第二種方法來實現(xiàn)圖像的二值化。
OTSU算法計算出來的閾值可以使圖像的前景目標區(qū)域的像素的平均灰度值、背景區(qū)域像素的平均灰度值與整幅圖像像素的平均灰度值之間的差別最大,這種差異使用方差來表示的,故名最大類間方差法,該方法由日本學者大津于1978年提出,故又名大津法。
OTSU算法的原理非常簡單,該算法假定一幅圖像根據(jù)雙模直方圖(前景圖像像素和背景圖像像素)被分為兩類像素,它要計算能將兩類分開的最佳閾值,使得它們的類間方差最大,也就是前景圖像和背景圖像間像素的離散程度最大。OTSU算法類間方差的定義如下:


圖 11.1.2 類間方差公式
如圖所示,其中w0表示前景圖像像素出現(xiàn)的概率,u0表示前景圖像像素的平均灰度,w1表示背景圖像像素出現(xiàn)的概率,u1表示背景圖像像素的平均灰度,u表示整幅圖像像素的平均灰度。
為了實現(xiàn)找到使類間方差最大的閾值這個目標。我們需要遍歷0~255個灰度等級,這每一個灰度等級都將圖像分為兩類像素(前景圖像像素和背景圖像像素)。然后在每一個灰度等級下算出前景圖像像素的平均值(u0)和出現(xiàn)概率(w0)以及背景圖像像素的平均值(u1)和出現(xiàn)概率(u),同時我們還要計算出整幅圖像的平均灰度(u)。最后代入上面的公式計算出類間方差σ2。我們就是要找到一個灰度值得這個類間方差最大,然后將這個灰度值作為圖像二值化的閾值。
下面給出一幅灰度圖像以及它做了指定閾值和OTSU自適應二值化之后的圖像來加深我們對OTSU自適應二值化的理解:

圖 11.1.3 圖像自適應二值化


如圖所示,左邊的這幅圖像是灰度圖,中間的這副圖像是我們手動指定閾值操作的二值化圖像,右邊的這副圖像是灰度圖做了自適應二值化算法處理后的圖像,可以發(fā)現(xiàn)圖像經過自適應二值化計算出來的閾值比手動指定閾值二值化的效果更好。
11.2實驗任務
本節(jié)的實驗任務是使用Vivado HLS設計OTSU自適應二值化的IP核,并在Vivado中對設計出來的IP核進行驗證。
11.3HLS設計
我們在電腦中的“F:ZYNQHigh_Level_Synthesis”目錄下新建一個名為otsu_threshold的文件夾,作為本次實驗的工程目錄。然后打開Vivado HLS工具,創(chuàng)建一個新的工程。設置工程名為“otsu_threshold”,選擇工程路徑為剛剛創(chuàng)建的文件夾。需要注意的是,工程名以及路徑只能由英文字母、數(shù)字和下劃線組成,不能包含中文、空格以及其他特殊字符。如下圖所示:

圖 11.3.1 工程配置界面


設置好工程名及路徑之后,點擊“Next”,進入如下界面設置頂層函數(shù):

圖 11.3.2 設置頂層函數(shù)


工程創(chuàng)建完成后,在工程面板中的“source”目錄上點擊右鍵,然后在打開的列表中選擇“New File”新建源文件,在彈出的對話框中輸入源文件的名稱“otsu_threshold.cpp”,如圖1.3.3所示。源文件默認的保存路徑為HLS工程目錄,為方便源文件的管理,我們在工程目錄下新建一個名為“src”的文件下,將源文件保存在src目錄下。

圖 11.3.3 輸入源文件名


我們在這里使用C++語言來設計,那么后綴名需要設置為“.cpp”。設置好文件名和路徑之后,點擊“保存”。
“otsu_threshold.cpp”文件源代碼如下:

  • 1 #include "otsu_threshold.h"
  • 2
  • 3 void ov5640_otsu_threshold(AXI_STREAM & INPUT_STREAM,
  • 4 AXI_STREAM & OUTPUT_STREAM,
  • 5 int rows,
  • 6 int cols
  • 7 ){
  • 8
  • 9 #pragma HLS INTERFACE axis port=INPUT_STREAM
  • 10 #pragma HLS INTERFACE axis port=OUTPUT_STREAM
  • 11 #pragma HLS INTERFACE s_axilite port=rows
  • 12 #pragma HLS INTERFACE s_axilite port=cols
  • 13 #pragma HLS INTERFACE ap_ctrl_none port=return
  • 14 #pragma HLS dataflow
  • 15
  • 16 //hls::mat 格式變量
  • 17 RGB_IMAGE img_0(rows,cols);
  • 18 GRAY_IMAGE img_1(rows,cols);
  • 19 GRAY_IMAGE img_2(rows,cols);
  • 20 RGB_IMAGE img_3(rows,cols);
  • 21
  • 22 //將 AXI4 Stream 數(shù)據(jù)轉換成 hls::mat 格式
  • 23 hls::AXIvideo2Mat(INPUT_STREAM,img_0);
  • 24
  • 25 //將 RGB888 格式的彩色數(shù)據(jù)轉換成灰度數(shù)據(jù)
  • 26 hls::CvtColor<HLS_RGB2GRAY,HLS_8UC3,HLS_8UC1>(img_0,img_1);
  • 27
  • 28 //對灰度圖像進行OTSU自適應二值化
  • 29 hls::Otsu_threshold<HLS_8UC1,HLS_8UC1,MAX_HEIGHT,MAX_WIDTH>(img_1,img_2);
  • 30
  • 31 //將灰度數(shù)據(jù)轉換成三個通道的灰度圖像
  • 32 hls::CvtColor<HLS_GRAY2RGB,HLS_8UC1,HLS_8UC3>(img_2,img_3);
  • 33
  • 34 //將 hls::mat 格式數(shù)據(jù)轉換成 AXI4 Stream 格式
  • 35 hls::Mat2AXIvideo(img_3,OUTPUT_STREAM);
  • 36 }

  • 代碼的主體部分與《基于OV5640的直方圖均衡實驗》非常類似,只是在代碼的第29行我們使用的是hls::Otsu_threshold這個函數(shù)來實現(xiàn)自適應二值化算法。這個函數(shù)在Vivado HLS視頻庫中沒有相關定義,需要我們自己實現(xiàn)。
    “otsu_threshold.h”代碼如下:

  • 1 #ifndef OTSU_THRESHOLD_H
  • 2 #define OTSU_THRESHOLD_H
  • 3
  • 4 #include "hls_math.h"
  • 5 #include "hls_video.h"
  • 6
  • 7 namespace hls {
  • 8
  • 9 template<int SRC_T, int DST_T,int ROW, int COL>
  • 10 void Threshold(
  • 11 Mat<ROW, COL, SRC_T> &_src,
  • 12 Mat<ROW, COL, DST_T> &_dst,
  • 13 ap_uint<8> &threshold)
  • 14 {
  • 15 const int NUM_STATES=4;
  • 16 Window<1,NUM_STATES,ap_uint<8> > addr_win;
  • 17
  • 18 ap_uint<BitWidth<ROW*COL>::Value> hist_out[256];
  • 19 Window<1,NUM_STATES,ap_uint<BitWidth<ROW*COL>::Value> > hist_win;
  • 20
  • 21 ap_uint<BitWidth<ROW*COL>::Value> hist;
  • 22 ap_uint<8> addr;
  • 23 ap_uint<8> addr_last;
  • 24 ap_uint<BitWidth<ROW*COL>::Value> hist_last;
  • 25 ap_uint<8> addr_flag;
  • 26 ap_uint<BitWidth<ROW*COL>::Value> hist_flag;
  • 27 ap_uint<8> addr_w;
  • 28 ap_uint<BitWidth<ROW*COL>::Value> hist_w;
  • 29
  • 30 ap_uint<BitWidth<ROW*COL>::Value> tmp=0;
  • 31
  • 32 float pixel_probability[256];
  • 33 for(int i=0;i<NUM_STATES;i++) {
  • 34 #pragma HLS UNROLL
  • 35 addr_win(0,i)=i;
  • 36 hist_win(0,i)=0;
  • 37 }
  • 38
  • 39 for(int i=0;i<256;i++) {
  • 40 hist_out=0;
  • 41 pixel_probability = 0.0f;
  • 42 }
  • 43
  • 44 int cols=_src.cols;
  • 45 int rows=_src.rows;
  • 46 assert(rows<=ROW);
  • 47 assert(cols<=COL);
  • 48 loop_height: for(int i=0;i<rows;i++)
  • 49 {
  • 50 loop_width: for(int j=0;j<cols;j++)
  • 51 {
  • 52 #pragma HLS PIPELINE
  • 53 #pragma HLS LOOP_FLATTEN OFF
  • 54 #pragma HLS DEPENDENCE array inter false
  • 55 ap_uint<4> flag=NUM_STATES;
  • 56 HLS_TNAME(SRC_T) tempsrc=0;
  • 57 HLS_TNAME(DST_T) tempdst=0;
  • 58 _src.data_stream[0].read(tempsrc);
  • 59 tempdst=tempsrc > threshold ? 255 : 0;
  • 60 _dst.data_stream[0]<<tempdst;
  • 61
  • 62 for (int m=0; m<NUM_STATES; m++) {
  • 63 if (tempsrc==addr_win(0,m)) {
  • 64 flag = m;
  • 65 break;
  • 66 }
  • 67 }
  • 68
  • 69 latency_region:{
  • 70 #pragma HLS latency min=0 max=1
  • 71 addr_last = addr_win(0,NUM_STATES-1);
  • 72 hist_last = hist_win(0,NUM_STATES-1)+1;
  • 73 for (int m=NUM_STATES-1; m>0; m--) {
  • 74 addr = addr_win(0,m-1);
  • 75 hist = hist_win(0,m-1);
  • 76 if (m==NUM_STATES/2) {
  • 77 addr_w = addr;
  • 78 if (m==flag+1) {
  • 79 hist_w = hist+1;
  • 80 } else {
  • 81 hist_w = hist;
  • 82 }
  • 83 }
  • 84 if (m==flag+1) {
  • 85 addr_flag = addr;
  • 86 hist_flag = hist+1;
  • 87 addr_win(0,m) = addr_flag;
  • 88 hist_win(0,m) = hist_flag;
  • 89 } else {
  • 90 addr_win(0,m) = addr;
  • 91 hist_win(0,m) = hist;
  • 92 }
  • 93 }
  • 94 if (flag==NUM_STATES) {
  • 95 hist_win(0,0) = hist_out[tempsrc]+1;
  • 96 addr_win(0,0) = tempsrc;
  • 97 } else if (flag==NUM_STATES-1) {
  • 98 addr_win(0,0) = addr_last;
  • 99 hist_win(0,0) = hist_last;
  • 100 } else if (flag>=NUM_STATES/2) {
  • 101 addr_win(0,0) = addr_flag;
  • 102 hist_win(0,0) = hist_flag;
  • 103 } else {
  • 104 addr_win(0,0) = addr_w;
  • 105 hist_win(0,0) = hist_w;
  • 106 }
  • 107 hist_out[addr_w] = hist_w;
  • 108 }
  • 109 }
  • 110 }
  • 111
  • 112 for (int m=0; m<NUM_STATES/2; m++) {
  • 113 #pragma HLS PIPELINE
  • 114 hist_out[addr_win(0,m)]=hist_win(0,m);
  • 115 }

  • 實現(xiàn)OTSU算法,需要先統(tǒng)計圖像各個像素值出現(xiàn)的個數(shù),也就是統(tǒng)計圖像的直方圖。統(tǒng)計直方圖這部分代碼我們參考Vivado HLS視頻庫中直方圖均衡化中的部分源碼。下面簡單講解一下這個源碼的實現(xiàn)思路。
    我們想要獲取一幅圖像的直方圖,就需要定義一個數(shù)組,這個數(shù)組可以保存每個像素值出現(xiàn)的個數(shù)。其中數(shù)組的地址代表的是圖像像素的灰度等級0~255,數(shù)組里存儲的就是每一個灰度等級出現(xiàn)的個數(shù),在代碼的第18行就定義了“hist_out”這樣的一個數(shù)組。我們在獲取到輸入圖像像素的灰度值后,把這個灰度值作為數(shù)組的地址,從數(shù)組中取出數(shù)據(jù),并將得到的數(shù)據(jù)加1后再寫回數(shù)組對應的地址。這樣一幀圖像輸入完成后,數(shù)組中就存儲了整幅圖像的直方圖信息,即實現(xiàn)了直方圖的統(tǒng)計。
    在獲取一幀圖像的直方圖之后,需要根據(jù)圖像的直方圖來計算類間方差。在計算類間方差的時候,我們需要緩存后續(xù)輸入的圖像數(shù)據(jù),為計算上一幀圖像的OTSU閾值留出時間。代碼的第16行“addr_win”緩存了圖像像素的灰度值,代碼的第19行“hist_win”緩存了圖像像素出現(xiàn)的個數(shù),這里NUM_STATUS定義成4表示我們緩存的大小是4。
    代碼的第58行是讀取輸入像素的灰度值并存儲到“tempsrc”中,代碼的第59行是通過三目運算符,判斷輸入圖像像素值與閾值之間的大小,如果輸入圖像像素值比閾值大,則將輸出圖像像素設置為255,否則將輸出圖像像素設置為0,這樣就實現(xiàn)了圖像的二值化操作。
    在代碼的第130行到第180行就是通過OTSU算法來計算圖像的閾值。我們首先遍歷灰度級0~255,針對每一個灰度,把它作為閾值。如代碼的第130行所示:“threshold_tmp”這個變量就是我們設置的這個閾值。然后以這個閾值分類,分別計算前景圖像像素和背景圖像像素出現(xiàn)的個數(shù)和灰度總和。這里計算灰度總和的方式就是拿每個像素的灰度級乘以它出現(xiàn)的個數(shù)然后做一個累加。如代碼第144到第155行所示:“j”代表的是前景或背景圖像像素的灰度值,“hist_out”數(shù)組里存儲的是每個灰度級出現(xiàn)的個數(shù)。接下來我們就需要根據(jù)簡介里所介紹的類間方差公式,來分別計算公式中各個符號的值。如下圖所示:

    圖 11.3.4 類間方差公式


    其中“w0”代表的是前景圖像像素出現(xiàn)的概率,對應于代碼的第158行“front_pixel_probability”這個變量。我們在這里是拿前景圖像像素出現(xiàn)的個數(shù)除以一幀像素的個數(shù)來計算前景圖像像素出現(xiàn)的概率;“u0”代表的是前景圖像像素的平均灰度,對應于代碼的第164行“front_gray_average”這個變量。我們在這里是通過前景圖像像素的灰度總和除以前景圖像像素出現(xiàn)的個數(shù)來計算前景圖像像素的平均灰度?!皍”代表的是整幅圖像的平均灰度,對應于代碼的第168行“total_gray_average”這個變量。我們在這里是通過整幅圖像像素的灰度總和除以一幀像素的個數(shù)來得到的。在代碼的第178行到第180行就是找出最大的類間方差,并且將最大類間方差所對應的像素值賦值給“threshold”這個變量,作為我們二值化的閾值。
    我們程序用到了一些優(yōu)化指令,下面對這些優(yōu)化指令做一些介紹:
    在代碼的第34行“pragma HLS UNROLL”是HLS優(yōu)化指令,表示我們展開循環(huán)創(chuàng)建多個獨立的操作,這將會導致我們可以在單個時鐘周期里并行執(zhí)行for循環(huán)中的操作,而基于處理器的架構導致它執(zhí)行這些操作步驟都是串行執(zhí)行的。在FPGA內部數(shù)據(jù)可以并行處理,這體現(xiàn)了用FPGA并行加速的優(yōu)勢。如下圖所示:

    圖 11.3.5 循環(huán)展開


    左邊的這個“Rolled Loop”是滾動循環(huán),它表示每次迭代都在單獨的時鐘周期內執(zhí)行,這個實現(xiàn)需要四個時鐘周期,只需要用FPGA的一個乘法器就可以實現(xiàn);中間的這個“Partially Unrolled Loop”是部分展開循環(huán),在這個例子中,這個實現(xiàn)需要兩個時鐘周期,需要用FPGA的兩個乘法器來實現(xiàn);右邊的這個“Unroolled Loop”是展開循環(huán),在這個例子中,循環(huán)被完全展開,我們可以在單個時鐘周期內執(zhí)行所有循環(huán)操作。然而這個實現(xiàn)需要四個乘法器,更重要的是,這個實現(xiàn)需要能夠在相同的時鐘周期內執(zhí)行4次讀取和4次寫入操作,由于在FPGA的塊RAM最多只有兩個端口,因此我們在實現(xiàn)這個的時候需要對陣列進行分區(qū)。需要注意的是,循環(huán)展開后,如果循環(huán)的一次迭代中的操作需要前一次迭代的結果,那么它們不能并行執(zhí)行,而是在數(shù)據(jù)可用時立即執(zhí)行。
    在代碼的第52行“pragma HLS PIPELINE”是為了提高吞吐率而進行的優(yōu)化?!癙IPELINE”指的是流水線操作,流水線操作允許操作同時發(fā)生,任務可以不必在開始下一個操作之前完成所有操作。流水線可以應用于函數(shù)和循環(huán)。函數(shù)的吞吐率改進如下圖所示:

    圖 11.3.6 函數(shù)流水線操作


    如圖所示,如果沒有流水線操作,這個函數(shù)每3個時鐘周期讀取一個輸入,并且每2個時鐘周期輸出一個值。這個函數(shù)的啟動間隔(initiation interval)為3,延遲(latency)為2。通過流水線操作,每個周期(initiation interval = 1)讀取一個新的輸入,而不會改變輸出延遲或使用的資源。
    循環(huán)流水線操作允許循環(huán)中的操作以并發(fā)方式實現(xiàn),如圖所示:

    圖 11.3.7 循環(huán)流水線操作


    左邊的這個圖是默認的順序操作,其中每個輸入讀取(initiation interval = 3)之間有3個時鐘周期,并且在執(zhí)行最后一次輸出寫入之前需要8個時鐘周期。右邊的這個圖是循環(huán)流水線之后的結果,經過流水線處理后可以每個周期(initiation interval = 1)讀取一個新的輸入樣本,并且僅在4個時鐘周期后寫入最終輸出。在這里我們使用這個指令來提高系統(tǒng)的吞吐率。
    在代碼的第53行“pragma HLS LOOP_FLATTEN OFF”是為了防止這個嵌套循環(huán)在FPGA實現(xiàn)中被展平為單個循環(huán)層次結構。在Vivado HLS中默認情況下不會將嵌套循環(huán)展開,但可以定義優(yōu)化的程度,如果優(yōu)化等級定義過高,在綜合的時候還是有可能將嵌套的循環(huán)結構展平為單個循環(huán)層次結構,添加這個指令,就是為了防止Vivado HLS做這種優(yōu)化。
    程序創(chuàng)建完成后,點擊工具欄中向右的綠色三角形對C++代碼進行綜合,綜合完成后在工具欄中點擊黃色的“田”字按鈕,導出RTL,如下圖所示:


    圖 11.3.4 導出RTL
    在彈出的對話框中保持默認設置,直接點擊“OK”,如下圖所示:

    圖 11.3. 將設計導出成IP


    設計導出完成后,HLS設計部分就結束了,我們在HLS工程目錄下可以找到導出的IP核,如下圖紅色方框所示:

    圖 11.3.18導出得到的IP


    HLS設計結束之后,我們將在Vivado中對導出的IP核進行驗證。
    11.4IP驗證
    在IP驗證環(huán)節(jié),我們會使用Vivado工具的IP集成器將生成的IP核添加到Block Design中,然后完成設計后將程序下載到領航者開發(fā)板上進行驗證。
    用于IP驗證的底層硬件可以在《領航者ZYNQ之HLS開發(fā)指南》第5章“OV5640 攝像頭灰度顯示”實驗的基礎上進行。打開該實驗所對應的Vivado工程“ov5640_rgb2gray_ip_test”,將其另存為“otsu_threshold_ip_test”工程。為了方便工程管理,我們將Vivado工程的目錄與HLS工程目錄保持一致,如下圖所示:

    圖 11.4.1 創(chuàng)建Vivado工程


    在通過“另存為”的方式保存工程之后,還要將原來工程中的IP庫(名為ip_repo的文件夾)復制到新的Vivado工程目錄下, 然后將HLS設計過程中導出的IP核拷貝到“ip_repo”目錄下并解壓。
    在Vivado中重新將當前工程目錄下的ip_repo文件夾添加到工程的IP庫中,然后將HLS生成的IP核text_overlay添加到Block Design中,并將其STREAM接口分別連接到Video In to AXI4-Stream模塊的video_out接口與VDMA模塊的S_AXIS_S2MM接口上。最后點擊上圖中左上角的“Run Connection Automation”,讓工具自動連接該IP核的其他端口,包括時鐘、復位以及AXI-Lite從接口,最終完成的設計如下圖所示:
    然后點擊“Run Connnection Automation”,下面列出了會自動連接的模塊及其接口,勾選“All Automation”, 然后點擊“OK”按鈕。最終完成的設計如下圖所示:

    圖 11.4.2 完成后的Block Design


    到這里我們的Block Design就設計完成了,在Diagram窗口空白處右擊,然后選擇“Validate Design”驗證設計。驗證完成后彈出對話框提示“Validation Successful”表明設計無誤,點擊“OK”確認。最后按快捷鍵“Ctrl + S”保存設計。
    接下來在Source窗口中右鍵點擊Block Design設計文件“system.bd”,然后依次執(zhí)行“Generate Output Products”和“Create HDL Wrapper”。
    最后在左側Flow Navigator導航欄中找到PROGRAM AND DEBUG,點擊該選項中的“Generate Bitstream”,對設計進行綜合、實現(xiàn)、并生成Bitstream文件。
    在生成 Bitstream 之后,在菜單欄中選擇 File > Export > Export hardware 導出硬件,并在彈出的對話框 中,勾選“Include bitstream”。然后在菜單欄選擇 File > Launch SDK,啟動 SDK 軟件。
    在Vivado SDK中新建空的應用工程,工程名為“ov5640_otsu_threshold”。
    然后找到《領航者ZYNQ之嵌入式開發(fā)指南》第二十三章“OV5640 攝像頭 LCD 顯示”實驗的Vivado工程目錄,將“21_ov7725_lcdov7725_lcd.sdkov7725_lcd”目錄下的src文件夾拷貝到新建的應用工程目錄下。
    在SDK中刷新src目錄,然后將“main.c”的代碼修改為如下所示:

  • 1 #include <stdio.h>
  • 2 #include <stdlib.h>
  • 3 #include <string.h>
  • 4 #include "xil_types.h"
  • 5 #include "xil_cache.h"
  • 6 #include "xparameters.h"
  • 7 #include "xgpio.h"
  • 8 #include "xaxivdma.h"
  • 9 #include "xaxivdma_i.h"
  • 10 #include "display_ctrl/display_ctrl.h"
  • 11 #include "vdma_api/vdma_api.h"
  • 12 #include "emio_sccb_cfg/emio_sccb_cfg.h"
  • 13 #include "ov5640/ov5640_init.h"
  • 14 #include "xov5640_otsu_threshold.h"
  • 15
  • 16 //宏定義
  • 17 #define BYTES_PIXEL 3 //像素字節(jié)數(shù),RGB888占3個字節(jié)
  • 18 #define FRAME_BUFFER_NUM 3 //幀緩存?zhèn)€數(shù)3
  • 19 #define DYNCLK_BASEADDR XPAR_AXI_DYNCLK_0_BASEADDR //動態(tài)時鐘基地址
  • 20 #define VDMA_ID XPAR_AXIVDMA_0_DEVICE_ID //VDMA器件ID
  • 21 #define DISP_VTC_ID XPAR_VTC_0_DEVICE_ID //VTC器件ID
  • 22 //PL端 AXI GPIO 0(lcd_id)器件 ID
  • 23 #define AXI_GPIO_0_ID XPAR_AXI_GPIO_0_DEVICE_ID
  • 24 //使用AXI GPIO(lcd_id)通道1
  • 25 #define AXI_GPIO_0_CHANEL 1
  • 26
  • 27 //全局變量
  • 28 //frame buffer的起始地址
  • 29 unsigned int const frame_buffer_addr = (XPAR_PS7_DDR_0_S_AXI_BASEADDR
  • 30 + 0x1000000);
  • 31 XAxiVdma vdma;
  • 32 DisplayCtrl dispCtrl;
  • 33 XGpio axi_gpio_inst; //PL端 AXI GPIO 驅動實例
  • 34 XOv5640_otsu_threshold otsu_threshold_inst; //PL端otsu_threshold驅動實例
  • 35 VideoMode vd_mode;
  • 36 unsigned int lcd_id;
  • 37
  • 38 int main(void)
  • 39 {
  • 40 u32 status;
  • 41 u16 cmos_h_pixel; //ov5640 DVP 輸出水平像素點數(shù)
  • 42 u16 cmos_v_pixel; //ov5640 DVP 輸出垂直像素點數(shù)
  • 43 u16 total_h_pixel; //ov5640 水平總像素大小
  • 44 u16 total_v_pixel; //ov5640 垂直總像素大小
  • 45
  • 46 //獲取LCD的ID
  • 47 XGpio_Initialize(&axi_gpio_inst, AXI_GPIO_0_ID);
  • 48 lcd_id = LTDC_PanelID_Read(&axi_gpio_inst,AXI_GPIO_0_CHANEL);
  • 49 xil_printf("lcd_id = %xnr",lcd_id);
  • 50
  • 51 //根據(jù)獲取的LCD的ID號來進行ov5640顯示分辨率參數(shù)的選擇
  • 52 switch(lcd_id){
  • 53 case 0x4342 : //4.3寸屏,480*272分辨率
  • 54 cmos_h_pixel = 480;
  • 55 cmos_v_pixel = 272;
  • 56 total_h_pixel = 1800;
  • 57 total_v_pixel = 1000;
  • 58 break;
  • 59 case 0x4384 : //4.3寸屏,800*480分辨率
  • 60 cmos_h_pixel = 800;
  • 61 cmos_v_pixel = 480;
  • 62 total_h_pixel = 1800;
  • 63 total_v_pixel = 1000;
  • 64 break;
  • 65 case 0x7084 : //7寸屏,800*480分辨率
  • 66 cmos_h_pixel = 800;
  • 67 cmos_v_pixel = 480;
  • 68 total_h_pixel = 1800;
  • 69 total_v_pixel = 1000;
  • 70 break;
  • 71 case 0x7016 : //7寸屏,1024*600分辨率
  • 72 cmos_h_pixel = 1024;
  • 73 cmos_v_pixel = 600;
  • 74 total_h_pixel = 2200;
  • 75 total_v_pixel = 1000;
  • 76 break;
  • 77 case 0x1018 : //10.1寸屏,1280*800分辨率
  • 78 cmos_h_pixel = 1280;
  • 79 cmos_v_pixel = 800;
  • 80 total_h_pixel = 2570;
  • 81 total_v_pixel = 980;
  • 82 break;
  • 83 default :
  • 84 cmos_h_pixel = 480;
  • 85 cmos_v_pixel = 272;
  • 86 total_h_pixel = 1800;
  • 87 total_v_pixel = 1000;
  • 88 break;
  • 89 }
  • 90
  • 91 emio_init(); //初始化EMIO
  • 92 status = ov5640_init( cmos_h_pixel, //初始化ov5640
  • 93 cmos_v_pixel,
  • 94 total_h_pixel,
  • 95 total_v_pixel);
  • 96 if(status == 0)
  • 97 xil_printf("OV5640 detected successful!rn");
  • 98 else
  • 99 xil_printf("OV5640 detected failed!rn");
  • 100
  • 101 //根據(jù)獲取的LCD的ID號來進行video參數(shù)的選擇
  • 102 switch(lcd_id){
  • .

    .
    在代碼的第14行引入了“xov5640_otsu_threshold.h”頭文件,這個頭文件是Vivado HLS工具生成的,里面聲明了OTSU自適應二值化IP核的驅動函數(shù)。首先在代碼的34行定義了OTSU自適應二值化IP核的驅動實例otsu_threshold_inst,該變量會在后面對IP核進行配置時用到。然后在代碼的第112行通過“XOv5640_otsu_threshold_Initialize ()”函數(shù)來初始化Vivado HLS生成的OTSU自適應二值化IP核;在代碼的第116行通過傳入“vd_mode.height”形參來設置OTSU自適應二值化IP核的行數(shù),在代碼的第114行通過傳入“vd_mode.width”形參來設置列數(shù)。這些數(shù)據(jù)類型和函數(shù)在“xov5640_otsu_threshold.h”頭文件中均有聲明。
    11.5下載驗證
    編譯完工程之后我們就可以開始下載程序了。將 OV5640 攝像頭模塊插在領航者Zynq開發(fā)板的“OLED/CAMERA”插座上,并將LCD的排線接頭插入開發(fā)板上的 LCD 接線座。將下載器一端連電腦,另一端與開發(fā)板上的 JTAG 端口連接,連接電源線并打開電源開關。
    在SDK軟件下方的SDK Terminal窗口中點擊右上角的加號設置并連接串口。然后下載本次實驗硬件設計過程中所生成的BIT文件,來對PL進行配置。最后下載軟件程序,下載完成后在LCD上就可以看到液晶屏上顯示了經過OTSU自適應二值化處理后的圖像,如下圖所示:

    圖 11.5.1 OTSU自適應二值化效果圖

    總結

    以上是生活随笔為你收集整理的input自适应_【正点原子FPGA连载】第十一章基于OV5640的自适应二值化实验-领航者ZYNQ之HLS 开发指南...的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。