RGB—YCbCr图像转换------图像处理
介绍
通过MATLAB把RGB888的图像转换为RGB332的图像数据,然后通过MATLAB保存到TXT文本当中(因为332格数据为8bit正好一个字节,串口正好一次发送一个像素点,怎么转换之前写过 哈哈)。然后通过将RGB332转换为RGB565格式数据存入到SDRAM中,然后通过VGA驱动模块读出数据进行RGB—YCbCr图像转换最后通过VGA显示,需要注意的是在RGB—YCbCr图像转换过程中有数据计算需要打拍同步行场信号。
整体流程
首先通过串口接收端接收上位机发送的640 *480大小的图片数据,然后存入到SDRAM中,通过VGA驱动模块读取数据,然后进行RGB—YCbCr图像转换,最后通过VGA显示。具体RTL视图如下所示。
RGB—YCbCr图像转换原理
RGB—YCbCr图像转换公式如下所示。
Y = 0.299R +0.587G + 0.114B
Cb = 0.568(B-Y) + 128 = -0.172R-0.339G + 0.511B + 128
CR = 0.713(R-Y) + 128 = 0.511R-0.428G -0.083B + 128
因为FPGA不能进行浮点数运算所以将上式中带有小数部分扩大256倍然后再右移8bit,如下式所示
Y = (77 *R + 150*G + 29 *B)>>8
Cb = (-43*R - 85 *G + 128*B)>>8 + 128
Cr = (128*R - 107*G - 21 *B)>>8 + 128
为防止负数出现把128加入到括号内,如下式所示。
Y = (77 *R + 150*G + 29 *B )>>8
Cb = (-43*R - 85 *G + 128*B + 32768)>>8
Cr = (128*R - 107*G - 21 *B + 32768)>>8
具体步骤
步骤(1)
因为RGB—YCbCr图像转换过程中数据都是以8bit位宽进行的,所以现将RGB565数据转换成RGB888格式数据,代码如下所示。
//RGB565 to RGB 888
assign rgb888_r = {img_red , img_red[4:2] };
assign rgb888_g = {img_green, img_green[5:4]};
assign rgb888_b = {img_blue , img_blue[4:2] };
步骤(2)
进行公式中的全部相乘操作代码如下所示
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
rgb_r_m0 <= 16'd0;
rgb_r_m1 <= 16'd0;
rgb_r_m2 <= 16'd0;
rgb_g_m0 <= 16'd0;
rgb_g_m1 <= 16'd0;
rgb_g_m2 <= 16'd0;
rgb_b_m0 <= 16'd0;
rgb_b_m1 <= 16'd0;
rgb_b_m2 <= 16'd0;
end
else begin
rgb_r_m0 <= rgb888_r * 8'd77 ;
rgb_r_m1 <= rgb888_r * 8'd43 ;
rgb_r_m2 <= rgb888_r * 8'd128;
rgb_g_m0 <= rgb888_g * 8'd150;
rgb_g_m1 <= rgb888_g * 8'd85 ;
rgb_g_m2 <= rgb888_g * 8'd107;
rgb_b_m0 <= rgb888_b * 8'd29 ;
rgb_b_m1 <= rgb888_b * 8'd128;
rgb_b_m2 <= rgb888_b * 8'd21 ;
end
end
步骤(3)
进行公示中的全部相加操作代码如下所示
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
img_y0 <= 16'd0;
img_cb0 <= 16'd0;
img_cr0 <= 16'd0;
end
else begin
img_y0 <= rgb_r_m0 + rgb_g_m0 + rgb_b_m0;
img_cb0 <= rgb_b_m1 - rgb_r_m1 - rgb_g_m1 + 16'd32768;
img_cr0 <= rgb_r_m2 - rgb_g_m2 - rgb_b_m2 + 16'd32768;
end
end
步骤(4)
进行公示中的移位操作代码如下所示
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
img_y1 <= 8'd0;
img_cb1 <= 8'd0;
img_cr1 <= 8'd0;
end
else begin
img_y1 <= img_y0 >> 8;
img_cb1 <= img_cb0 >> 8;
img_cr1 <= img_cr0 >> 8;
end
end
步骤(5)
打三拍进行行场同步代码如下所示
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
pre_frame_vsync_d <= 3'd0;
pre_frame_hsync_d <= 3'd0;
pre_frame_de_d <= 3'd0;
end
else begin
pre_frame_vsync_d <= {pre_frame_vsync_d[1:0], pre_frame_vsync};
pre_frame_hsync_d <= {pre_frame_hsync_d[1:0], pre_frame_hsync};
pre_frame_de_d <= {pre_frame_de_d[1:0] , pre_frame_de };
end
end
assign post_frame_vsync = pre_frame_vsync_d[2] ;
assign post_frame_hsync = pre_frame_hsync_d[2] ;
assign post_frame_de = pre_frame_de_d[2] ;
将Y分量高5位、高6位、高5位数据作为VGA显示的红、绿、蓝三通道输入数据代码如下所示
assign vga_rgb = {img_y_w[7:3],img_y_w[7:2],img_y_w[7:3]} ;
最后通过VGA显示结果如下所示
原图
YCbCr格式图片