FPGA實現圖像的非線性變換:伽瑪(冪律)變換


  伽瑪變換又名指數變換、冪次變換或冪律變換,是另一種常用的非線性變換。

 

一、伽瑪(冪律)變換理論

  伽瑪變換的一般表達式為:s = c·rγ

  其中 c 和 γ 為正常數,有時考慮到偏移量,也將表達式寫為 s=c(r+ ε)γ。與對數變換不同,伽瑪變換可以根據 y 的不同取值選擇性地增強低灰度區域的對比度或是高灰度區域的對比度。y是圖像灰度校正中非常重要的-一個參數,其取值決定了輸入圖像和輸出圖像之間的灰度映射方式,即決定了是增強低灰度( 陰影區域)還是增強高灰度(高亮區域)。其中:

  ● y>1時,圖像的高灰度區城對比度得到增強;
  ● y<1時,圖像的低灰度區域對比度得到增強;
  ● y=1時,這一灰度變換是線性的,即不改變原圖像。
  伽瑪變換的映射關系如圖所示。在進行變換時,通常需要將0~255的灰度動態范圍首先變換到 0~1 的動態范圍,然后執行伽瑪變換后再回復原動態范圍。

  灰度圖彩色圖都可以進行伽瑪變換,下面的案例直接拿彩色圖案來測試結果。

 二、MATLAB實現

%--------------------------------------------------------------------------
%--                     gamma變換
%--------------------------------------------------------------------------
clear all
close all
clc

I = imread('img.jpg'); %讀入原圖像

subplot(3,1,1);imshow(imadjust(I,[],[],0.75));title('Gamma 0.75');
subplot(3,1,2);imshow(imadjust(I,[],[],1   ));title('Gamma 1');
subplot(3,1,3);imshow(imadjust(I,[],[],1.5 ));title('Gamma 1.5');

  由 MATLAB 可以看出的確符合上面說的結論:

  ● y>1時,圖像的高灰度區城對比度得到增強,圖像看起來變暗了;
  ● y<1時,圖像的低灰度區域對比度得到增強,圖像看起來變亮了;
  ● y=1時,這一灰度變換是線性的,即不改變原圖像。

 

 三、FPGA實現

1、log函數查找表
  對於 FPGA 來說,直接實現對數公式難度很大,像這種問題我們多采用基於查找表的方式進行對數變換。ROM 表的制作可以用MATLAB實現,代碼如下所示:
%--------------------------------------------------------------------------
%--             生成gamma校正所需的rom mif文件
%--------------------------------------------------------------------------
clear all
close all
clc

depth = 256;
width = 8; 
r = [0:1:255];
%--------------------------------------------------------------------------
%--                     sqrt開根
%--------------------------------------------------------------------------
s_qrt = 16*sqrt(r);  %開根 
z1    = round(s_qrt); 

fid = fopen('sqrt.mif','w');
fprintf(fid,'depth= %d; \n',depth); 
fprintf(fid,'width= %d; \n',width); 
fprintf(fid,'address_radix=uns;\n'); 
fprintf(fid,'data_radix = uns;\n'); 
fprintf(fid,'Content Begin \n'); 
for(k=1:depth)
    fprintf(fid,'%d: %d; \n',k-1,z1(k));
end
fprintf(fid,'end;');
%--------------------------------------------------------------------------
%--                     square開方
%--------------------------------------------------------------------------
s_quare = (1/256)*r.^2;   %平方
z2 = round(s_quare);

fid = fopen('square.mif','w');
fprintf(fid,'depth= %d; \n',depth); 
fprintf(fid,'width= %d; \n',width); 
fprintf(fid,'address_radix=uns;\n'); 
fprintf(fid,'data_radix = uns;\n'); 
fprintf(fid,'Content Begin \n'); 
for(k=1:depth)
    fprintf(fid,'%d: %d; \n',k-1,z2(k));
end
fprintf(fid,'end;');
%--------------------------------------------------------------------------
%--                     曲線展示
%--------------------------------------------------------------------------
hold on
plot(r);        %原曲線
plot(s_qrt);    %開根
plot(s_quare);  %開方
legend('原曲線','開根曲線','開方曲線');
hold off

   點擊運行就可以得到 sqrt.mif 和 square.mif 文件,分別代表了 γ < 1 和 γ > 1 的情況。此外可以看到這次采用的 γ 曲線如圖所示:

2、代碼設計

  有了 rom 查找表,代碼設計變得異常簡單,直接拿數據進查找表對照即可,和上篇博客是一樣的操作,關鍵代碼如下所示:

//==========================================================================
//==    RGB565轉RGB888
//==========================================================================
assign R = {RGB_data[15:11],RGB_data[13:11]};
assign G = {RGB_data[10: 5],RGB_data[ 6: 5]};
assign B = {RGB_data[ 4: 0],RGB_data[ 2: 0]};
//==========================================================================
//==    gamma sqrt 圖像變亮
//==========================================================================
rom_sqrt u_R_sqrt
(
    .address                (R                      ),
    .clock                  (clk                    ),
    .q                      (R_sqrt                 )
);

rom_sqrt u_G_sqrt
(
    .address                (G                      ),
    .clock                  (clk                    ),
    .q                      (G_sqrt                 )
);

rom_sqrt u_B_sqrt
(
    .address                (B                      ),
    .clock                  (clk                    ),
    .q                      (B_sqrt                 )
);

assign gamma_data_sqrt = {R_sqrt[7:3],G_sqrt[7:2],B_sqrt[7:3]};
//==========================================================================
//==    gamma square 圖像變暗
//==========================================================================
rom_square u_R_square
(
    .address                (R                      ),
    .clock                  (clk                    ),
    .q                      (R_square               )
);

rom_square u_G_square
(
    .address                (G                      ),
    .clock                  (clk                    ),
    .q                      (G_square               )
);

rom_square u_B_square
(
    .address                (B                      ),
    .clock                  (clk                    ),
    .q                      (B_square               )
);

assign gamma_data_square = {R_square[7:3],G_square[7:2],B_square[7:3]};
//==========================================================================
//==    信號同步,rom給地址到出數據會延遲1clk
//==========================================================================
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        RGB_de_r    <= 1'b0;
        RGB_hsync_r <= 1'b0;
        RGB_vsync_r <= 1'b0;
    end
    else begin  
        RGB_de_r    <= RGB_de;
        RGB_hsync_r <= RGB_hsync;
        RGB_vsync_r <= RGB_vsync;
    end
end

assign gamma_de    = RGB_de_r;
assign gamma_hsync = RGB_hsync_r;
assign gamma_vsync = RGB_vsync_r;

 

四、上板驗證

  sqrt開根的伽馬圖:

  原圖:

  square 開方的伽馬圖:

  雖然我的板子壞了,但總的效果還是成功的,圖像在不同的 γ 值下效果不同,sqrt開根操作(γ<1)時整體變亮,square開方操作(γ>1)是整體變暗,和MATLAB的效果差不多,實驗成功。

 

參考資料:

[1] OpenS Lee:FPGA開源工作室(公眾號)

[2] 張錚, 王艷平, 薛桂香. 數字圖像處理與機器視覺[M]. 人民郵電出版社, 2010.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM