有符號浮點運算的基本步驟:以雙線性插值為例

NoNounknow發表於2024-08-16

參考:韓彬的影像處理書、無雙軟體學院方法。

步驟一:無損定點化

浮點數在硬體計算中首先需要做的便是定點化,一般是左移一定位寬,可以是2048或4096;

這個過程要注意保障無損;

步驟二:運算和位寬匹配;

要確定所有參與計算的數小數位位寬是匹配的,否則無法進行任何層次的計算;

需要特別注意很多小數在計算的時候也需要定點化,例如:

always@(posedge clk)
    if(rst)    
        src_xf0 <= 'd0;
    else if(dst_de==1'b1)
        src_xf0 <= {dst_hcnt,2'd0} + 2;
    else
        src_xf0 <= 'd0;

這裡做的計算是修改後的雙線性插值中的中心對齊操作;

0.5左移兩位變成了2;

步驟三:相乘後的截位處理

發生了相乘操作以後,整數和小數位寬都會發生變化,注意匹配;

此處小數位位寬為12,0.5左移12位後為2048;

//fix16_2 * fix16_12  = fix32_14        
always@(posedge clk)
    if(rst)    
        src_xf1 <= 'd0;
    else
        src_xf1 <= src_xf0*sx;
//fix26_12 - fix12_12  = fix26_12 可能為負數
always@(posedge clk)
    if(rst)    
        src_xf2 <= 'd0;
    else
        src_xf2 <= src_xf1[27:2] - 2048;

步驟四:加減處理後的正負判斷;

目前為止的公式:src_x = (dst_x + 0.5) * scale_x - 0.5

always@(posedge clk)
    if(rst)    
        src_xf3 <= 'd0;
    else
        src_xf3 <= src_xf2;        

always@(posedge clk)
    if(rst)    
        src_x0 <= 'd0;
    else if(src_xf2[25]==1'b1)
        src_x0 <= 'd0;        
    else
        src_x0 <= src_xf2[25:12];

在這裡的運算中,相減可能出現負數,這是顯而易見的,但是此處xf2指的是座標;(當然,相加如果座標大於影像尺寸也會做匹配處理)

座標不能有負數,最小是0;

在sobel裡我也做了類似的操作;

always@(posedge clk)
    if(rst)    
        region_type <= 0;
    else if(src_x0>=SRC_IW-1&&src_y0>=SRC_IH-1&&src_xy_de==1'b1)
        region_type <= 1;
    else if(src_y0>=SRC_IH-1&&src_xy_de==1'b1)
        region_type <= 2;
    else if(src_x0>=SRC_IW-1&&src_xy_de==1'b1)    
        region_type <= 3;
    else
        region_type <= 4;

步驟五:符號化:

這裡計算的就不是座標,而是實際的畫素值了;

實際的畫素值也沒有負值,但是這裡計算出的資料可以用來後續對畫素的增減,重要性判斷,所以有正有負;

//fix26_12 - fix26_12 = fix26_12
always@(posedge clk)
    if(rst)    
        v <= 'd0;
    else
        v <= $signed(src_xf3) - $signed({src_x0,12'd0});    

後面沒有太多指的說的,只需要記住實際使用的時候取出整數位資料;

還有就是小數位第一位是1代表了0.5,如果希望做四捨五入的話需要在整數位+1處理;

//fix25_12
always@(posedge clk)
    if(rst)
        cast_data <= 'd0;
    else if(line_data[24]==1'b1)
        cast_data <= 0;    
    else if(line_data[22:12]>=255)
        cast_data <= 255;
    else
        cast_data <= line_data[11] ? line_data[19:12] + 1'b1 : line_data[19:12];

相關文章