基于 FPGA 的彩色图像灰度化的设计实现(rgb2gray | image_stitche_x)

本文介绍了基于FPGA的彩色图像灰度化处理,包括分量法、最大值法、平均值法和加权平均法,并详细阐述了平均值法的近似处理。同时,提出了图像合并模块的设计,通过状态机实现左右拼接显示。通过仿真验证了设计的正确性。
摘要由CSDN通过智能技术生成


前言

rgb2gray 模块:彩色图像灰度化处理,对串口接收的彩色图像数据实时进行灰度化处理;
image_stitche_x 模块:将串口接收的尺寸为 400480 大小的彩色图像与灰度化处理后的 400480 大小的图像数据以左右形式合并成一张 800*480 的图像。


提示:以下是本篇文章正文内容,下面案例可供参考

一、彩色图像灰度化处理模块的设计

1.基本原理

将彩色图像转化为灰度图像的过程称为图像灰度化处理。常见的 24 位深度彩色图像RGB888 中的每个像素的颜色由 R、G、B 三个分量决定,并且三个分量各占 1 个字节,每个分量可以取值 0~255,这样一个像素点可以有 1600 多万(255255255)的颜色的变化范围。而灰度图像是 R、G、B 三个分量相同的一种特殊的彩色图像,其一个像素点的变化范围为 0~255。对于一幅彩色图来说,其对应的灰度图则是只有 8 位的图像深度,这也说明了用灰度图做图像处理所需的计算量确实要少。不过需要注意的是,虽然丢失了一些颜色等级,但是从整幅图像的整体和局部的色彩以及亮度等级分布特征来看,灰度图描述与彩色图的描述是一致的。一般有分量法、最大值法、平均值法、加权平均法四种方法对彩色图像进行灰度化。

2.彩色图像灰度化处理方法介绍

方法 1:分量法

将彩色图像中的三分量的亮度作为三个灰度图像的灰度值,可根据应用需要选取一种灰度图像。具体表达式如下。

                                         gray1(𝑖,𝑗) = 𝑅(𝑖,𝑗)
                                         gray2(𝑖,𝑗) = 𝐺(𝑖,𝑗)
                                         gray3(𝑖,𝑗) = 𝐵(𝑖,𝑗)

其中,gray1(𝑖,𝑗), gray2(𝑖,𝑗), gray3(𝑖,𝑗)为转换后的灰度图像在(i,j)处的灰度值,R(i,j),G(i,j),B(i,j)分别为转换前的彩色图像在(i,j)处 R、G、B 三个分量的值。

方法 2:最大值法

将彩色图像中的三分量亮度 R,G,B 的最大值作为灰度图的灰度值。具体表达式如下。
gray(i, j) = max[𝑅(𝑖,𝑗),𝐺(𝑖,𝑗),𝐵(𝑖,𝑗)]

方法 3:平均值法

将彩色图像中的三分量亮度求平均得到一个灰度值。如下:
gray(i, j) =(𝑅(𝑖,𝑗) + 𝐺(𝑖,𝑗) + 𝐵(𝑖,𝑗))/3
上式中有除法,考虑到在 FPGA 中实现除法比较的消耗资源,这里在实现前可以先做如下的近似处理。可以将上面公式乘以 3/256,这样就需要同时乘以 256/3 保证公式的正确性。公式处理过程如下:
在这里插入图片描述
对 256/3 做近似取整处理,将 256/3 替换成 85,则公式变为如下。
在这里插入图片描述这样式子中除以 256 就可以采用移位方法来处理,式子变为如下:
在这里插入图片描述
上面处理过程中使用是对 256/3 的近似处理,当然这里可以采用其他数据,比如512/3、1024/3、2048/3 等等,基本的原则是将平均公式法中分母的 3 替换成 2 的幂次的数,这样除法就可以使用移位的方式实现,减小 FPGA 中由于存在除法带来的资源消耗。

平均值法的实现

该方法实现起来并不复杂,通过上面的计算公式可以知道,计算公式里只有加法、乘法和移位计算,这里的乘法通过移位相加的方式进行计算,计算具体实现见下面代码。

//求平均法 GRAY = (R+B+G)/3=(R+B+G)*85)>>8
 wire [9:0]sum;
 reg [15:0]gray_r;
 
 assign sum = red_8b_i + green_8b_i + blue_8b_i;
 
 always@(posedge clk or posedge reset_p)
 begin
 if(reset_p)
 gray_r <= 16'd0;
 else if(rgb_valid)
 gray_r <= (sum << 6)+(sum << 4)+(sum << 2)+ sum;
 else
 gray_r <= 16'd0;
 end
assign gray_8b_o = gray_r[15:8];
 always@(posedge clk)
 begin
 gray_valid <= rgb_valid;
 gray_hs <= rgb_hs;
 gray_vs <= rgb_vs;
 end

对该模块的仿真也相对比较简单,只需要在 testbech 中给时钟复位激励以及 RGB 三通道的图像数据即可,具体代码如下,仿真中分别给 R、G、B 通道不同的是起始数据值,然后通过递增加 1 的形式改变 R、G、B 通道数据,验证设计的正确性。

 initial begin
 reset_p = 1;
 rgb_valid = 0;
 red_8b_i = 0;
 green_8b_i = 0;
 blue_8b_i = 0; 
 #(`CLK_PERIOD*200+1);
 reset_p = 0;
 red_8b_i = 56;
 green_8b_i = 124;
 blue_8b_i = 203;
 #2000;
 
 rgb_valid = 1;
 repeat(256)begin
 #(`CLK_PERIOD)
 red_8b_i = red_8b_i + 1;
 green_8b_i = green_8b_i + 1;
 blue_8b_i = blue_8b_i + 1;
 end
 rgb_valid = 0;
 #2000;
 $stop; 
 end

为了能验证采用平均值法实现彩色图像灰度化计算的正确性,在仿真代码中加入了如下代码。直接通过平均法的原始公式产生一组对比数据。

always@(posedge clk)
 begin
 if(rgb_valid == 1'b1)
 comp1_gray <= (red_8b_i + green_8b_i + blue_8b_i)/3;
 else
 comp1_gray <= 0;
 end

这样可以比较容易的通过对比 comp1_gray 和 gray_8b_o 的值来验证设计模块的正确性。其仿真波形图如下:

在这里插入图片描述
在这里插入图片描述
在后面有个地方可以看到从一个地方开始 comp1_gray 和 gray_8b_o 的值相差 1,可以分析下出现这个问题的原因,其实 gray_8b_o 和 comp1_gray 的计算公式并非完全一样,gray_8b_o 的计算公式是为了避免除法做了一定的近似,而在仿真文件中 comp1_gray 是直接求的平均。可以通过 red、green、blue 这 3 个数据分别对 gray_8b_o 和 comp1_gray 进行计算,计算结果与仿真波形结果是一致的。这也说明了,避免除法做近似处理计算的 gray 和直接通过除法求的平均值 comp1_gray 是稍存在偏差的。这个是可以接收的误差范围。

方法 4 加权平均法

根据重要性及其它指标,将三个分量以不同的权值进行加权平均。有一个很著名的心理学公式:
在这里插入图片描述
这里 0.299+0.587+0.114=1,刚好是满偏,这是通过不同的敏感度以及经验总结出来的公式,一般可以直接用这个。在实际应用时,为了能避免低速的浮点运算以及除法运算,可以先将式子缩放 1024 倍来实现运算算法,如下:

在这里插入图片描述
通过近似取整处理后得到近似公式如下。

在这里插入图片描述

式子中除以 1024(这里是 2 的 n 次方就可以,n 不同,结果会略微有差别)可以采用移位方法来处理,式子变为如下:

在这里插入图片描述
也可以压缩到 8 位以内,式子变为如下。具体压缩到多少位可以根据实际需求。

在这里插入图片描述

加权平均法的实现

对于加权平均法可通过两种方式实现,公式直接计算法和查找表法。
 公式直接计算法
公式直接计算法与方法 3 实现类似,通过转换公式直接进行计算,只是具体计算数值发生了变化,同样乘法采用移位相加的方式实现。具体代码如下:

//典型灰度转换公式 Gray = R*0.299+G*0.587+B*0.114=(R*77 + G*150 + B*29) >>8
 wire [15:0]red_x77;
 wire [15:0]green_x150;
 wire [15:0]blue_x29;
 reg [15:0]sum;
 //乘法转换成移位相加方式
 assign red_x77 = (red_8b_i << 6) + (red_8b_i << 3) + (red_8b_i <<
2) + red_8b_i;
 assign green_x150 = (green_8b_i<< 7) + (green_8b_i<< 4) + (green_8b_i<<
2) + (green_8b_i<<1);
 assign blue_x29 = (blue_8b_i << 4) + (blue_8b_i << 3) + (blue_8b_i <<
2) + blue_8b_i;
 always@(posedge clk or posedge reset_p)
 begin
 if(reset_p)
 sum <= 16'd0;
 else if(rgb_valid)
 sum <= red_x77 + green_x150 + blue_x29;
 else
 sum <= 16'd0;
 end
 
 assign gray_8b_o = sum[15:8];
 always@(posedge clk)
 begin
 gray_valid <= rgb_valid;
 gray_hs <= rgb_hs;
 gray_vs <= rgb_vs;
 end

 公查找表法
通过观察计算公式发现,R、G、B 数据值均乘以了一个定值,然后对乘法之后的结果相加,最后右移 8 位,上面采用直接计算法实现是对常数乘法采用的移位相加方法计算,对于这类固定范围内的数值,同时可取数据不多情况下(这里 R、G、B 数值范围在 0~255,可取的数据有限)乘以一个常数,可以采用查找表方法实现,该方法主要的优势是直接通过访问 ROM 内的数据,相对使用移位相加实现乘法使用的 LUT 资源会少点,但占用的存储器会更多。因为需要将 R、G、B 乘以系数之后的数值存储在 ROM 中,然后通过读取 ROM方式来得到计算之后的数值。这里使用 Vivado 添加 3 个 ROM IP 核,分别通过 R75、G147、B36(0≤R≤255,0≤G≤255,0≤B≤255)的计算值建立 3 个初始化 coe 文件,然后在ROM IP 核中分别添加 coe 文件进行初始化。具体代码如下:代码中 rom_red_x77、rom_green_x150、rom_blue_x29 分别存储着 R 75、G147、B36(0≤R≤255,0≤G≤255,0≤B≤255)256 个数值。

//查找表方式,可以省去公式法中乘法运算 Gray =(R*77 + G*150 + B*29) >>8,将 3 个分量
乘以系数后的数值存储在 ROM 中
 wire [14:0]red_x77;
 wire [15:0]green_x150;
 wire [13:0]blue_x29; 
 reg [15:0]sum;
 reg rgb_valid_dly1;
 reg rgb_hs_dly1;
 reg rgb_vs_dly1;
 
 rom_red_x77 rom_red_x77(
 .clka (clk ), // input wire clka
 .ena (rgb_valid ), // input wire ena
 .addra (red_8b_i ), // input wire [7 : 0] addra
 .douta (red_x77 ) // output wire [14 : 0] douta
 );
 
 rom_green_x150 rom_green_x150(
 .clka (clk ), // input wire clka
 .ena (rgb_valid ), // input wire ena
 .addra (green_8b_i ), // in
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C.V-Pupil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值