FPGA實現圖像的直方圖拉伸


  在視頻處理中,為了能夠實時調節圖像的對比度,通常需要對直方圖進行拉伸處理。直方圖拉伸是指將圖像灰度直方圖較窄的灰度級區間向兩端拉伸,增強整幅圖像像素的灰度級對比度,達到增強圖像的效果。

  常用的直方圖拉伸方法有線性拉伸、3段式分段線性拉伸和非線性拉伸等。這里我們介紹FPGA中常見的線性拉伸。

  線性拉伸也即灰度拉伸,屬於線性點運算的一種。它擴展圖像的直方圖,使其充滿整個灰度級范圍內。設f(x,y)為輸入圖像,它的最小灰度級A和最大灰度級B的定義如下:

  將A和B分別映射到0和255,則最終得到輸出圖像g(x,y)為

 

一、MATLAB實現

%--------------------------------------------------------------------------
%--                     灰度直方圖拉伸
%--------------------------------------------------------------------------
close all
clear all;
clc;
 
I = rgb2gray(imread('car.bmp')); %讀圖轉灰度
 
Imin = min(min(I));
Imax = max(max(I));

[M,N] = size(I);
C =255/(Imax-Imin);
Inew = zeros(size(I));
for i=1:M
   for j=1:N
       if(I(i,j)==Imin) 
           Inew(i,j) = 0;
       elseif(I(i,j)==Imax) 
           Inew(i,j) = 255;
       else
           Inew(i,j)=(C.*(I(i,j)-Imin));
       end
   end
end

Inew = uint8(Inew);

subplot(221),imshow(I);   title('灰度圖');
subplot(223),imshow(Inew);title('灰度拉伸圖');
subplot(222),imhist(I);   title('灰度直方圖統計');
subplot(224),imhist(Inew);title('灰度拉伸后的直方圖統計');

  點擊運行,得到如下結果:

  由此可以看出:線性拉伸達到了類似直方圖均衡化的功能,將比較集中的直方圖拉伸到整個灰度分布區域。

 

二、FPGA實現

1、理論分析

  拉伸處理的公式如下,其中 A 為最大灰度級,B為最小灰度級,f(x,y)為原圖像,g(x,y)為拉伸后的圖像。

  FPGA實現灰度圖像的拉伸可分為真拉伸和偽拉伸,真拉伸是指公式所有值都是當前幀,處理后的結果也是當前幀。這需要對圖像進行一幀的緩存,在實際應用中,處理幀緩存是費時費力費資源的一-件事情,在許多情況下,圖像的變換比較慢,在這種情況下的一-個近似是當建立當前幀的直方圖統計結果時使用從前一幀得到的映射。結果是直方圖均衡化可能不是非常准確,但是消耗的資源和處理的延時都有顯著地減少。我們稱之為偽拉伸,其實就是在前一幀計算出公式所有值,用來對本幀圖像進行拉伸處理,這樣設計難度大大減小。

2、實現步驟  

  為得到A、B的值需要進行統計工作,這至少要等到前一幀圖像“流過”之后才能完成。此限制決定了我們難以在同一幀既統計又輸出最終拉伸結果。必須對前期的統計結果進行緩存。這點是毋庸置疑的。在下一次統計前需要將緩存結果清零。我們可以按一下步驟來實現:

  (1)前一幀:統計一幀圖像的最大值和最小值,即A和B

  (2)前一幀到當前幀的空隙:保存前一幀的最大值和最小值。

  (3)當前幀:進行直方圖拉伸公式的計算:

    ①計算 255 * (f(x,y) - A 和 B - A。

    ②計算①中,二者的商

    ③計算大括號,對f(x,y)進行判斷,輸出最終直方圖拉伸的結果。

 3、Verilog設計

//==========================================================================
//==    計算一幀圖像的最大值最小值
//==========================================================================
//vsync下降沿
//---------------------------------------------------
assign neg_Y_vsync = Y_vsync_r[0] && ~Y_vsync;

//實時計算大小
//---------------------------------------------------
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        max <= 8'd0;
        min <= 8'd255;
    end
    else if(Y_vsync && Y_de) begin     //像素有效時
        max <= (max > Y_data) ? max : Y_data;
        min <= (min < Y_data) ? min : Y_data;
    end
    else if(neg_Y_vsync) begin         //一幀圖像結束時
        max <= 8'd0;
        min <= 8'd255;
    end
end

//保存上一幀最大值、最小值
//---------------------------------------------------
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        Y_max <= 'd0;
        Y_min <= 'd0;
    end
    else if(neg_Y_vsync) begin         //一幀圖像結束時
        Y_max <= max;
        Y_min <= min;
    end
end
//==========================================================================
//==    直方圖拉伸,耗費3clk
//==========================================================================
//分子和分母,1clk
//---------------------------------------------------
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        mole <= 'd0;
        deno <= 'd0;
    end
    else begin
        mole <= (Y_data - Y_min) * 255;
        deno <=  Y_max  - Y_min;
    end
end

//g(x,y),1clk
//---------------------------------------------------
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        quot <= 'd0;
    end
    else begin
        quot <= mole / deno;
    end
end

//獲得拉伸結果,1clk
//---------------------------------------------------
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        hist_data <= 8'd0;
    end
    else if(Y_data < Y_min) begin
        hist_data <= 8'd0;
    end
    else if(Y_data > Y_max) begin
        hist_data <= 8'd255;
    end
    else begin
        hist_data <= quot[7:0];
    end
end
//==========================================================================
//==    信號同步
//==========================================================================
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        Y_de_r    <= 3'b0;
        Y_hsync_r <= 3'b0;
        Y_vsync_r <= 3'b0;
    end
    else begin  
        Y_de_r    <= {Y_de_r[1:0],    Y_de};
        Y_hsync_r <= {Y_hsync_r[1:0], Y_hsync};
        Y_vsync_r <= {Y_vsync_r[1:0], Y_vsync};
    end
end

assign hist_de    = Y_de_r[2];
assign hist_hsync = Y_hsync_r[2];
assign hist_vsync = Y_vsync_r[2];

 

三、上板驗證

  原圖:

  直方圖拉伸處理后:

  拉伸后,對比度明顯增強,實驗成功。

 

后記:

  同樣的,也可以用彩色圖像的RGB三通道來這樣處理,最后再合並,也能起到不錯的效果。

  此外本博客設計的直方圖拉伸是有缺陷的,當選取的圖片有白色噪聲時,直方圖拉伸會失敗。不過面對噪聲我們可以在直方圖拉伸前用中值濾波先處理一下,后續的博客會整理中值濾波的實現方法。此外,本博客的實現方法基於書本《基於FPGA的數字圖像處理原理及應用》,該書提供了一種改良的方法,可以應對白色噪聲,但是設計難度增加很多,感興趣的朋友可以翻閱該書學學看。

 

參考資料:

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

[2] 牟新剛、周曉、鄭曉亮.基於FPGA的數字圖像處理原理及應用[M]. 電子工業出版社,2017.

 


免責聲明!

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



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