高质网

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

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单通道实现灰度图像的转换
 

上图为整个图像显示的架构。我们采用RGB565格式。
RGB单通道实现灰度图像FPGA源码:
//----------------------------------------------------------------------
//  R G B to gray
//----------------------------------------------------------------------
wire [15:0] rgb;
assign TFT_rgb = {rgb[15:11],rgb[15:11],1'b0,rgb[15:11]};  //red 
//assign TFT_rgb = {rgb[10:6],rgb[10:5],rgb[10:6]};          //green
//assign TFT_rgb = {rgb[4:0],rgb[4:0],1'b1,rgb[4:0]};          //blue
//assign TFT_rgb = {rgb[4:0],rgb[4:0],1'b0,rgb[4:0]};          //blue

实现结果

原图


Red分量


Green分量


Blue分量

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

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

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;
仿真通过
*/
`timescale 1ns/1ps
modulergb_to_ycbcr(
inputclk,
input[7 : 0]i_r_8b,
input[7 : 0]i_g_8b,
input[7 : 0]i_b_8b,

inputi_h_sync,
inputi_v_sync,
inputi_data_en,

output[7 : 0]o_y_8b,
output[7 : 0]o_cb_8b,
output[7 : 0]o_cr_8b,

outputo_h_sync,
outputo_v_sync,                                                                                                  
outputo_data_en
);


/***************************************parameters*******************************************/
//multiply 256
parameterpara_0183_10b = 10'd47;    //0.183 定点数
parameterpara_0614_10b = 10'd157;
parameterpara_0062_10b = 10'd16;
parameterpara_0101_10b = 10'd26;
parameterpara_0338_10b = 10'd86;
parameterpara_0439_10b = 10'd112;
parameterpara_0399_10b = 10'd102;
parameterpara_0040_10b = 10'd10;
parameterpara_16_18b = 18'd4096;
parameterpara_128_18b = 18'd32768;
/********************************************************************************************/

/***************************************signals**********************************************/
wiresign_cb;
wiresign_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;

regi_h_sync_delay_1;
regi_v_sync_delay_1;
regi_data_en_delay_1;


regi_h_sync_delay_2;
regi_v_sync_delay_2;
regi_data_en_delay_2;

regi_h_sync_delay_3;
regi_v_sync_delay_3;
regi_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*******************************************/
//LV1 pipeline :mult
always @ (posedgeclk)
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 @ (posedgeclk)
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 @ (posedgeclk)
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
//LV2 pipeline : add
always @ (posedgeclk)
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
//LV3 pipeline : y + cb + cr

assignsign_cb = (add_cb_0_18b >= add_cb_1_18b);
assignsign_cr = (add_cr_0_18b >= add_cr_1_18b);
always @ (posedgeclk)
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 @ (posedgeclk)
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
assigno_y_8b = (y_tmp[9:8] == 2'b00) ? y_tmp[7 : 0] : 8'hFF;
assigno_cb_8b = (cb_tmp[9:8] == 2'b00) ? cb_tmp[7 : 0] : 8'hFF;
assigno_cr_8b = (cr_tmp[9:8] == 2'b00) ? cr_tmp[7 : 0] : 8'hFF;
/********************************************************************************************/

/***************************************timing***********************************************/
always @ (posedgeclk)
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
//--------------------------------------
assigno_h_sync = i_h_sync_delay_3;
assigno_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;

assign TFT_rgb = {o_y_8b[7:3],o_y_8b[7:2],o_y_8b[7:3]};     //Y
//assign TFT_rgb = {o_cb_8b[7:3],o_cb_8b[7:2],o_cb_8b[7:3]};  //cb
//assign TFT_rgb = {o_cr_8b[7:3],o_cr_8b[7:2],o_cr_8b[7:3]};  //cr

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


原图

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

001.png扫一扫获取最新精彩内容与学习资料 

 

高质网 倡导尊重与保护知识产权。如发现本站文章存在版权等问题,烦请30天内提供版权疑问、身份证明、版权证明、联系方式等发邮件至1851688011@qq.com我们将及时沟通与处理。!:首页 > 大数据 » FPGA图像处理之rgbtogray算法的实现

()
分享到:

相关推荐

留言与评论(共有 0 条评论)
   
验证码: