FPGA图像处理之rgbtogray算法的实现

简介: Ycbcrr或Y'CbCr有的时候会被写作:YCBCR或是Y'CBCR,是色彩空间的一种,通常会用于影片中的影像连续处理,或是数字摄影系统中。Y'为颜色的亮度(luma)成分、而CB和CR则为蓝色和红色的浓度偏移量成份。Y'和Y是不同的,而Y就是所谓的流明(luminance),表示光的浓度且为非线性,使用伽马修正(gamma correction)编码处理。

1.背景知识

在正是入题之前先给大家讲解一下gray图像,YUV图像以及Ycbcr图像。

Gray图像:灰度图像就是我们常说的黑白图像,由黑到白为灰阶为0-255。

YUV是被欧洲电视系统所采用的一种颜色编码方法(属于PAL),是PAL和SECAM模拟彩色电视制式采用的颜色空间。在现代彩色电视系统中,通常采用三管彩色摄影机或彩色CCD摄影机进行取像,然后把取得的彩色图像信号经分色、分别放大校正后得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号B-Y(即U)、R-Y(即V),最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这种色彩的表示方法就是所谓的YUV色彩空间表示。采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。YUV主要用于优化彩色视频信号的传输,使其向后相容老式黑白电视。与RGB视频信号传输相比,它最大的优点在于只需占用极少的频宽(RGB要求三个独立的视频信号同时传输)。其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。“亮度”是透过RGB输入信号来建立的,方法是将RGB信号的特定部分叠加到一起。“色度”则定义了颜色的两个方面─色调与饱和度,分别用Cr和Cb来表示。其中,Cr反映了RGB输入信号红色部分与RGB信号亮度值之间的差异。而Cb反映的是RGB输入信号蓝色部分与RGB信号亮度值之间的差异。

Ycbcrr或Y'CbCr有的时候会被写作:YCBCR或是Y'CBCR,是色彩空间的一种,通常会用于影片中的影像连续处理,或是数字摄影系统中。Y'为颜色的亮度(luma)成分、而CB和CR则为蓝色和红色的浓度偏移量成份。Y'和Y是不同的,而Y就是所谓的流明(luminance),表示光的浓度且为非线性,使用伽马修正(gamma correction)编码处理。

2.FPGA 实现RGB图像转Gray图像方法

一般RGB像转灰度(gray)图像有两种方法,第一种就是使用RGB图像的单通道去显示图像(R,G或B)。

其二就是讲RGB图像转换成Ycbcr图像,使用Y分量去显示图像,来实现彩色图像转灰度图。

3.RGB单通道实现灰度图像的转换

image.png

上图为整个图像显示的架构。我们采用RGB565格式。

RGB单通道实现灰度图像FPGA源码:

//----------------------------------------------------------------------

//  R G B to gray

//----------------------------------------------------------------------

wire[15:0] rgb;

assignTFT_rgb = {
   
   rgb[15:11],rgb[15:11],1'b0,rgb[15:11]};  //red

//assignTFT_rgb = {rgb[10:6],rgb[10:5],rgb[10:6]};          //green

//assignTFT_rgb = {rgb[4:0],rgb[4:0],1'b1,rgb[4:0]};          //blue

//assignTFT_rgb = {rgb[4:0],rgb[4:0],1'b0,rgb[4:0]};          //blue

实现结果

image.png

                            原图

image.png

Red分量

image.png

Green分量

image.png

Blue分量

由上三个分量显示图像来看,Green分量显示效果较好。大家可以多试其他图像,这种方法比较简单,容易实现。

4 RGB图像转Ycbcr图像实现gray图像。

image.png

RGB转Ycbcr算法:

  计算公式: Y  = 0.183R + 0.614G + 0.062B + 16;

                        CB = -0.101R -0.338G + 0.439B + 128;

                        CR =  0.439R - 0.399G - 0.040B + 128;

   其中,时序在计算过程中完全没有用到

  输入到输出有三个clock的时延。

  第一级流水线计算所有乘法;

  第二级流水线计算所有加法,把正的和负的分开进行加法;

  第三级流水线计算最终的和,若为负数取0;

Modelsim仿真部分希望自己去做。

RGB转Ycbcr FPGA源码:

/*

    RGB转YUV算法

      计算公式: Y =  0.183R + 0.614G + 0.062B + 16;

                                         CB= -0.101R - 0.338G + 0.439B + 128;

                                         CR=  0.439R - 0.399G - 0.040B + 128;

      其中,时序在计算过程中完全没有用到

      输入到输出有三个clock的时延。

      第一级流水线计算所有乘法;

      第二级流水线计算所有加法,把正的和负的分开进行加法;

      第三级流水线计算最终的和,若为负数取0;

      仿真通过

*/

`timescale1ns/1ps

module  rgb_to_ycbcr(

                                          input                                                       clk,

                                          input                           [7 : 0]            i_r_8b,

                                          input                           [7 : 0]            i_g_8b,

                                          input                           [7 : 0]            i_b_8b,



                                          input                                               i_h_sync,

                                          input                                                   i_v_sync,

                                          input                                                   i_data_en,



                                          output                  [7 : 0]            o_y_8b,

                                          output                  [7 : 0]            o_cb_8b,

                                          output                  [7 : 0]            o_cr_8b,



                                          output                                              o_h_sync,

                                          output                                    o_v_sync,                                                                                                 

                                          output                    o_data_en                                                                                               

                                          );



/***************************************parameters*******************************************/

//multiply256

parameter     para_0183_10b = 10'd47;    //0.183 定点数

parameter     para_0614_10b = 10'd157;

parameter     para_0062_10b = 10'd16;

parameter     para_0101_10b = 10'd26;

parameter     para_0338_10b = 10'd86;

parameter     para_0439_10b = 10'd112;

parameter     para_0399_10b = 10'd102;

parameter     para_0040_10b = 10'd10;

parameter     para_16_18b = 18'd4096;

parameter     para_128_18b = 18'd32768;

/********************************************************************************************/



/***************************************signals**********************************************/

wire                      sign_cb;

wire                      sign_cr;

reg[17:0]       mult_r_for_y_18b;

reg[17:0]       mult_r_for_cb_18b;

reg[17:0]       mult_r_for_cr_18b;



reg[17:0]       mult_g_for_y_18b;

reg[17:0]       mult_g_for_cb_18b;

reg[17:0]       mult_g_for_cr_18b;



reg[17:0]       mult_b_for_y_18b;

reg[17:0]       mult_b_for_cb_18b;

reg[17:0]       mult_b_for_cr_18b;



reg[17:0]       add_y_0_18b;

reg[17:0]       add_cb_0_18b;

reg[17:0]       add_cr_0_18b;



reg[17:0]       add_y_1_18b;

reg[17:0]       add_cb_1_18b;

reg[17:0]       add_cr_1_18b;



reg[17:0]      result_y_18b;

reg[17:0]       result_cb_18b;

reg[17:0]       result_cr_18b;



reg[9:0]y_tmp;

reg[9:0]cb_tmp;

reg[9:0]cr_tmp;



reg                              i_h_sync_delay_1;

reg                              i_v_sync_delay_1;

reg                              i_data_en_delay_1;



reg                              i_h_sync_delay_2;

reg                              i_v_sync_delay_2;

reg                              i_data_en_delay_2;



reg                              i_h_sync_delay_3;

reg                              i_v_sync_delay_3;

reg                              i_data_en_delay_3;

/********************************************************************************************/



/***************************************initial**********************************************/

initial

begin

       mult_r_for_y_18b <= 18'd0;

       mult_r_for_cb_18b <= 18'd0;

       mult_r_for_cr_18b <= 18'd0;



       mult_g_for_y_18b <= 18'd0;

       mult_g_for_cb_18b <= 18'd0;

       mult_g_for_cr_18b <= 18'd0;



       mult_b_for_y_18b <= 18'd0;

       mult_g_for_cb_18b <= 18'd0;

       mult_b_for_cr_18b <= 18'd0;





       add_y_0_18b <= 18'd0;

       add_cb_0_18b <= 18'd0;

       add_cr_0_18b <= 18'd0;



       add_y_1_18b <= 18'd0;

       add_cb_1_18b <= 18'd0;

       add_cr_1_18b <= 18'd0;



       result_y_18b <= 18'd0;

       result_cb_18b <= 18'd0;

       result_cr_18b <= 18'd0;



       i_h_sync_delay_1 <= 1'd0;

       i_v_sync_delay_1 <= 1'd0;

       i_data_en_delay_1 <= 1'd0;



       i_h_sync_delay_2 <= 1'd0;

       i_v_sync_delay_2 <= 1'd0;

       i_data_en_delay_2 <= 1'd0;



end

/********************************************************************************************/



/***************************************arithmetic*******************************************/

//LV1pipeline : mult

always @(posedge      clk)

begin

       mult_r_for_y_18b <= i_r_8b *para_0183_10b;

       mult_r_for_cb_18b <= i_r_8b *para_0101_10b;

       mult_r_for_cr_18b <= i_r_8b *para_0439_10b;

end



always @(posedge      clk)

begin

       mult_g_for_y_18b <= i_g_8b *para_0614_10b;

       mult_g_for_cb_18b <= i_g_8b * para_0338_10b;

       mult_g_for_cr_18b <= i_g_8b *para_0399_10b;

end



always @(posedge      clk)

begin

       mult_b_for_y_18b <= i_b_8b *para_0062_10b;

       mult_b_for_cb_18b <= i_b_8b *para_0439_10b;

       mult_b_for_cr_18b <= i_b_8b *para_0040_10b;

end

//LV2pipeline : add

always @(posedge      clk)

begin

       add_y_0_18b <= mult_r_for_y_18b +mult_g_for_y_18b;

       add_y_1_18b <= mult_b_for_y_18b +para_16_18b;



       add_cb_0_18b <= mult_b_for_cb_18b +para_128_18b;

       add_cb_1_18b <= mult_r_for_cb_18b +mult_g_for_cb_18b;



       add_cr_0_18b <= mult_r_for_cr_18b +para_128_18b;

       add_cr_1_18b <= mult_g_for_cr_18b +mult_b_for_cr_18b;

end

//LV3pipeline : y + cb + cr



assign     sign_cb = (add_cb_0_18b >=add_cb_1_18b);

assign     sign_cr = (add_cr_0_18b >=add_cr_1_18b);

always @(posedge      clk)

begin

       result_y_18b <= add_y_0_18b +add_y_1_18b;

       result_cb_18b <= sign_cb ?(add_cb_0_18b - add_cb_1_18b) : 18'd0;

       result_cr_18b <= sign_cr ?(add_cr_0_18b - add_cr_1_18b) : 18'd0;

end



always @(posedge      clk)

begin

       y_tmp <= result_y_18b[17:8] +{
   
   9'd0,result_y_18b[7]};

       cb_tmp <= result_cb_18b[17:8] +{
   
   9'd0,result_cb_18b[7]};

       cr_tmp <= result_cr_18b[17:8] +{
   
   9'd0,result_cr_18b[7]};

end



//output

assign     o_y_8b   =(y_tmp[9:8] == 2'b00) ? y_tmp[7 : 0] : 8'hFF;

assign     o_cb_8b        =(cb_tmp[9:8] == 2'b00) ? cb_tmp[7 : 0] : 8'hFF;

assign     o_cr_8b  =(cr_tmp[9:8] == 2'b00) ? cr_tmp[7 : 0] : 8'hFF;

/********************************************************************************************/



/***************************************timing***********************************************/

always @(posedge      clk)

begin

       i_h_sync_delay_1 <= i_h_sync;

       i_v_sync_delay_1 <= i_v_sync;

       i_data_en_delay_1 <= i_data_en;



       i_h_sync_delay_2 <= i_h_sync_delay_1;

       i_v_sync_delay_2 <= i_v_sync_delay_1;

       i_data_en_delay_2 <=i_data_en_delay_1;



       i_h_sync_delay_3 <= i_h_sync_delay_2;

       i_v_sync_delay_3 <= i_v_sync_delay_2;

       i_data_en_delay_3 <=i_data_en_delay_2;

end

//--------------------------------------

//timing

//--------------------------------------

assign     o_h_sync = i_h_sync_delay_3;

assign     o_v_sync = i_v_sync_delay_3;

assign    o_data_en = i_data_en_delay_3;



/********************************************************************************************/

Endmodule



代码2////////////////////////////////////////////////////////////////

wire[15:0] rgb;

wire hs;

wire vs;

wire de;                             



wire[7 :0]             o_y_8b;

wire[7 :0]             o_cb_8b;

wire[7 :0]             o_cr_8b;



assignTFT_rgb = {
   
   o_y_8b[7:3],o_y_8b[7:2],o_y_8b[7:3]};     //Y

//assignTFT_rgb = {o_cb_8b[7:3],o_cb_8b[7:2],o_cb_8b[7:3]};  //cb

//assignTFT_rgb = {o_cr_8b[7:3],o_cr_8b[7:2],o_cr_8b[7:3]};  //cr

代码已经过验证,实现效果

image.png

原图

image.png

Y分量实现效果

此方法实现RGB转gray图像效果较好。

5 引用文档

YUV--------------------------------------------------------百度百科

Ycbcr-------------------------------------------------------百度百科

最后欢迎大家关注我的扣扣群,微信公众号。

相关文章
|
18天前
|
监控 算法 数据安全/隐私保护
基于三帧差算法的运动目标检测系统FPGA实现,包含testbench和MATLAB辅助验证程序
本项目展示了基于FPGA与MATLAB实现的三帧差算法运动目标检测。使用Vivado 2019.2和MATLAB 2022a开发环境,通过对比连续三帧图像的像素值变化,有效识别运动区域。项目包括完整无水印的运行效果预览、详细中文注释的代码及操作步骤视频,适合学习和研究。
|
5月前
|
算法 计算机视觉
图像处理之积分图应用四(基于局部均值的图像二值化算法)
图像处理之积分图应用四(基于局部均值的图像二值化算法)
529 0
|
5月前
|
监控 算法 图计算
图像处理之积分图应用三(基于NCC快速相似度匹配算法)
图像处理之积分图应用三(基于NCC快速相似度匹配算法)
73 0
|
4月前
|
算法 异构计算
FPGA强化(10):基于Sobel算法的边缘检测(二)
FPGA强化(10):基于Sobel算法的边缘检测(二)
58 0
|
4月前
|
算法 异构计算
FPGA强化(10):基于Sobel算法的边缘检测(一)
FPGA强化(10):基于Sobel算法的边缘检测
31 0
|
5月前
|
资源调度 算法 计算机视觉
图像处理之积分图应用二(快速边缘保留滤波算法)
图像处理之积分图应用二(快速边缘保留滤波算法)
34 0
|
5月前
|
算法 BI 计算机视觉
图像处理之积分图应用一(半径无关的快速模糊算法)
图像处理之积分图应用一(半径无关的快速模糊算法)
40 0
|
13天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
1月前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于MSER和HOG特征提取的SVM交通标志检测和识别算法matlab仿真
### 算法简介 1. **算法运行效果图预览**:展示算法效果,完整程序运行后无水印。 2. **算法运行软件版本**:Matlab 2017b。 3. **部分核心程序**:完整版代码包含中文注释及操作步骤视频。 4. **算法理论概述**: - **MSER**:用于检测显著区域,提取图像中稳定区域,适用于光照变化下的交通标志检测。 - **HOG特征提取**:通过计算图像小区域的梯度直方图捕捉局部纹理信息,用于物体检测。 - **SVM**:寻找最大化间隔的超平面以分类样本。 整个算法流程图见下图。
|
10天前
|
人工智能 算法 数据安全/隐私保护
基于遗传优化的SVD水印嵌入提取算法matlab仿真
该算法基于遗传优化的SVD水印嵌入与提取技术,通过遗传算法优化水印嵌入参数,提高水印的鲁棒性和隐蔽性。在MATLAB2022a环境下测试,展示了优化前后的性能对比及不同干扰下的水印提取效果。核心程序实现了SVD分解、遗传算法流程及其参数优化,有效提升了水印技术的应用价值。