衡阳派盒市场营销有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

基于FPGA實現圖像直方圖設計

FPGA設計論壇 ? 來源:FPGA設計論壇 ? 2024-12-24 10:24 ? 次閱讀

直方圖統計的原理

直方圖統計從數學上來說,是對圖像中的像素點進行統計。圖像直方圖統計常用于統計灰度圖像,表示圖像中各個灰度級出現的次數或者概率。統計直方圖的實現采用C/C++或者其他高級語言實現十分簡單,單采用FPGA來實現直方圖的統計就稍顯麻煩。若使用Xilinx和Altera的FPGA芯片,可以使用HLS來進行圖像的加速處理。但這暫時不是我的重點。

C語言實現直方圖統計:unsigned int histoBuffer[256];

for(int idxCol = 0; idxCol < imageWidth; idxCol ++)

{

for(int idxRow = 0; idxRow < imageHeight; idxRow ++)

{

histoBuffer[image[idxRow * imageWidth + idxCol]] ++;

}

}

基于FPGA實現圖像直方圖

在前面可以看到基于C/C++或者其他高級語言實現直方圖統計十分簡單。但是在FPGA中,需要設計具體的時序和電路才能正確地將直方圖進行統計。

直方圖統計的注意點

使用FPGA來完成直方圖的統計需要注意以下幾點:

對一幅圖像進行統計,必須等到當前的圖像“流過”后才能完成。這使得采用FPGA相較于其他方式并沒有太大的優勢。

在統計的過程中,需要對已經統計的像素的統計值進行緩存。

在下一幀圖像來臨的時候,需要將RAM中的數據清空。

設計統計模塊

根據上面的要點,在設計直方圖統計電路的時候可以按照如下思路來進行:

新的一幀圖像來臨是,需要將上一幀圖像的直方圖統計結果清零。

在新一幀圖像數據有效時,進行統計

一幀圖像數據統計完成后,將統計結果讀出,并將統計結果輸出到外部。

狀態機設計:

在復位或空閑狀態下,系統處于IDLE狀態,當檢測到新一幀圖像(vsync信號的上升沿)時,狀態跳轉到CLEAR狀態,清空RAM中保存的上一幀圖像的數據。當RAM中的圖像數據清空完成后,進入到直方圖統計狀態CALCULATE,在該狀態下進行直方圖的統計當一幀圖像統計完成后,將本幀圖像的統計結果輸出,也即GET_HISTO狀態。

4b988b6e-c01b-11ef-9310-92fbcf53809c.png

CLEAR狀態:

下圖是CLEAR狀態下的時序設計圖,拉高一個clear_flag信號,向RAM中寫入0,將上一幀圖像的統計結果清零。

4ba85c74-c01b-11ef-9310-92fbcf53809c.png

CALCULATE狀態:

統計狀態下完成的任務是最復雜的,由于在圖像數據流來領的時候,常常會遇到相鄰幾個像素點的灰度值是相同的,因此可以將這些點進行統計,然后在將統計值寫入到RAM中,將小對RAM的讀寫操作。

下面的時序圖是一個典型的統計時序設計圖,基本包括了圖像流入時的像素狀態。

在統計時,主要是來比較當前的像素點和上一個像素點的值是否相同,若相同則像素統計值cal_pixel就會加一,直到相鄰兩像素值不同或者一行圖像結束時,停止加一,并且將當前統計結果cal_pixel和RAM中已經緩存的統計值進行累加,重新寫入到RAM中(也即wr_ram_data),同時需要使能RAM的寫操作。wr_ram_en。寫入RAM的地址,其實就是當前的灰度值。在這之中,需要注意從RAM中讀出數據具有1或者2個時鐘周期的Latency(根據IP核設置有關。

在FPGA的直方圖統計中,該部分是最重要的。完成了該時序圖,也就基本上完成了統計電路。

4bbb6a58-c01b-11ef-9310-92fbcf53809c.png

GET_HISTO狀態:

4bd43d30-c01b-11ef-9310-92fbcf53809c.png

該狀態下,就是完成對直方圖的統計結果的讀出。

程序設計

FPGA完成直方圖的設計,其實就是上面的三個時序圖的設計,完成了上述三個時序圖后,就能夠直方圖統計模塊。下面的這個模塊完成的是一個256*256大小的灰度圖的直方圖統計,若需要對其他大小的圖像進行直方圖統計,只需修改其中的參數即可。其實對于我的設計,每一行的像素個數是由上游模塊確定的,在本模塊中,只需指定圖像的高度即可,指定高度,也僅僅是為了將直方圖從RAM中讀出。

parameter IMG_WIDTH=256;

parameter IMG_HEIGHT=256;

`timescale 1ns / 1ps

module calculate_histogram(

input wire clk ,

inputwire rst ,

input wire pi_hsync,

inputwire pi_vsync,

inputwire pi_data_vld,

input wire [7:0]pi_data ,

output wire po_histo_vld,

output wire [31:0]po_histo_data

);

//==========================================

//parameter define

//==========================================

parameter IMG_WIDTH = 256 ;

parameter IMG_HEIGHT =256 ;

parameter GRAY_LEVEL= 256;//灰度級

parameter IDLE = 4'b0001;//空閑狀態

parameter CLEAR= 4'b0010;//清空RAM中數據狀態

parameter CALCULATE = 4'b0100;//統計圖像直方圖狀態

parameter GET_HISTO = 4'b1000;//輸出直方圖

//==========================================

//internal siganls

//==========================================

reg [3:0]state ;//狀態寄存器

reg [1:0]vsync_dd;//場同步信號寄存

//==========================================

//清空RAM階段

//==========================================

reg [8:0]cnt_clear ;

wireadd_cnt_clear;

wire end_cnt_clear;

reg clear_flag;//清空RAM指示信號

//==========================================

//統計直方圖階段

//==========================================

reg [12:0]cnt_row ;

wire add_cnt_row ;

wire end_cnt_row;

reg data_vld_dd0;//數據有效延時信號

reg data_vld_dd1;//數據有效延時信號

reg [7:0]pi_data_dd0;//有效數據延時

reg [7:0]pi_data_dd1;//有效數據延時

reg [31:0]cal_pixle;//相同的像素統計值

reg [31:0]cal_value ;//寫入RAM的統計值

reg cal_value_vld;//寫入RAM數據有效信號

reg cal_one_row_done;//統計一行圖像數據結束

wire [7:0]cal_wr_ram_addr;//統計狀態下寫RAM的地址

wire [7:0]cal_rd_ram_addr;//統計狀態下讀RAM的地址

//==========================================

//讀出數據階段

//==========================================

reg get_data_flag ;

reg [8:0]cnt_get ;

wire add_cnt_get ;

wire end_cnt_get ;

reg histo_data_vld ;

wire [31:0]histo_data ;

//==========================================

//Block RAM Related Signals

//==========================================

reg wr_ram_en ;//寫RAM使能信號

reg [7:0]wr_ram_addr;//寫RAM地址

reg [31:0]wr_ram_data ;//寫入RAM的數據

reg [7:0]rd_ram_addr ;//讀RAM的地址

wire[31:0]rd_ram_data;//從RAM中讀出的數據

assign po_histo_data = (histo_data_vld) ? histo_data : 32'd0;

assign po_histo_vld = histo_data_vld;

//----------------state machine describe------------------

always @(posedge clk) begin

if (rst==1'b1) begin

state <= IDLE ;

end

else begin

case(state)

IDLE : begin

//檢測到新的一幀圖像

if (vsync_dd[0] == 1'b1 && vsync_dd[1] == 1'b0) begin

state <= CLEAR;

end

else begin

state <= IDLE;

end

end

CLEAR : begin

//當前RAM中的數據已經清空

if (end_cnt_clear == 1'b1) begin

state <= CALCULATE;

end

else begin

state <= CLEAR;

end

end

CALCULATE : begin

//當前一幅圖像數據的灰度直方圖已經統計完成

if (end_cnt_row == 1'b1) begin

state <= GET_HISTO;

end

else begin

state <= CALCULATE;

end

end

GET_HISTO : begin

//將RAM中的直方圖數據全部讀出

if (end_cnt_get == 1'b1) begin

state <= IDLE;

end

else begin

state <= GET_HISTO;

end

end

default : begin

state <= IDLE;

end

endcase

end

end

//----------------vsync_dd------------------

//檢測一幀圖像

always @(posedge clk) begin

if (rst==1'b1) begin

vsync_dd <= 'd0;

end

else begin

vsync_dd <= {vsync_dd[0], pi_vsync};

end

end

//==========================================

//during the clear state

//==========================================

//----------------cnt_clear------------------

//用于清空RAM的計數器

always @(posedge clk) begin

if (rst == 1'b1) begin

cnt_clear <= 'd0;

end

else if (add_cnt_clear) begin

if(end_cnt_clear)

cnt_clear <= 'd0;

else

cnt_clear <= cnt_clear + 1'b1;

end

else begin

cnt_clear <= 'd0;

end

end

assign add_cnt_clear = state == CLEAR && wr_ram_en == 1'b1;

assign end_cnt_clear = add_cnt_clear &&cnt_clear == GRAY_LEVEL - 1;

//----------------clear_flag------------------

always @(posedge clk) begin

if (rst==1'b1) begin

clear_flag <= 1'b0;

end

else if (state == CLEAR ) begin

if (end_cnt_clear == 1'b1) begin

clear_flag <= 1'b0;

end

else begin

clear_flag <= 1'b1;

end

end

else begin

clear_flag <= 1'b0;

end

end

//==========================================

//during the calculate state

//==========================================

//----------------delay------------------

always @(posedge clk) begin

if (rst==1'b1) begin

data_vld_dd0 <= 'd0;

data_vld_dd1 <= 'd0;

pi_data_dd0 <= 'd0;

pi_data_dd1 <= 'd0;

end

else begin

data_vld_dd0 <= pi_data_vld;

data_vld_dd1 <= data_vld_dd0;

pi_data_dd0 <= pi_data;

pi_data_dd1 <= pi_data_dd0;

end

end

//----------------cal_pixle------------------

always @(posedge clk) begin

if (rst==1'b1) begin

cal_pixle <= 'd1;

end

else if (state == CALCULATE && data_vld_dd0 == 1'b1 ) begin

//相鄰兩個像素點的值不同,統計值回到1

if (pi_data != pi_data_dd0 ) begin

cal_pixle <= 'd1;

end

//一行圖形數據統計結束

else if (pi_data_vld == 1'b0 ) begin

cal_pixle <= 'd1;

end

//相鄰兩個像素點的值相同

else if (pi_data == pi_data_dd0) begin

cal_pixle <= cal_pixle + 1'b1;

end

end

else begin

cal_pixle <= 'd1;

end

end

//----------------cal_value------------------

//寫入RAM的數據

always @(posedge clk) begin

if (rst==1'b1) begin

cal_value <= 'd0;

cal_value_vld <= 1'b0;

end

else if (state == CALCULATE ) begin

//相鄰兩個像素值不同,將當前統計結果寫入

if (pi_data != pi_data_dd0 && data_vld_dd0 == 1'b1) begin

//從RAM中讀出的數據,有一拍的延時,這里保證了數據對齊

cal_value <= rd_ram_data + cal_pixle;

cal_value_vld <= 1'b1;

end

//一行圖像統計結束,將當前結果寫入

else if(pi_data_vld == 1'b0 && data_vld_dd0 == 1'b1)begin

cal_value <= rd_ram_data + cal_pixle;

cal_value_vld <= 1'b1;

end

else begin

cal_value <= 'd0;

cal_value_vld <= 1'b0;

end

end

else begin

cal_value <= 'd0;

cal_value_vld <= 1'b0;

end

end

//----------------cal_wr_ram_addr/cal_rd_ram_addr------------------

assign cal_wr_ram_addr = pi_data_dd1; //寫入數據RAM的地址

assign cal_rd_ram_addr = pi_data;//讀出數據RAM的地址

//----------------cal_one_row_done------------------

always @(posedge clk) begin

if (rst==1'b1) begin

cal_one_row_done <= 1'b0;

end

//一行圖像統計完成

else if (state == CALCULATE && pi_data_vld == 1'b0 && data_vld_dd0 == 1'b1) begin

cal_one_row_done <= 1'b1;

end

else begin

cal_one_row_done <= 1'b0;

end

end

//----------------cnt_row------------------

always @(posedge clk) begin

if (rst == 1'b1) begin

cnt_row <= 'd0;

end

else if (add_cnt_row) begin

if(end_cnt_row)

cnt_row <= 'd0;

else

cnt_row <= cnt_row + 1'b1;

end

end

assign add_cnt_row = cal_one_row_done == 1'b1;

assign end_cnt_row = add_cnt_row &&cnt_row == IMG_HEIGHT - 1;

//==========================================

//during get histogram data state

//==========================================

//----------------get_data_flag------------------

always @(posedge clk) begin

if (rst==1'b1) begin

get_data_flag <= 1'b0;

end

else if (state == GET_HISTO) begin

if (end_cnt_get == 1'b1) begin

get_data_flag <= 1'b0;

end

else begin

get_data_flag <= 1'b1;

end

end

else begin

get_data_flag <= 1'b0;

end

end

//----------------cnt_get------------------

always @(posedge clk) begin

if (rst == 1'b1) begin

cnt_get <= 'd0;

end

else if (add_cnt_get) begin

if(end_cnt_get)

cnt_get <= 'd0;

else

cnt_get <= cnt_get + 1'b1;

end

else begin

cnt_get <= 'd0;

end

end

assign add_cnt_get = get_data_flag == 1'b1;

assign end_cnt_get = add_cnt_get &&cnt_get == GRAY_LEVEL - 1;

//----------------histo_data_vld------------------

always @(posedge clk) begin

if (rst==1'b1) begin

histo_data_vld <= 1'b0;

end

else begin

histo_data_vld <= get_data_flag;

end

end

assign histo_data = (histo_data_vld) ? rd_ram_data : 'd0 ;

//==========================================

//signals that related to Block RAM

//==========================================

histogram_ram inst_bram_histo (

.clka(clk), // input wire clka

.wea(wr_ram_en), // input wire [0 : 0] wea

.addra(wr_ram_addr), // input wire [7 : 0] addra

.dina(wr_ram_data), // input wire [31 : 0] dina

.clkb(clk), // input wire clkb

.addrb(rd_ram_addr), // input wire [7 : 0] addrb

.doutb(rd_ram_data) // output wire [31 : 0] doutb

);

//----------------wr_ram_addr,wr_ram_data,wr_ram_en------------------

always @(*) begin

if (state == CLEAR) begin

wr_ram_addr = cnt_clear;

wr_ram_en = clear_flag;

wr_ram_data = 'd0;

end

else if (state == CALCULATE) begin

wr_ram_addr = cal_wr_ram_addr;

wr_ram_en = cal_value_vld;

wr_ram_data = cal_value;

end

else begin

wr_ram_addr = 'd0;

wr_ram_en = 1'b0;

wr_ram_data = 'd0;

end

end

//----------------rd_ram_addr------------------

always @(*) begin

if (state == CALCULATE) begin

rd_ram_addr = cal_rd_ram_addr;

end

else if (state == GET_HISTO) begin

rd_ram_addr = cnt_get;

end

else begin

rd_ram_addr = 'd0;

end

end

endmodule

仿真驗證

由于只是算法的一個驗證,我并不想使用太多的外部資源,使用片上的存儲資源即可。一個2562568bit大小的圖像并不會占用多少資源。圖像大小是256*256的灰度圖,在matlab中完成直方圖的統計,是十分簡單的,只需使用imhist這個函數即可。

4be67144-c01b-11ef-9310-92fbcf53809c.png

直方圖部分統計結果如下:

4bf7e51e-c01b-11ef-9310-92fbcf53809c.png

在modelsim中,對前面所設計的模塊進行仿真。仿真的結果如下:

4c084080-c01b-11ef-9310-92fbcf53809c.png

可以看到仿真的直方圖統計結果與matlab中的仿真結果相比一致。在Modelsim的Memory List中,也可以看到一幀圖像統計完成后,RAM中的結果,從結果中可以看到統計結果和matlab一致。

4c1d3f6c-c01b-11ef-9310-92fbcf53809c.png

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • FPGA
    +關注

    關注

    1629

    文章

    21753

    瀏覽量

    604159
  • 直方圖
    +關注

    關注

    0

    文章

    21

    瀏覽量

    7903

原文標題:FPGA圖像處理基礎----直方圖統計

文章出處:【微信號:gh_9d70b445f494,微信公眾號:FPGA設計論壇】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    基于直方圖算法進行FPGA架構設計

    引言 直方圖統計在圖像增強和目標檢測領域有重要應用,比如直方圖均衡,梯度直方圖。直方圖的不同種類和統計方法請見之前的文章。本章就是用
    的頭像 發表于 12-10 16:37 ?2817次閱讀

    基于FPGA實現分離用軟件的圖像處理系統設計

    灰度直方圖統計直方圖圖像的灰度分布統計的一種表示方法,統計目標圖像中各個灰度點的像素個數,很多對于圖像的調整算法都是基于此進行的;如何基于
    的頭像 發表于 04-04 10:32 ?1440次閱讀

    FPGA直方圖處理方法

    圖像直方圖用作數字圖像中色調分布的圖形表示。它繪制了每個色調值的像素數。通過查看特定圖像直方圖,觀看者將能夠一目了然地判斷整個色調分布。
    的頭像 發表于 12-15 09:20 ?1084次閱讀
    <b class='flag-5'>FPGA</b><b class='flag-5'>直方圖</b>處理方法

    一文帶你了解FPGA直方圖操作

    后面慢慢介紹,先重點介紹直方圖均衡。公眾號:OpenFPGA 直方圖統計及FPGA實現 從數學上來說,
    發表于 01-10 15:07

    基于FPGA的HDTV視頻圖像灰度直方圖統計算法設計

    本文介紹了如何在FPGA 中利用Block RAM 的特殊結構實現HDTV 視頻增強算法中灰度直方圖統計?;叶?b class='flag-5'>直方圖統計灰度直方圖統計是
    發表于 05-14 12:37

    有誰用FPGA做過數字圖像直方圖統計

    剛開始用FPGA做數字圖像處理,看了一些有關直方圖方面的資料但是感覺還是不太清晰,請問有誰做過求帶順便求推薦FPGA做數字圖像處理方面入門級
    發表于 08-21 09:48

    有誰用FPGA做過數字圖像直方圖統計

    剛開始用FPGA做數字圖像處理,看了一些有關直方圖方面的資料但是感覺還是不太清晰,請問有誰做過求帶順便求推薦FPGA做數字圖像處理方面入門級
    發表于 08-23 11:01

    基于FPGA圖像直方圖實時顯示

    ``基于FPGA圖像直方圖實時顯示 AT7_Xilinx開發板(USB3.0+LVDS)資料共享 騰訊鏈接:https://share.weiyun.com/5GQyKKc 百度網盤鏈接
    發表于 07-12 17:33

    基于FPGA圖像直方圖均衡處理

    放在projectzstar_ex66matlab文件夾下。3基于FPGA直方圖均衡處理工程文件夾at7_img_ex04at7.srcssources_1 ew下的laplace_transform.v模塊實現
    發表于 07-14 17:26

    【干貨】基于FPGA圖像處理(圖像增強)之直方圖均衡

    最近一直在用FPGA調圖像處理相關的算法,主要是集中在圖像增強和增晰方面。現在來介紹一個復雜度不高,但確實也還比較好用的圖像增強算法-直方圖
    發表于 12-08 09:40

    Labview圖像處理——直方圖介紹

    一、Labview直方圖程序介紹1、前面板2、程序框圖二、直方圖基本概念介紹圖像直方圖圖像的基本屬性之一,也是
    發表于 11-24 17:59

    基于FPGA的視頻圖像灰度信號直方圖均衡算法實現設計

    直方圖均衡作為一種基礎的圖像處理方法在很多領域得到應用,但大多是通過DSP或者CPU編程實現,其優點是靈活性比較高,調試方便,最大的缺點是很難做到實時或者準實時處理,這在某些領域是不可接受的。而使
    發表于 07-20 18:06 ?2699次閱讀
    基于<b class='flag-5'>FPGA</b>的視頻<b class='flag-5'>圖像</b>灰度信號<b class='flag-5'>直方圖</b>均衡算法<b class='flag-5'>實現</b>設計

    MATLAB如何實現圖像增強灰度變換直方圖均衡匹配

    在MATLAB數字圖像處理領域,如何實現空間域圖像增強的灰度變換,以及圖像直方圖的均衡和匹配(配準)?本文通過大量的圖片增強案例,從
    發表于 01-13 21:56 ?1.1w次閱讀
    MATLAB如何<b class='flag-5'>實現</b><b class='flag-5'>圖像</b>增強灰度變換<b class='flag-5'>直方圖</b>均衡匹配

    基于直方圖算法的FPGA設計架構

    直方圖統計在圖像增強和目標檢測領域有重要應用,比如直方圖均衡,梯度直方圖。直方圖的不同種類和統計方法請見之前的文章。本章就是用
    發表于 04-20 10:47 ?1200次閱讀
    基于<b class='flag-5'>直方圖</b>算法的<b class='flag-5'>FPGA</b>設計架構

    如何使用FPGA實現實時圖像增強算法

    FPGA,通過并行處理結構及流水線技術,可實時處理每秒50幀780×582×12bits的可見光圖像。在處理視頻的過程中,由前一幀圖像直方圖信息,來增強后一幀
    發表于 02-03 15:21 ?10次下載
    如何使用<b class='flag-5'>FPGA</b><b class='flag-5'>實現</b>實時<b class='flag-5'>圖像</b>增強算法
    大发888客户端的 软件| 斗牛棋牌游戏| 月亮城百家乐官网的玩法技巧和规则| 德州扑克底牌| 菲律宾百家乐官网开户| 威尼斯人娱乐场申博太阳城| 吕百家乐官网赢钱律| 百家乐官网赌博外挂| 太阳城网上投注| 澳门百家乐网上赌城| 百家乐官网那里可以玩| 百家乐官网牌机的破解法| 皇冠走地网| 大发888 这类平台| 百家乐国际娱乐场开户注册| 百家乐真钱路怎么看| 百家乐官网桌游| 建始县| 大发888 真钱娱乐平台| 真人百家乐蓝盾娱乐网| 哈尔滨百家乐官网赌场| 爱赢娱乐城开户| 大发888官网免费下载| 百家乐桌布呢布| 百家乐缆法排行榜| 百家乐官网平预测软件| 休闲百家乐官网的玩法技巧和规则 | 百家乐實戰後二穩賺| 24葬书-葬法| 百家乐官网科学打| 广州百家乐官网赌场娱乐网规则| 澳门百家乐官网十大缆| 百家乐官网技术秘籍| 靖安县| 百樂坊娱乐| 圣淘沙娱乐城真人赌博| 七乐亚洲娱乐| 华宝娱乐城| 百家乐官网网娱乐城| 百家乐官网真人游戏开户| 网上百家乐官网真实吗|