RGB转Y(Gray)算法实现

一、图像的灰度化处理的基本原理

将彩色图像转化成为灰度图像的过程称为图像的灰度化处理,本文所提到的RGB均为8bit。彩色图像中的每个像素的颜色由R、G、B三个分量组成,而每个分量有256个值可取,一个像素点可以有1600多万(256x256x256)的颜色的变化范围。而灰度图像是R、G、B三个分量中提取的亮度分量,其一个像素点的变化范围有256种,所以在数字图像处理种一般先将各种格式的图像转变成灰度图像以使后续的图像的计算量变得少一些。图像的灰度化处理有多种方法实现,以下是两种方式,一种是AdobePhotoshop中的,另一种是实际工程中的;

二 具体实现

方法1:AdobePhotoshop 里的公式AdobeRGB (1998) [gamma=2.20]
具体的公式表达式如下:
gray= (R^2.2 * 0.2973 + G^2.2 * 0.6274 + B^2.2 * 0.0753)^(1/2.2)
该方法运行速度稍慢,效果很好,但是FPGA实现起来较复杂,资源消耗多;
方法2:典型灰度转换公式
gray = R0.299 + G0.587 + B0.114
在此0.299+0.587+0.144=1,刚好是满偏,这是通过不同的敏感度以及经验总结出来的公式,一般可以直接用这个。而实际应用时,希望避免低速的浮点运算,所以需要整数算法。注意到系数都是小数点后3位,我们可以将它们缩放1000倍来实现整数运算算法,如下
gray = (R
299 + G587 + B114) / 1000
但是除法就需要消耗DSP,为了从资源、精度、效率的角度考虑,可将1000扩展到1024,得到式子如下:
gray = (R* 306 + G601 + B117) / 1024=(R* 306 + G601 + B117) >>10
可以根据实际精度需求,压缩到8位以内,现在变成这样子:
gray = (R75 + G147 + B36) >>8
方法3:查找表方法
整数算法已经很快了,但是完美是没有极限的,在实际工程中可能LUT、DSP不够用,或者还不够快时,可以使用查找表的方法,观察原始式子
gray = R
0.299 + G0.587 + B0.114
每一通道数据乘以一个常数,这三个变量可以提前算好,保存在ROM,这样就只是查找表的时间了。同样为了避免浮点,将式子变为
gray = (R75 + G147 + B*36) >>8

方法2实现
只是具体计算数值发生了变化,同样乘法采用移位相加的方式实现。

  module RGB2Gray(
      clk,
      rst_n,
      rgb_inen,
      red,
      green,
      blue,
      gray,
      gray_outen
  );
      input clk;         //时钟
      input rst_n;       //异步复位
      input rgb_inen;    //rgb输入有效标识
      input [7:0]red;    //R输入
      input [7:0]green;  //G输入
      input [7:0]blue;   //B输入
      output [7:0]gray;  //GRAY输出
      output reg gray_outen; //gray输出有效标识
      
  //典型灰度转换公式Gray = R*0.299+G*0.587+B*0.114=(R*75 + G*147 + B*36) >>8
      wire [15:0]w_R;
      wire [15:0]w_G;
      wire [15:0]w_B;
      reg [17:0]sum;

      assign w_R = {red,6'b000000} + {red,3'b000} + {red,1'b0} + red;
      assign w_G = {green,7'b0000000} + {green,4'b0000} + {green,1'b0} + green;
      assign w_B = {blue,5'b00000} + {blue,2'b00};

      always@(posedge clk or negedge rst_n)
      begin
          if(!rst_n)
              sum <= 18'd0;
          else if(rgb_inen)
              sum <= w_R + w_G + w_B;
          else
              sum <= 18'd0;
      end
      
      assign gray = sum[15:8];

      always@(posedge clk or negedge rst_n)
      begin
          if(!rst_n)
              gray_outen <= 1'b0;
          else if(rgb_inen)
              gray_outen <= 1'b1;
          else
              gray_outen <= 1'b0;
      end
  
 endmodule

方法3实现
该方法主要的优势是速度块,但占用的存储器会更多,因为需要将R、G、B乘以系数之后的数值存储在ROM中,然后通过读取ROM方式来得到计算之后的数值。这里使用全quartusII软件添加3个ROMIP核,分别对Rx75、Gx147、Bx36(0≤R≤255,0≤G≤255,0≤B≤255)建立3个mif文件,然后在ROM IP核中分别添加mif文件进行初始化。具体代码如下:代码中ROM_R、ROM_G、ROM_B分别存储着Rx75、Gx147、Bx36(0≤R≤255,0≤G≤255,0≤B≤255)256个数值。

module RGB2Gray(
     clk,
     rst_n,
     rgb_inen,
     red,
     green,
     blue,
     gray,
     gray_outen
 );
     input clk;         //时钟
     input rst_n;       //异步复位
     input rgb_inen;    //rgb输入有效标识
     input [7:0]red;    //R输入
     input [7:0]green;  //G输入
     input [7:0]blue;   //B输入
     output [7:0]gray;  //GRAY输出
     output reg gray_outen; //gray输出有效标识
     
 //查找表方式,可以省去乘法运算Gray =(R*75 + G*147 + B*36) >>8,将3个分量乘以系数后的数值存储在ROM中
 wire [14:0]w_R;
 wire [15:0]w_G;
 wire [13:0]w_B;
 
 reg [17:0]sum;
 reg [1:0]r_gray_outen;
 
 GRAY_ROM_R GRAY_ROM_R(
     .address(red),
     .clock(clk),
     .rden(rgb_inen),
     .q(w_R)
 );
     
 GRAY_ROM_G GRAY_ROM_G(
     .address(green),
     .clock(clk),
     .rden(rgb_inen),
     .q(w_G)
 );
 
GRAY_ ROM_B GRAY_ROM_B(
     .address(blue),
     .clock(clk),
     .rden(rgb_inen),
     .q(w_B)
 );
 
 always@(posedge clk)
     {gray_outen,r_gray_outen} <= {r_gray_outen,rgb_inen};
 
 always@(posedge clk or negedge rst_n)
 begin
     if(!rst_n)
         sum <= 18'd0;
     else if(r_gray_outen[1])
         sum <= w_R + w_G + w_B;
     else
         sum <= 18'd0;
 end
 
 assign gray = sum[15:8];
 
 endmodule 

你可能感兴趣的:(FPGARGB2Y)