芯路恒电子技术论坛

 找回密码
 立即注册
热搜: 合集
查看: 14388|回复: 4

基于FPGA的彩色图像灰度化处理实现

[复制链接]
  • TA的每日心情
    开心
    2021-1-26 21:41
  • 16

    主题

    41

    帖子

    273

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    273
    发表于 2018-5-5 22:30:10 | 显示全部楼层 |阅读模式
    本帖最后由 挣钱买刀 于 2018-5-24 11:49 编辑

    一、图像的灰度化处理的基本原理
    将彩色图像转化成为灰度图像的过程成为图像的灰度化处理。彩色图像RGB24中的每个像素的颜色有RGB三个分量决定,而每个分量有255中值可取,这样一个像素点可以有1600多万(255*255*255)的颜色的变化范围。而灰度图像是RGB三个分量相同的一种特殊的彩色图像,其一个像素点的变化范围为255种,所以在数字图像处理种一般先将各种格式的图像转变成灰度图像以使后续的图像的计算量变得少一些。灰度图像的描述与彩色图像一样仍然反映了整幅图像的整体和局部的色度和亮度等级的分布和特征。图像的灰度化处理有如下几种方法实现。
    以下方法的介绍是参考博客,具体链接http://blog.chinaaet.com/crazybingo/p/32550,懒得点链接直接看下面的也是一样的。
    方法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:求平均法
    原则上的灰度,就是让R=G=B,那顾名思义,可以直接求平均,如下:
    gray = (R+G+B)/3
    有除法,这里将3改为256,这里公式变为gray = ((R+G+B)*85)≥8。
    图像显示时用(gray,gray,gray)替代(R,G,B)即可。
    不过这样会导致图像质量不好,这是必然的,因为也许图像的分量不均匀,再者肉眼对色彩的敏感程度也是不一样的。
    方法3:典型灰度转换公式
    对于彩色转灰度,有一个很著名的心理学公式:
    gray = R*0.299 + G*0.587 + B*0.114
    在此0.299+0.587+0.144=1,刚好是满偏,这是通过不同的敏感度以及经验总结出来的公式,一般可以直接用这个。而实际应用时,希望避免低速的浮点运算,所以需要整数算法。注意到系数都是小数点后3位,我们可以将它们缩放1000倍来实现整数运算算法,如下
    gray = (R*299 + G*587 + B*114) / 1000
    但是除法就是不爽,为了能在后续实现移位,将1000扩展到1024,得到式子如下:
    gray = (R* 306 + G*601 + B*117) / 1024=(R* 306 + G*601 + B*117) >>10
    适当的还可以在精简,压缩到8位以内,现在变成这样子:
    gray = (R*75 + G*147 + B*36) >>8
    方法4:查找表
    到目前为止,整数算法已经很快了,但是完美是没有极限的,其实是可以更快的,观察原始式子
    gray = R*0.299 + G*0.587 + B*0.114
    每一通道数据乘以一个常数,这三个变量可以提前算好,保存在ROM,这样就只是查找表的时间了。
    同样为了避免浮点,将式子变为gray = (R*75 + G*147 + B*36) >>8
    二、图像的灰度化处理方法实现
           接下来将分别对方法2、3、4三种方法在FPGA上实现,并结合小梅哥团队出品《自学笔记——设计与验证》一书中串口传图工程对三种不同实现方法进行板级的验证。
    待处理的彩色图片
    0001.jpg
           方法2实现,该方法实现起来比较简单,这里乘法也通过移位的方式进行计算,具体实现见下面代码:
    [Pascal] 纯文本查看 复制代码
    1         module RGB2Gray(
    2                 clk,
    3                 rst_n,
    4                 rgb_inen,
    5                 red,
    6                 green,
    7                 blue,
    8                 gray,
    9                 gray_outen
    10        );
    11                input clk;         //时钟
    12                input rst_n;       //异步复位
    13                input rgb_inen;    //rgb输入有效标识
    14                input [7:0]red;    //R输入
    15                input [7:0]green;  //G输入
    16                input [7:0]blue;   //B输入
    17                output [7:0]gray;  //GRAY输出
    18                output reg gray_outen; //gray输出有效标识
    19                
    20                //求平均法GRAY = (R+B+G)/3=((R+B+G)*85)>>8
    21                wire [9:0]sum;
    22                reg [15:0]gray_r;
    23                
    24                assign sum = red + green + blue;
    25                
    26                always@(posedge clk or negedge rst_n)
    27                begin
    28                        if(!rst_n)
    29                                gray_r <= 16'd0;
    30                        else if(rgb_inen)
    31                                gray_r <= (sum<<6) + (sum<<4) + (sum<<2) + sum;
    32                        else
    33                                gray_r <= 16'd0;
    34                end
    35                
    36                assign gray = gray_r[15:8];
    37                
    38                always@(posedge clk or negedge rst_n)
    39                begin
    40                        if(!rst_n)
    41                                gray_outen <= 1'b0;
    42                        else if(rgb_inen)
    43                                gray_outen <= 1'b1;
    44                        else
    45                                gray_outen <= 1'b0;
    46                end
    47                
    48        endmodule 
    实现效果如下图: 1.jpg
      方法3实现,与方法2实现类似,只是具体计算数值发生了变化,同样乘法采用移位相加的方式实现,
    [Pascal] 纯文本查看 复制代码
    1         module RGB2Gray(
    2                 clk,
    3                 rst_n,
    4                 rgb_inen,
    5                 red,
    6                 green,
    7                 blue,
    8                 gray,
    9                 gray_outen
    10        );
    11                input clk;         //时钟
    12                input rst_n;       //异步复位
    13                input rgb_inen;    //rgb输入有效标识
    14                input [7:0]red;    //R输入
    15                input [7:0]green;  //G输入
    16                input [7:0]blue;   //B输入
    17                output [7:0]gray;  //GRAY输出
    18                output reg gray_outen; //gray输出有效标识
    19                
    20        //典型灰度转换公式Gray = R*0.299+G*0.587+B*0.114=(R*75 + G*147 + B*36) >>8
    21        wire [15:0]w_R;
    22        wire [15:0]w_G;
    23        wire [15:0]w_B;
    24        reg [17:0]sum;
    25
    26        assign w_R = {red,6'b000000} + {red,3'b000} + {red,1'b0} + red;
    27        assign w_G = {green,7'b0000000} + {green,4'b0000} + {green,1'b0} + green;
    28        assign w_B = {blue,5'b00000} + {blue,2'b00};
    29
    30        always@(posedge clk or negedge rst_n)
    31        begin
    32                if(!rst_n)
    33                        sum <= 18'd0;
    34                else if(rgb_inen)
    35                        sum <= w_R + w_G + w_B;
    36                else
    37                        sum <= 18'd0;
    38        end
    39        
    40        assign gray = sum[15:8];
    41
    42        always@(posedge clk or negedge rst_n)
    43        begin
    44                if(!rst_n)
    45                        gray_outen <= 1'b0;
    46                else if(rgb_inen)
    47                        gray_outen <= 1'b1;
    48                else
    49                        gray_outen <= 1'b0;
    50        end
    51                
    [float=left]52        endmodule 
         
    该方法在实现过程中遇到一个错误,通过仿真方式很容易的发现并进行了改正,发生错误的地方是在计算w_R、w_G、w_B的地方,错误代码如下:
    [Pascal] 纯文本查看 复制代码
            assign w_R = red<<6 + red<<3 + red<<1 + red;
            assign w_G = green<<7 + green<<4 + green<<1 + green;
            assign w_B = blue<<5 + blue<<2;


    在等式左边计算过程中由于red、green、blue是位宽8bit的数,在移位后数据高位部分就丢失掉了,比如,green<<7得到的是{green[0],7'b0000000},并非我期望的green*2的7次方。后来改为如下正确的代码后就可以得到正确的结果了。
    [Pascal] 纯文本查看 复制代码
            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};


    该方法实现效果图如下:
    2.jpg
    [size=13.3333px]方法4实现,该方法主要的优势是速度块,但占用的存储器会更多,因为需要将R、G、B乘以系数之后的数值存储在ROM中,然后通过读取ROM方式来得到计算之后的数值。这里使用全quartusII软件添加3个ROMIP核,分别对R*75、G*147、B*36(0≤R≤255,0≤G≤255,0≤B≤255)建立3个mif文件,然后在ROM IP核中分别添加mif文件进行初始化。具体代码如下:代码中[size=13.3333px]ROM_R、[size=13.3333px]ROM_G、[size=13.3333px]ROM_B分别存储着R*75、G*147、B*36(0≤R≤255,0≤G≤255,0≤B≤255)256个数值。
    [Pascal] 纯文本查看 复制代码
    1         module RGB2Gray(
    2                 clk,
    3                 rst_n,
    4                 rgb_inen,
    5                 red,
    6                 green,
    7                 blue,
    8                 gray,
    9                 gray_outen
    10        );
    11                input clk;         //时钟
    12                input rst_n;       //异步复位
    13                input rgb_inen;    //rgb输入有效标识
    14                input [7:0]red;    //R输入
    15                input [7:0]green;  //G输入
    16                input [7:0]blue;   //B输入
    17                output [7:0]gray;  //GRAY输出
    18                output reg gray_outen; //gray输出有效标识
    19                
    20        //查找表方式,可以省去乘法运算Gray =(R*75 + G*147 + B*36) >>8,将3个分量乘以系数后的数值存储在ROM中
    21        wire [14:0]w_R;
    22        wire [15:0]w_G;
    23        wire [13:0]w_B;
    24        
    25        reg [17:0]sum;
    26        reg [1:0]r_gray_outen;
    27        
    28        ROM_R ROM_R(
    29                .address(red),
    30                .clock(clk),
    31                .rden(rgb_inen),
    32                .q(w_R)
    33        );
    34                
    35        ROM_G ROM_G(
    36                .address(green),
    37                .clock(clk),
    38                .rden(rgb_inen),
    39                .q(w_G)
    40        );
    41        
    42        ROM_B ROM_B(
    43                .address(blue),
    44                .clock(clk),
    45                .rden(rgb_inen),
    46                .q(w_B)
    47        );
    48        
    49        always@(posedge clk)
    50                {gray_outen,r_gray_outen} <= {r_gray_outen,rgb_inen};
    51        
    52        always@(posedge clk or negedge rst_n)
    53        begin
    54                if(!rst_n)
    55                        sum <= 18'd0;
    56                else if(r_gray_outen[1])
    57                        sum <= w_R + w_G + w_B;
    58                else
    59                        sum <= 18'd0;
    60        end
    61        
    62        assign gray = sum[15:8];
    63        
    64        endmodule 

    实现效果图如下:

    方法3和方法4出现的结果是一样的,两者的差别在速度与占用的存储器的差别,方法2实现的效果与方法3、4有略微的差别,由于拍的照片没法明显看出来,在实现过程中,从一种方法2切换到方法3、4,是能看到图像有变亮。
         今天先到这里,代码工程及整个设计的框架结构放附件。


    Uart2Sdram2TFT_RGB2GRAY.zip

    8.52 MB, 下载次数: 847

    工程

    基于FPGA的彩色图像灰度化的实现.pdf

    754.98 KB, 下载次数: 462

    文档

    回复

    使用道具 举报

    该用户从未签到

    0

    主题

    1

    帖子

    12

    积分

    新手入门

    Rank: 1

    积分
    12
    发表于 2018-5-21 21:18:27 | 显示全部楼层
    非常好!谢谢!期待您的“代码工程及整个设计的框架结构后面再传上”
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2021-1-26 21:41
  • 16

    主题

    41

    帖子

    273

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    273
     楼主| 发表于 2018-5-24 11:50:32 | 显示全部楼层
    ldqzhh 发表于 2018-5-21 21:18
    非常好!谢谢!期待您的“代码工程及整个设计的框架结构后面再传上”

    工程和详细的文档放在了附件了,可下载查看
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-5-28 08:31
  • 0

    主题

    1

    帖子

    26

    积分

    新手上路

    Rank: 2

    积分
    26
    发表于 2018-5-28 08:43:56 | 显示全部楼层
    感谢楼主分享,学习了
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2018-12-20 23:13
  • 3

    主题

    17

    帖子

    29

    积分

    新手上路

    Rank: 2

    积分
    29
    发表于 2018-12-20 23:53:00 | 显示全部楼层
    非常好的资料,讲的很详细,谢谢分享
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|小黑屋|Archiver|芯路恒电子技术论坛 |鄂ICP备2021003648号

    GMT+8, 2024-4-19 17:29 , Processed in 0.120741 second(s), 37 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc. Template By 【未来科技】【 www.wekei.cn 】

    快速回复 返回顶部 返回列表