YCbCr是色彩空间的一种,通常会用于影片中的影像连续处理,或是数字摄影系统中。Y(luminance)为颜色的亮度和浓度、Cb(chrominance-blue)为蓝色色度分量,Cr(chrominance-rad)则为红色色度分量。
从摄像头采集到的RGB数据转换到显示器使用的YCbCr数据,按照官方给出的计算公式
Y = 0.299 R + 0.587 G + 0.114 B
Cb = -0.1687 R - 0.3313 G + 0.5 B + 128
Cr = 0.5 R - 0.4187 G - 0.0813 B + 128
我们的数据转换模块,也正是基于上述转换公式设计
考虑到使用Verilog语言无法描述浮点数运算,所以将所等式两边同时*256(即2^8)后,再统一除2^8即可得到正确的值。
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*256后带入括号
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
module RGB888_To_YCbCr444
(
//system signal
input clk, //cmos video pixel clock
input rst_n, //global reset
//Image data and control signals prepred to be processd
input per_frame_vsync,
input per_frame_href,
input per_frame_clken,
wire [7:0] per_img_red,
wire [7:0] per_img_green,
wire [7:0] per_img_blue,
//Image data and control signals have been processd
output new_frame_vsync,
output new_frame_href,
output new_frame_clken,
output [7:0] img_Y,
output [7:0] img_Cb,
output [7:0] img_Cr
);
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
在这里我们进行一个流水线设计,将先乘再加的转换公式中乘和加的部分断开
//step 1 operate the multiplication
reg [15:0] img_red_r0, img_red_r1, img_red_r2;
reg [15:0] img_green_r0, img_green_r1, img_green_r2;
reg [15:0] img_blue_r0, img_blue_r1, img_blue_r2;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
img_red_r0 <= 0;
img_red_r1 <= 0;
img_red_r2 <= 0;
img_green_r0 <= 0;
img_green_r1 <= 0;
img_green_r2 <= 0;
img_blue_r0 <= 0;
img_blue_r1 <= 0;
img_blue_r2 <= 0;
end
else
begin
img_red_r0 <= per_img_red * 8'd77;
img_red_r1 <= per_img_red * 8'd43;
img_red_r2 <= per_img_red * 8'd128;
img_green_r0 <= per_img_green * 8'd150;
img_green_r1 <= per_img_green * 8'd85;
img_green_r2 <= per_img_green * 8'd107;
img_blue_r0 <= per_img_blue * 8'd29;
img_blue_r1 <= per_img_blue * 8'd128;
img_blue_r2 <= per_img_blue * 8'd21;
end
end
接下来是按照公式和对应位置将乘积对应相加
//step 2 add the product
reg [15:0] img_Y_r0;
reg [15:0] img_Cb_r0;
reg [15:0] img_Cr_r0;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
img_Y_r0 <= 0;
img_Cb_r0 <= 0;
img_Cr_r0 <= 0;
end
else
begin
img_Y_r0 <= img_red_r0 + img_green_r0 + img_blue_r0;
img_Cb_r0 <= img_blue_r1 - img_red_r1 - img_green_r1 + 16'd32768;
img_Cr_r0 <= img_red_r2 + img_green_r2 + img_blue_r2 + 16'd32768;
end
end
最后一步只需要将计算出的数据除以256,便完成了RGB到YCbCr的转换
reg [7:0] img_Y_r1;
reg [7:0] img_Cb_r1;
reg [7:0] img_Cr_r1;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
img_Y_r1 <= 0;
img_Cb_r1 <= 0;
img_Cr_r1 <= 0;
end
else
begin
img_Y_r1 <= img_Y_r0[15:8];
img_Cb_r1 <= img_Cb_r0[15:8];
img_Cr_r1 <= img_Cr_r0[15:8];
end
end
接下来就是对时序的调整了,在上面的转换过程中,我们采取了三段流水线的处理方式,所以控制信号为了保持同步要打三拍
reg [2:0] per_frame_vsync_r;
reg [2:0] per_frame_href_r;
reg [2:0] per_frame_clken_r;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
per_frame_vsync_r <= 0;
per_frame_href_r <= 0;
per_frame_clken_r <= 0;
end
else
begin
per_frame_vsync_r <= {per_frame_vsync_r[1:0], per_frame_vsync};
per_frame_href_r <= {per_frame_href_r[1:0], per_frame_href};
per_frame_clken_r <= {per_frame_clken_r[1:0], per_frame_clken};
end
end
assign new_frame_vsync = per_frame_vsync_r[2];
assign new_frame_href = per_frame_href_r[2];
assign new_frame_clken = per_frame_clken_r[2];
将处理好的YCrCb接到输出上
assign img_Y = new_frame_href ? img_Y_r1 : 8'd0;
assign img_Cb = new_frame_href ? img_Cb_r1: 8'd0;
assign img_Cr = new_frame_href ? img_Cr_r1: 8'd0;
到此为止,所有模块功能完成
endmodule