RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何在FPGA中正確處理浮點(diǎn)數(shù)運(yùn)算

FPGA設(shè)計(jì)論壇 ? 來源:FPGA設(shè)計(jì)論壇 ? 作者:FPGA設(shè)計(jì)論壇 ? 2022-03-18 11:03 ? 次閱讀

使用插值算法實(shí)現(xiàn)圖像縮放是數(shù)字圖像處理算法中經(jīng)常遇到的問題。我們經(jīng)常會將某種尺寸的圖像轉(zhuǎn)換為其他尺寸的圖像,如放大或者縮小圖像。由于在縮放的過程中會遇到浮點(diǎn)數(shù),如何在FPGA中正確的處理浮點(diǎn)數(shù)運(yùn)算是在FPGA中實(shí)現(xiàn)圖像縮放的關(guān)鍵。

一、插值算法原理

在圖像的縮放處理過程中,經(jīng)常會用到插值算法,常見的插值算法包括最鄰近插值,雙線性插值,雙三次線性插值,蘭索斯插值等方法。其中,雙線性插值由于折中的插值效果和實(shí)現(xiàn)復(fù)雜度,運(yùn)用較為廣泛。本文中僅介紹最臨近插值,重點(diǎn)討論如何在FPGA平臺上使用雙線性插值實(shí)現(xiàn)圖像的縮放。

1.1 最臨近插值---------最臨近插值介紹

講理論不如舉例子來的快,所以為了更好更快的理解最臨近插值,我們通過舉個(gè)簡單的例子來解釋最臨近插值是個(gè)什么神奇的東西。假如有一個(gè)3*3矩陣(一幅圖像其實(shí)就是矩陣),如下,我們把這個(gè)圖像叫做原圖(source image):

66 28 128

25 88 200

36 68 120

在矩陣中,坐標(biāo)(x,y)是這樣確定的,矩陣的左上角的頂點(diǎn)為原點(diǎn),從左到右為x軸,從上到下為y軸,如下所示:

24ef1ada-a667-11ec-952b-dac502259ad0.png

圖1 圖像中坐標(biāo)確定方式

假設(shè)我們想把這個(gè)3*3的原圖擴(kuò)大成4*4(我們把這個(gè)4*4的圖像叫做目的圖像destination image)我們該如何做呢?首先當(dāng)然是先把4*4的矩陣畫出來,如下所示:

????

? ???

????

????

矩陣畫出來后,接下來就要像未知數(shù)里填充像素點(diǎn)了。要填入的值如何計(jì)算呢,通過如下公式進(jìn)行計(jì)算:

24fed5f6-a667-11ec-952b-dac502259ad0.png

首先我們先來填充目的圖像 (0,0),套用上述公式可得到對應(yīng)原圖像的坐標(biāo)點(diǎn),srcX =0,srcY= 0;找到原圖像中對應(yīng)的坐標(biāo)點(diǎn)的像素值,將該像素填充到目的圖像中,如下

66 ???

????

????

接下來填充目的圖像(1,0),仍然套用公式,srcX = 3/4,srcY = 0,結(jié)果發(fā)現(xiàn)得到的結(jié)果居然有小數(shù),由于計(jì)算機(jī)中的像素點(diǎn)已經(jīng)是最小單位,像素的坐標(biāo)都是整數(shù),沒有小數(shù)。這是只需要按照四舍五入的思想將小數(shù)坐標(biāo)轉(zhuǎn)換為整數(shù)坐標(biāo)即可.所以(3/4,0) ≈ (1,0),把原圖像中(1,0)點(diǎn)的像素值填入目的圖像(1,0)坐標(biāo)處,得到如下結(jié)果:

66 28 ??

????

????

接下來重復(fù)上述過程,就可得到放大后的目的圖像,如下:

66 28 128 128

25 88 200 200

36 68 120 120

36 68 120 120

這種放大圖像的方法叫做最臨近插值算法,這是一種最基本最簡單的圖像縮放算法,該方法縮放后的圖像會出現(xiàn)失真現(xiàn)象。

1.2 雙線性插值算法

雙線性插值算法是一種比較好的縮放算法,它充分利用源圖中虛擬點(diǎn)四周的四個(gè)像素點(diǎn)來共同決定目標(biāo)圖形中的一個(gè)像素值,因此縮放效果要比最臨近插值算法好的多。

雙線性插值算法的描述如下:

對于目的圖像中的某點(diǎn)坐標(biāo),通過乘以縮放倍數(shù)(srcwidth/dstwidth、srcheight/dstheight)得到一個(gè)浮點(diǎn)坐標(biāo)(i+u,j+v)(其中i,j均為浮點(diǎn)坐標(biāo)的整數(shù)部分;u,v為浮點(diǎn)坐標(biāo)的小數(shù)部分),則這個(gè)浮點(diǎn)坐標(biāo)(i+u,j+v)處的像素值f(i+u,j+v)可以由原圖像中的坐標(biāo)點(diǎn)(i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所對應(yīng)的四個(gè)像素值來共同決定,即

2515c7a2-a667-11ec-952b-dac502259ad0.png

如1.1計(jì)算的目的像素坐標(biāo)(1,0)對應(yīng)源圖像的坐標(biāo)為(3/4,0),即 i = 0,u = 0.75;j = 0,v = 0;即目的圖像(1,0)處的像素值由源圖像中(0,0)、(1,0)、(0,1)(1,1)四個(gè)坐標(biāo)點(diǎn)對應(yīng)的像素值來確定,代入上述公式即可計(jì)算出(3/4,0)處的像素值。

看了上述內(nèi)容應(yīng)該對最臨近插值算法和雙線性插值算法有一定的了解,其基本原理應(yīng)該已經(jīng)掌握。

在網(wǎng)上刷博客發(fā)現(xiàn)有好多大佬講解了雙線性插值算法的優(yōu)化(雙線性插值算法總結(jié)),發(fā)現(xiàn)優(yōu)化以后縮放效果更好一些,優(yōu)化的具體細(xì)節(jié)就不再講解,具體優(yōu)化過程就是使用

252cb0a2-a667-11ec-952b-dac502259ad0.png

寫到這里雙線性插值算法的基本原理及優(yōu)化方式已經(jīng)基本講述完畢,那么,如何使用FPGA來實(shí)現(xiàn)雙線性插值呢?接下來我們進(jìn)行分析如何使用FPGA來實(shí)現(xiàn)雙線性插值。

二、雙線性插值的FPGA實(shí)現(xiàn)遇到的問題及解決方案

通過以上分析,我們會發(fā)現(xiàn)使用FPGA實(shí)現(xiàn)雙線性插值有以下難點(diǎn):

如何處理算法中出現(xiàn)的小數(shù);

如何同時(shí)求出相鄰的四個(gè)點(diǎn)的坐標(biāo)以及系數(shù);

如何使用這四個(gè)坐標(biāo)同時(shí)輸出相鄰的四個(gè)像素值;

接下來我們依次解決上述問題

2.1 如何處理算法中出現(xiàn)的小數(shù)

FPGA處理浮點(diǎn)數(shù)一般都是將浮點(diǎn)數(shù)轉(zhuǎn)化為定點(diǎn)數(shù)進(jìn)行處理,我們在求srcX、srcY也按照此思想。由于FPGA中沒法進(jìn)行小數(shù)表示,因此我們將srcX、srcY放大一定倍數(shù)變成整數(shù),這個(gè)整數(shù)的高n位表示坐標(biāo)點(diǎn)的整數(shù)部分(i或j),低m位表示小數(shù)部分(u或者v)。如我們要將30*30的圖像放大成64*64即srcwidth = srcheight = 30,dstwidth = dstheight =64(接下來工程實(shí)現(xiàn)也按照此例子來實(shí)現(xiàn))。

254257cc-a667-11ec-952b-dac502259ad0.png

位寬為16位。由于放大了128倍,所以srcX[6:0]、srcY[6:0]的低7位表示小數(shù)部分,即u = srcX[6:0],v=srcY[6:0];

其余高位部分表示整數(shù)部分,即i = srcX[15:7],j = srcY[15:7]。這樣就可以解決算法中出現(xiàn)的小數(shù)問題。

2.2如何同時(shí)求出相鄰的四個(gè)點(diǎn)的坐標(biāo)以及系數(shù)

由1.1可知,我們可以求出第一個(gè)坐標(biāo)點(diǎn)(i,j) = (srcX[15:7],srcY[15:7]),那么如何求出相鄰其它三個(gè)點(diǎn)的坐標(biāo)呢?接下來需要求出其余三點(diǎn)(i+1,j)、(i,j+1)、(i+1,j+1)的坐標(biāo),

(i+1,j) = (srcX[15:7] + 'd1,srcY[15:7]);

(i,j+1) = (srcX[15:7] ,srcY[15:7] * srcwidth);

(i+1,j+1) = (srcX[15:7] + 'd1 ,srcY[15:7] * srcwidth);

通過以上方式便可以很容易的求出四個(gè)點(diǎn)的坐標(biāo)。接下來就要考慮如何使用這四個(gè)坐標(biāo)同時(shí)讀取四個(gè)對應(yīng)的像素值。

同時(shí)我們定義四個(gè)位寬為8位的系數(shù)變量coefficient1[7:0]、coefficient2[7:0]、coefficient3[7:0]、coefficient4[7:0],通過

coefficient1[7:0] = ‘d128 - coefficient2;(由于系數(shù)放大了128倍,所以是128-系數(shù)2,對應(yīng)1-u)

coefficient2[7:0] = {1'b0,u} = {1'b0,srcX[6:0]};

coefficient3[7:0] = ‘d128 - coefficient4;(由于系數(shù)放大了128倍,所以是128-系數(shù)4,對應(yīng)1-v)

coefficient4[7:0] = {1'b0,v} = {1'b0,srcY[6:0]};

為什么定義的系數(shù)變量為8位而不是7位,這是因?yàn)橄禂?shù)變量的最大值為’d128,8位位寬才能表示‘d128。

接下來使用上述求出的四個(gè)坐標(biāo)求出對應(yīng)的坐標(biāo)的像素值,再套用公式

25576a9a-a667-11ec-952b-dac502259ad0.png

即可求出目的圖像對應(yīng)位置放大后的像素值。

通過以上分析,可以將公式變形為如下形式,求出對應(yīng)點(diǎn)的像素值后直接使用以下公式即可:

256bb310-a667-11ec-952b-dac502259ad0.png

求得該像素值之后還需要將該像素值除以128*128才是所得的實(shí)際結(jié)果。

2.3 如何使用這四個(gè)坐標(biāo)同時(shí)輸出相鄰的四個(gè)像素值

通過2.2分析可以同時(shí)求出四個(gè)像素點(diǎn)的坐標(biāo),但是如何通過這四個(gè)坐標(biāo)同時(shí)求出對應(yīng)的像素值呢?由于待縮放的數(shù)據(jù)是先緩存進(jìn)RAM的,如果待縮放的圖像數(shù)據(jù)僅僅緩存在一個(gè)RAM里,是不可能通過四個(gè)像素點(diǎn)的坐標(biāo)同時(shí)訪問這個(gè)RAM,即不可能同時(shí)求出對應(yīng)的四個(gè)像素點(diǎn)的值。所以,可以通過犧牲面積換取速度的方式,即將RAM復(fù)制4次,每個(gè)RAM都緩存整個(gè)待縮放的圖像數(shù)據(jù),這樣四個(gè)像素點(diǎn)的坐標(biāo)就可以通過訪問不同的RAM來同時(shí)訪問對應(yīng)的四個(gè)像素值了。雖然犧牲了FPGA內(nèi)部的存儲資源,但是提升了雙線性插值算法的速度。

三 、雙線性插值的FPGA實(shí)現(xiàn)

通過第二節(jié)內(nèi)容的分析可知,使用FPGA實(shí)現(xiàn)雙線性插值主要包含以下三個(gè)模塊:生成目的圖像對應(yīng)原圖像坐標(biāo)和系數(shù)模塊、待處理圖像緩存模塊、雙線性插值運(yùn)算單元模塊。其數(shù)據(jù)流向圖如下圖所示:

257eb168-a667-11ec-952b-dac502259ad0.png

圖2 FPGA實(shí)現(xiàn)雙線性插值數(shù)據(jù)流向圖

圖2中虛框部分是圖像裁剪模塊,這里不討論圖像裁剪功能的實(shí)現(xiàn),僅僅討論圖像縮放功能的實(shí)現(xiàn)。

整個(gè)實(shí)現(xiàn)的過程描述如下:

上位機(jī)將待縮放的圖像數(shù)據(jù)送進(jìn)待處理圖像緩存模塊,該模塊將待處理的數(shù)據(jù)復(fù)制四份

待1中數(shù)據(jù)緩存完畢,開始生成目的圖像對應(yīng)原圖像坐標(biāo)和系數(shù);

將生成的坐標(biāo)送給待處理圖像緩存模塊進(jìn)行數(shù)據(jù)的訪問,將讀取的數(shù)據(jù)送給雙線性插值運(yùn)算單元;

將生成的系數(shù)送給雙線性插值運(yùn)算單元,與相應(yīng)的像素值進(jìn)行數(shù)學(xué)運(yùn)算,實(shí)現(xiàn)雙線性插值功能。

實(shí)現(xiàn)雙線性插值功能的代碼如下所示:

頂層模塊:

module top(input clk,

output [7:0]doutb,

output de_o,

output v_sync,

output h_sync

);

parameter [7:0]src_width = 'd30;

wire [7:0]coordinate_x;

wire [7:0]coordinate_y;

wire start;

wire en_b;

//

wire [7:0]coefficient1;

wire [7:0]coefficient2;

wire [7:0]coefficient3;

wire [7:0]coefficient4;

wire [7:0]doutbx;

wire [7:0]doutbx1;

wire [7:0]doutby;

wire [7:0]doutby1;

// Instantiate the module

sourceimage_virtualcoordinate coordinate (

.clk(clk),

.src_width(src_width),

.start(start),

.coordinate_x(coordinate_x),

.coordinate_y(coordinate_y),

.coefficient1(coefficient1),

.coefficient2(coefficient2),

.coefficient3(coefficient3),

.coefficient4(coefficient4),

.en(en_b)

);

//

wire [7:0]dina;

wire valid_zsc;

// Instantiate the module

self_generate self_generate (

.clk(clk),

.data_o(dina),

.valid_zsc(valid_zsc)

);

// Instantiate the module

mem_control mem_control (

.clk_wr(clk),

.clk_rd(clk),

.coordinate_x(coordinate_x), /

.coordinate_y(coordinate_y),

.din_a(dina), /

.en_a(valid_zsc), ///

.src_width(src_width), //

.en_b(en_b), ///

.doutbx(doutbx),

.doutbx1(doutbx1),

.doutby(doutby),

.doutby1(doutby1),

.start(start)

);

///

wire [7:0] data_o;

wire en_o;

// Instantiate the module

arithmetic_unit arithmetic_unit (

.clk(clk),

.coefficient1(coefficient1),

.coefficient2(coefficient2),

.coefficient3(coefficient3),

.coefficient4(coefficient4),

.en_b(en_b),

.doutbx(doutbx),

.doutbx1(doutbx1),

.doutby(doutby),

.doutby1(doutby1),

.data_o(data_o),

.en_o(en_o)

);

wire de;

wire start_en;

// Instantiate the module

mem_64multi_64 mem_64multi_64 (

.clk(clk),

.dina(data_o),

.ena(en_o),

.enb(enb),

.start_en(start_en),

.doutb(doutb)

);

// Instantiate the module

vesa_out vesa_out (

.clk(clk),

.start_en(start_en),

.v_sync(v_sync),

.h_sync(h_sync),

.de(enb),

.de_o(de_o)

);

endmodule

生成對應(yīng)的坐標(biāo)和系數(shù)模塊:

//該模塊是用來計(jì)算源圖像的虛擬坐標(biāo),由于源圖像和目的圖像都是正方形,所以只考慮一個(gè)縮放倍數(shù)即可

//

module sourceimage_virtualcoordinate(input clk,

input [7:0]src_width,/src_width = src_height

input [5:0]dest_width,/dest_width = dest_height = 'd64

input start,///數(shù)據(jù)緩存滿了以后才可以進(jìn)行計(jì)算

output [7:0]coordinate_x,

output [7:0]coordinate_y,

output [7:0]coefficient1,

output [7:0]coefficient2,

output [7:0]coefficient3,

output [7:0]coefficient4,

output reg en = 'd0

);

/高電平有效rst

reg [1:0]cnt = 'd0;

always @(posedge clk)

if(cnt == 'd3)

cnt <= 'd3;

else

cnt <= cnt + 'd1;

reg rst = 'd1;

always @(posedge clk)

if(cnt == 'd3)

rst <= 'd0;

else

rst <= 'd1;

//

localparam [1:0]IDLE = 2'b01;

localparam [1:0]START = 2'b10;

/

reg[1:0]next_state = 'd0;

reg[1:0]current_state = 'd0;

always @(posedge clk)

if(rst)高電平復(fù)位

current_state <= IDLE;

else

current_state <= next_state;

//

reg finish = 'd0;

always @(*)

case(current_state)

IDLE:begin

if(start)

next_state = START;

else

next_state = IDLE;

end

START:begin

if(finish)

next_state = IDLE;

else

next_state = START;

end

default:next_state = IDLE;

endcase

//

//reg en = 'd0;//目的坐標(biāo)計(jì)數(shù)器使能

always @(*)

case(current_state)

IDLE:begin

en = 'd0;

end

START:begin

en = 'd1;

end

default:en = 'd0;

endcase

///對目的圖像坐標(biāo)進(jìn)行計(jì)數(shù)

reg[5:0] pos_x = 'd0;/列計(jì)數(shù)

always@(posedge clk)

if(en)begin

if(pos_x == 'd63)

pos_x <= 'd0;

else

pos_x <= pos_x + 'd1;

end

else

pos_x <= pos_x;

reg[5:0] pos_y = 'd0;行計(jì)數(shù)

always @(posedge clk)

if(pos_x == 'd63)

pos_y <= pos_y + 'd1;?

else

pos_y <= pos_y;

//結(jié)束標(biāo)志

always@(posedge clk)

if((pos_x == 'd62)&&(pos_y == 'd63))///是pos_x==62而不是63

finish <= 'd1;

else

finish <= 'd0;

//通過pos_x、pos_y可以計(jì)算對應(yīng)源圖像位置的虛擬坐標(biāo)

reg [15:0]src_x = 'd0;///高8位表示整數(shù),低8位表示小數(shù)

reg [15:0]src_y = 'd0;///高8位表示整數(shù),低8位表示小數(shù)

//assign src_x = ((pos_x<<1 + 'd1)*src_width - 'd64 > 'd0)?(pos_x<<1 + 'd1)*src_width - 'd64:'d64-(pos_x<<1 + 'd1)*src_width;

//assign src_y = ((pos_y<<1 + 'd1)*src_width - 'd64 > 'd0)?(pos_y<<1 + 'd1)*src_width - 'd64:'d64-(pos_y<<1 + 'd1)*src_width;

wire [7:0]pos_xq;

wire [7:0]pos_yq;

assign pos_xq = pos_x<<1;

assign pos_yq = pos_y<<1;

///

always @(posedge clk)

if(pos_x == 'd0)begin

if(src_width > 'd64)

src_x <= src_width - 'd64;

else

src_x <= 'd64 - src_width;

end

else begin

if((pos_xq + 'd1)*src_width > 'd64)

src_x <= (pos_xq + 'd1)*src_width - 'd64;

else

src_x <= 'd64 - (pos_xq + 'd1)*src_width;

end

always @(posedge clk)

if(pos_y == 'd0)begin

if(src_width > 'd64)

src_y <= src_width - 'd64;

else

src_y <= 'd64 - src_width;

end

else begin

if((pos_yq + 'd1)*src_width > 'd64)

src_y <= (pos_yq + 'd1)*src_width - 'd64;

else

src_y <= 'd64 - (pos_yq + 'd1)*src_width;

end

//生成對應(yīng)坐標(biāo)

//wire [6:0]coordinate_x;

//wire [6:0]coordinate_y;

assign coordinate_x = src_x[14:7];

assign coordinate_y = src_y[14:7];

//生成對應(yīng)系數(shù)

//wire [7:0]coefficient1;

//wire [7:0]coefficient2;

//wire [7:0]coefficient3;

//wire [7:0]coefficient4;

assign coefficient2 = {1'b0,src_x[6:0]};

assign coefficient1 = 'd128 - coefficient2;

assign coefficient4 = {1'b0,src_y[6:0]};

assign coefficient3 = 'd128 - coefficient4;

endmodule

模擬上位機(jī)產(chǎn)生待縮放的數(shù)據(jù)模塊:

//模擬的輸入圖像指標(biāo)是30*30@56Hz

//

module self_generate(input clk,

output reg[7:0]data_o = 'd0,

output reg valid_zsc = 'd0

);

reg [10:0] cnt_h = 'd0;

reg [10:0] cnt_v = 'd0;

always @(posedge clk)

if(cnt_h == 'd799)

cnt_h <= 'd0;

else

cnt_h <= cnt_h + 'd1;

always @(posedge clk)

if(cnt_h == 'd799)begin

if(cnt_v == 'd524)

cnt_v <= 'd0;

else

cnt_v <= cnt_v + 'd1;

end

else

cnt_v <= cnt_v;

//reg dInValid = 'd0;

wire valid_1;

assign valid_1 = (((cnt_h >='d144)&&(cnt_h <='d173))&&((cnt_v >='d35)&&(cnt_v <='d64)))?'d1:'d0;/有效數(shù)據(jù)共30個(gè)

///

always @(posedge clk)

if(valid_1)

//if((cnt_h >='d144)&&(cnt_h <='d176))

//data_o <= 'hff;

//else if((cnt_h >='d177)&&(cnt_h <='d209))

//data_o <= 'h0f;

//else if((cnt_h >='d210)&&(cnt_h <='d242))

//data_o <= 'hff;

//else if((cnt_h >='d243)&&(cnt_h <='d275))

//data_o <= 'h0f;

//else if((cnt_h >='d276)&&(cnt_h <='d308))

//data_o <= 'hff;

//else if((cnt_h >='d309)&&(cnt_h <='d341))

//data_o <= 'h0f;

//else if((cnt_h >='d342)&&(cnt_h <='d374))

//data_o <= 'hff;

//else

//data_o <= 'h0f;

data_o <= data_o + 'd1;

else

data_o <= 'd0;

always @(posedge clk)

valid_zsc <= valid_1;

endmodule

待處理圖像緩存模塊:

module mem_control(input clk_wr,

input clk_rd,

input [7:0]coordinate_x,

input [7:0]coordinate_y,

input [7:0]din_a,

input en_a,

input [7:0]src_width,

input en_b,

output [7:0]doutbx,

output [7:0]doutbx1,

output [7:0]doutby,

output [7:0]doutby1,

output reg start = 'd0

);

wire [15:0]size;

assign size = src_width*src_width - 'd1;

wire [7:0]width;

assign width = src_width - 'd1;

//把數(shù)據(jù)復(fù)制四份,通過犧牲面積換取速度

reg [15:0]address_a = 'd0;

always @(posedge clk_wr)

if(en_a)begin

if(address_a == size)

address_a <= 'd0;

else

address_a <= address_a + 'd1;

end

else

address_a <= address_a;

如果數(shù)據(jù)緩存完畢,產(chǎn)生start標(biāo)志信號,表示可以進(jìn)行數(shù)據(jù)處理

always @(posedge clk_wr)

if(address_a == size)

start <= 'd1;

else

start <= 'd0;

wire [15:0]address_bx;

wire [15:0]address_bx1;

wire [15:0]address_by;

wire [15:0]address_by1;

assign address_bx = (coordinate_x == width)?coordinate_x + coordinate_y*src_width - 'd1:coordinate_x + coordinate_y*src_width;

assign address_bx1 = (coordinate_x == width)?address_bx:address_bx + 'd1;

assign address_by = (coordinate_y==width)?address_bx:coordinate_x + (coordinate_y+'d1)*src_width;

assign address_by1 = (coordinate_x == width)?address_by:address_by + 'd1;

// Instantiate the module

ram_module ram_1 (

.clk_wr(clk_wr),

.address_a(address_a),

.en_a(en_a),

.din_a(din_a),

.clk_rd(clk_rd),

.address_b(address_bx),

.en_b(en_b),

.doutb(doutbx)

);

// Instantiate the module

ram_module ram_2 (

.clk_wr(clk_wr),

.address_a(address_a),

.en_a(en_a),

.din_a(din_a),

.clk_rd(clk_rd),

.address_b(address_bx1),

.en_b(en_b),

.doutb(doutbx1)

);

// Instantiate the module

ram_module ram_3 (

.clk_wr(clk_wr),

.address_a(address_a),

.en_a(en_a),

.din_a(din_a),

.clk_rd(clk_rd),

.address_b(address_by),

.en_b(en_b),

.doutb(doutby)

);

// Instantiate the module

ram_module ram_4 (

.clk_wr(clk_wr),

.address_a(address_a),

.en_a(en_a),

.din_a(din_a),

.clk_rd(clk_rd),

.address_b(address_by1),

.en_b(en_b),

.doutb(doutby1)

);

endmodule

雙線性插值運(yùn)算單元模塊

module arithmetic_unit(input clk,

input [7:0]coefficient1,

input [7:0]coefficient2,

input [7:0]coefficient3,

input [7:0]coefficient4,

input en_b,

input [7:0]doutbx,

input [7:0]doutbx1,

input [7:0]doutby,

input [7:0]doutby1,

output reg[7:0]data_o = 'd0,

output reg en_o = 'd0

);

wire [23:0]data_1;

wire [23:0]data_2;

wire [23:0]data_3;

wire [23:0]data_4;

assign data_1 = coefficient1*coefficient3*doutbx;

/

assign data_2 = coefficient2*coefficient3*doutbx1;

/

assign data_3 = coefficient1*coefficient4*doutby;

assign data_4 = coefficient2*coefficient4*doutby1;

wire [23:0]data_a;

assign data_a = data_1 + data_2;

reg [23:0]data_aq = 'd0;

always @(posedge clk)

data_aq <= data_a;

wire [23:0]data_b;

assign data_b = data_3 + data_4;

reg [23:0]data_bq = 'd0;

always @(posedge clk)

data_bq <= data_b;

wire [23:0]data_oq;

assign data_oq = data_aq + data_bq;

always @(posedge clk)

data_o <= data_oq[21:14];

//en_b

reg en_b_q;

reg en_b_q1;

always@(posedge clk)begin

en_b_q <= en_b;

en_b_q1 <= en_b_q;

en_o <= en_b_q1;

end

endmodule

對運(yùn)算后的數(shù)據(jù)進(jìn)行緩存模塊:

module mem_64multi_64(input clk,

input [7:0]dina,

input ena,

input enb,

output reg start_en = 'd0,

output [7:0]doutb

);

/ram write

reg ena_q = 'd0;

always @(posedge clk)

ena_q <= ena;

reg [11:0]addra = 'd0;

always @(posedge clk)

if(ena_q)begin

if(addra == 'd4095)

addra <= 'd0;

else

addra <= addra + 'd1;

end

else

addra <= addra;

//ram read

reg [11:0]addrb = 'd0;

always @(posedge clk)

if(enb)begin

if(addrb == 'd4095)

addrb <= 'd0;

else

addrb <= addrb + 'd1;

end

else

addrb <= addrb;

//

always @(posedge clk)

if(addra == 'd4095)

start_en <= 'd1;

else

start_en <= start_en;

//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG

ram64multi64 ram64multi64 (

.clka(clk), // input clka

.ena(ena_q), // input ena

.wea(1'b1), // input [0 : 0] wea

.addra(addra), // input [11 : 0] addra

.dina(dina), // input [7 : 0] dina

.clkb(clk), // input clkb

.enb(enb), // input enb

.addrb(addrb), // input [11 : 0] addrb

.doutb(doutb) // output [7 : 0] doutb

);

endmodule

輸出顯示模塊:

module vesa_out( input clk,

input start_en,

output v_sync,

output h_sync,

output de,

output reg de_o = 'd0

);

reg [10:0] cnt_h = 'd0;

reg [10:0] cnt_v = 'd0;

always @(posedge clk)

if(start_en)begin

if(cnt_h == 'd799)

cnt_h <= 'd0;

else

cnt_h <= cnt_h + 'd1;

end

else

cnt_h <= cnt_h;

always @(posedge clk)

if(cnt_h == 'd799)begin

if(cnt_v == 'd524)

cnt_v <= 'd0;

else

cnt_v <= cnt_v + 'd1;

end

else

cnt_v <= cnt_v;

assign de = (((cnt_h >='d200)&&(cnt_h <='d263))&&((cnt_v >='d135)&&(cnt_v <='d198)))?'d1:'d0;

always @(posedge clk)

de_o <= de;

assign h_sync = (cnt_h >= 'd97)?'d1:'d0;

assign v_sync = (cnt_v >= 'd3)?'d1:'d0;

endmodule

仿真模塊:

module top_tb;

// Inputs

reg clk;

// Outputs

wire [7:0] doutb;

wire de_o;

wire v_sync;

wire h_sync;

// Instantiate the Unit Under Test (UUT)

top uut (

.clk(clk),

.doutb(doutb),

.de_o(de_o),

.v_sync(v_sync),

.h_sync(h_sync)

);

initial begin

// Initialize Inputs

clk = 0;

// Wait 100 ns for global reset to finish

#100;

// Add stimulus here

end

always #5 clk = !clk;

endmodule

仿真結(jié)果如下:該仿真結(jié)果處理的是30*30大小圖像縮放成64*64圖像,輸入圖像的每一行數(shù)據(jù)都是1,2,3···30,仿真結(jié)果如下所示:

2594ba44-a667-11ec-952b-dac502259ad0.png

經(jīng)與matlab運(yùn)算結(jié)果做對比,結(jié)果完全一致。 ?

原文標(biāo)題:FPGA學(xué)習(xí)-基于FPGA的圖像實(shí)時(shí)縮放

文章出處:【微信公眾號:FPGA設(shè)計(jì)論壇】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

審核編輯:彭菁

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • FPGA
    +關(guān)注

    關(guān)注

    1629

    文章

    21729

    瀏覽量

    602986
  • 計(jì)算機(jī)
    +關(guān)注

    關(guān)注

    19

    文章

    7488

    瀏覽量

    87849
  • 數(shù)字圖像處理
    +關(guān)注

    關(guān)注

    7

    文章

    103

    瀏覽量

    18917

原文標(biāo)題:FPGA學(xué)習(xí)-基于FPGA的圖像實(shí)時(shí)縮放

文章出處:【微信號:gh_9d70b445f494,微信公眾號:FPGA設(shè)計(jì)論壇】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    基于FPGA實(shí)現(xiàn)的自定義浮點(diǎn)數(shù)

    基于FPGA實(shí)現(xiàn)各種設(shè)計(jì)的首要前提是理解并掌握數(shù)字的表示方法,計(jì)算機(jī)中的數(shù)字表示方法有兩種:定點(diǎn)數(shù)表示法和浮點(diǎn)數(shù)表示方法。
    發(fā)表于 10-10 10:30 ?1446次閱讀

    FPGA verilog浮點(diǎn)數(shù)運(yùn)算

    求用verilog實(shí)現(xiàn)浮點(diǎn)數(shù)運(yùn)算的資料,謝謝
    發(fā)表于 12-17 21:15

    點(diǎn)數(shù)浮點(diǎn)數(shù)的區(qū)別是什么

    點(diǎn)數(shù)浮點(diǎn)數(shù)的區(qū)別目的:理解定點(diǎn)數(shù)浮點(diǎn)數(shù)在傅里葉變換(FFT)的實(shí)際應(yīng)用中的選擇單片機(jī)中如果需要進(jìn)行一定的運(yùn)算(常見的傅里葉變換)時(shí),需
    發(fā)表于 02-21 07:22

    何在GCC中為具有FPU的Cortex M4啟用硬件浮點(diǎn)數(shù)學(xué)運(yùn)算呢?

    何在GCC中為具有FPU的Cortex M4啟用硬件浮點(diǎn)數(shù)學(xué)運(yùn)算呢?
    發(fā)表于 08-26 14:43

    擴(kuò)充浮點(diǎn)運(yùn)算集是否需要自己在FPGA板子上設(shè)置一個(gè)定點(diǎn)數(shù)轉(zhuǎn)為浮點(diǎn)數(shù)的部分?

    擴(kuò)充浮點(diǎn)運(yùn)算集的時(shí)候,是否需要自己在FPGA板子上設(shè)置一個(gè)定點(diǎn)數(shù)轉(zhuǎn)為浮點(diǎn)數(shù)的部分?
    發(fā)表于 08-11 09:13

    浮點(diǎn)數(shù)運(yùn)算怎么轉(zhuǎn)換成整數(shù)運(yùn)算?

    浮點(diǎn)數(shù)運(yùn)算怎么轉(zhuǎn)換成整數(shù)運(yùn)算
    發(fā)表于 10-12 06:31

    浮點(diǎn)數(shù)的表示方法

    浮點(diǎn)數(shù)的表示方法  浮點(diǎn)數(shù),是指小數(shù)點(diǎn)在數(shù)據(jù)中的位置可以左右移動的數(shù)據(jù)。它通常被表示成:    N = M* RE  這里的M(Mantissa)被稱為浮點(diǎn)數(shù)
    發(fā)表于 10-13 17:13 ?1.6w次閱讀
    <b class='flag-5'>浮點(diǎn)數(shù)</b>的表示方法

    浮點(diǎn)數(shù)常用的編碼方法

    浮點(diǎn)數(shù)常用的編碼方法  前面已經(jīng)說到,在計(jì)算機(jī)內(nèi),浮點(diǎn)數(shù)被表示為如下格式:    通常情況
    發(fā)表于 10-13 17:21 ?4482次閱讀
    <b class='flag-5'>浮點(diǎn)數(shù)</b>常用的編碼方法

    單片機(jī)浮點(diǎn)數(shù)運(yùn)算的源碼設(shè)計(jì)

    單片機(jī)執(zhí)行程序的過程,實(shí)際上就是執(zhí)行我們所編制程序的過程。即逐條指令的過程。本文詳細(xì)介紹了浮點(diǎn)數(shù)在單片機(jī)中的表示方式和匯編子程序,浮點(diǎn)數(shù)比定點(diǎn)數(shù)加減法要困難,但是克服了定點(diǎn)數(shù)表示范圍小
    的頭像 發(fā)表于 03-07 15:19 ?1w次閱讀
    單片機(jī)<b class='flag-5'>浮點(diǎn)數(shù)</b><b class='flag-5'>運(yùn)算</b>的源碼設(shè)計(jì)

    點(diǎn)數(shù)浮點(diǎn)數(shù)在STM32單片機(jī)中使用傅里葉(FFT)變換的理解

    點(diǎn)數(shù)浮點(diǎn)數(shù)的區(qū)別目的:理解定點(diǎn)數(shù)浮點(diǎn)數(shù)在傅里葉變換(FFT)的實(shí)際應(yīng)用中的選擇單片機(jī)中如果需要進(jìn)行一定的運(yùn)算(常見的傅里葉變換)時(shí),需
    發(fā)表于 12-24 19:22 ?16次下載
    定<b class='flag-5'>點(diǎn)數(shù)</b>和<b class='flag-5'>浮點(diǎn)數(shù)</b>在STM32單片機(jī)中使用傅里葉(FFT)變換的理解

    談一談浮點(diǎn)數(shù)的精度問題

    還是要從浮點(diǎn)數(shù)的存儲和標(biāo)識出發(fā)來處理該問題,既然浮點(diǎn)數(shù)天然就存在一定的誤差,而有時(shí)候計(jì)算又無法獲得唯一的數(shù)值,如下圖所示,浮點(diǎn)數(shù)計(jì)算出來的實(shí)軸上的值都會因?yàn)?/div>
    的頭像 發(fā)表于 08-11 14:28 ?4584次閱讀
    談一談<b class='flag-5'>浮點(diǎn)數(shù)</b>的精度問題

    什么是浮點(diǎn)數(shù)?浮點(diǎn)數(shù)在內(nèi)存中的存儲

    浮點(diǎn)型簡單講就是實(shí)數(shù)的意思。浮點(diǎn)數(shù)在計(jì)算機(jī)中用以近似表示任意某個(gè)實(shí)數(shù)。
    的頭像 發(fā)表于 11-09 11:07 ?5337次閱讀
    什么是<b class='flag-5'>浮點(diǎn)數(shù)</b>?<b class='flag-5'>浮點(diǎn)數(shù)</b>在內(nèi)存中的存儲

    什么是浮點(diǎn)數(shù)

    Python數(shù)據(jù)類型第一種:字符串(str)。 Python數(shù)據(jù)類型第二種:整數(shù)(int)。 Python數(shù)據(jù)類型第三種:浮點(diǎn)數(shù)浮點(diǎn)數(shù)的英文名是float,浮點(diǎn)數(shù)沒有簡寫。
    的頭像 發(fā)表于 02-23 14:58 ?4602次閱讀

    FPGA浮點(diǎn)數(shù)表示及計(jì)算機(jī)數(shù)值表示規(guī)則

    點(diǎn)數(shù)硬件實(shí)現(xiàn)簡單,但表示的范圍有限,且部分的小數(shù)運(yùn)算IP核只支持浮點(diǎn)數(shù)運(yùn)算,因此這里還需要提到浮點(diǎn)數(shù)的相關(guān)內(nèi)容。
    發(fā)表于 06-16 15:41 ?1411次閱讀
    <b class='flag-5'>FPGA</b><b class='flag-5'>浮點(diǎn)數(shù)</b>表示及計(jì)算機(jī)數(shù)值表示規(guī)則

    modbus浮點(diǎn)數(shù)怎么讀取

    Modbus是一種通信協(xié)議,常用于工業(yè)自動化系統(tǒng)中的設(shè)備之間的通信。它支持多種數(shù)據(jù)類型,包括整數(shù)、浮點(diǎn)數(shù)、字符串等。浮點(diǎn)數(shù)在工業(yè)領(lǐng)域中廣泛應(yīng)用,因此了解如何讀取和處理Modbus浮點(diǎn)數(shù)
    的頭像 發(fā)表于 12-28 14:38 ?6200次閱讀
    RM新时代网站-首页