在图像处理过程中通常需要会对图像类型进行互相转换,在此给出两种转换的工程代码。
1、在将ycbCr422转rgb时,通常先将ycbcr422转换成ycbcr444再讲ycbcr444转成rgb
1.1 ycbcr422转换成ycbcr444
`timescale 1ns/1ns
module ZYP_YCbCr422_YCbCr444
(
//global clock
input clk, //cmos video pixel clock
input rst_n, //global reset
//CMOS 16Bit YCbCr data input: {CbYCrYCbYCrY}
input per_frame_vsync, //Prepared Image data vsync valid signal
input per_frame_href, //Prepared Image data href vaild signal
input per_frame_clken, //Prepared Image data output/capture enable clock
input [15:0] per_frame_YCbCr, //Prepared Image data of YCbCr 4:2:2 {CbY} {CrY}
//CMOS YCbCr444 data output
output post_frame_vsync, //Processed Image data vsync valid signal
output post_frame_href, //Processed Image data href vaild signal
output post_frame_clken, //Processed Image data output/capture enable clock
output reg [7:0] post_img_Y, //Processed Image data of YCbCr 4:4:4
output reg [7:0] post_img_Cb, //Processed Image data of YCbCr 4:4:4
output reg [7:0] post_img_Cr //Processed Image data of YCbCr 4:4:4
);
//------------------------------------------
//lag n pixel clocks
reg [4:0] post_frame_vsync_r;
reg [4:0] post_frame_href_r;
reg [4:0] post_frame_clken_r;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
post_frame_vsync_r <= 0;
post_frame_href_r <= 0;
post_frame_clken_r <= 0;
end
else
begin
post_frame_vsync_r <= {post_frame_vsync_r[3:0], per_frame_vsync};
post_frame_href_r <= {post_frame_href_r[3:0], per_frame_href};
post_frame_clken_r <= {post_frame_clken_r[3:0], per_frame_clken};
end
end
assign post_frame_vsync = post_frame_vsync_r[4];
assign post_frame_href = post_frame_href_r[4];
assign post_frame_clken = post_frame_clken_r[4];
wire yuv_process_href = per_frame_href || post_frame_href_r[3];
wire yuv_process_clken = per_frame_clken || post_frame_clken_r[3];
//-------------------------------------------
//convert YCbCr422 to YCbCr444
reg [2:0] yuv_state;
reg [7:0] mY0, mY1, mY2, mY3;
reg [7:0] mCb0, mCb1;
reg [7:0] mCr0, mCr1;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
yuv_state <= 3'd0;
{mY0, mCb0, mCr0} <= {8'h0, 8'h0, 8'h0};
mY1 <= 8'h0;
{mY2, mCb1, mCr1} <= {8'h0, 8'h0, 8'h0};
mY3 <= 8'h0;
{post_img_Y, post_img_Cb, post_img_Cr} <= {8'h0, 8'h0, 8'h0};
end
else if(yuv_process_href) //lag 2 data enable clock and need 2 more clocks
begin
if(yuv_process_clken) //lag 2 data enable clock and need 2 more clocks
case(yuv_state) //{Cb,Y},{Cr,Y}---YCbCr
3'd0: begin //reg p0
yuv_state <= 3'd1;
{mCb0, mY0} <= per_frame_YCbCr;
end
3'd1: begin //reg p1
yuv_state <= 3'd2;
{mCr0, mY1} <= per_frame_YCbCr;
end
3'd2: begin //p0; reg p2
yuv_state <= 3'd3;
{mCb1, mY2} <= per_frame_YCbCr;
{post_img_Y, post_img_Cb, post_img_Cr} <= {mY0, mCb0, mCr0};
end
3'd3: begin //p1; reg p3
yuv_state <= 3'd4;
{mCr1, mY3} <= per_frame_YCbCr;
{post_img_Y, post_img_Cb, post_img_Cr} <= {mY1, mCb0, mCr0};
end
3'd4: begin //p2; reg p0
yuv_state <= 3'd5;
{mCb0, mY0} <= per_frame_YCbCr;
{post_img_Y, post_img_Cb, post_img_Cr} <= {mY2, mCb1, mCr1};
end //p3; reg p1
3'd5: begin
yuv_state <= 3'd2;
{mCr0, mY1} <= per_frame_YCbCr;
{post_img_Y, post_img_Cb, post_img_Cr} <= {mY3, mCb1, mCr1};
end
endcase
else
begin
yuv_state <= yuv_state;
{mY0, mCb0, mCr0} <= {mY0, mCb0, mCr0};
mY1 <= mY1;
{mY2, mCb1, mCr1} <= {mY2, mCb1, mCr1};
mY3 <= mY3;
{post_img_Y, post_img_Cb, post_img_Cr} <= {post_img_Y, post_img_Cb, post_img_Cr};
end
end
else
begin
yuv_state <= 3'd0;
{mY0, mCb0, mCr0} <= {8'h0, 8'h0, 8'h0};
{mY1, mCb1, mCr1} <= {8'h0, 8'h0, 8'h0};
{post_img_Y, post_img_Cb, post_img_Cr} <= {8'h0, 8'h0, 8'h0};
end
end
endmodule
1.2 ycbcr444转成rgb
`timescale 1ns/1ns
module VIP_YCbCr444_RGB888
(
//global clock
input clk, //cmos video pixel clock
input rst_n, //global reset
//CMOS YCbCr444 data output
input per_frame_vsync, //Prepared Image data vsync valid signal
input per_frame_href, //Prepared Image data href vaild signal
input per_frame_clken, //Prepared Image data output/capture enable clock
input [7:0] per_img_Y, //Prepared Image data of Y
input [7:0] per_img_Cb, //Prepared Image data of Cb
input [7:0] per_img_Cr, //Prepared Image data of Cr
//CMOS RGB888 data output
output post_frame_vsync, //Processed Image data vsync valid signal
output post_frame_href, //Processed Image data href vaild signal
output post_frame_clken, //Processed Image data output/capture enable clock
output [7:0] post_img_red, //Prepared Image green data to be processed
output [7:0] post_img_green, //Prepared Image green data to be processed
output [7:0] post_img_blue //Prepared Image blue data to be processed
);
//--------------------------------------------
/*********************************************
R = 1.164(Y-16) + 1.596(Cr-128)
G = 1.164(Y-16) - 0.391(Cb-128) - 0.813(Cr-128)
B = 1.164(Y-16) + 2.018(Cb-128)
->
R = 1.164Y + 1.596Cr - 222.912
G = 1.164Y - 0.391Cb - 0.813Cr + 135.488
B = 1.164Y + 2.018Cb - 276.928
->
R << 9 = 596Y + 817Cr - 114131
G << 9 = 596Y - 200Cb - 416Cr + 69370
B << 9 = 596Y + 1033Cb - 141787
**********************************************/
reg [19:0] img_Y_r1; //8 + 9 + 1 = 18Bit
reg [19:0] img_Cb_r1, img_Cb_r2;
reg [19:0] img_Cr_r1, img_Cr_r2;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
img_Y_r1 <= 0;
img_Cb_r1 <= 0; img_Cb_r2 <= 0;
img_Cr_r1 <= 0; img_Cr_r2 <= 0;
end
else
begin
img_Y_r1 <= per_img_Y * 18'd596;
img_Cb_r1 <= per_img_Cb * 18'd200;
img_Cb_r2 <= per_img_Cb * 18'd1033;
img_Cr_r1 <= per_img_Cr * 18'd817;
img_Cr_r2 <= per_img_Cr * 18'd416;
end
end
//--------------------------------------------
/**********************************************
R << 9 = 596Y + 817Cr - 114131
G << 9 = 596Y - 200Cb - 416Cr + 69370
B << 9 = 596Y + 1033Cb - 141787
**********************************************/
reg [19:0] XOUT;
reg [19:0] YOUT;
reg [19:0] ZOUT;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
XOUT <= 0;
YOUT <= 0;
ZOUT <= 0;
end
else
begin
XOUT <= (img_Y_r1 + img_Cr_r1 - 20'd114131)>>9;
YOUT <= (img_Y_r1 - img_Cb_r1 - img_Cr_r2 + 20'd69370)>>9;
ZOUT <= (img_Y_r1 + img_Cb_r2 - 20'd141787)>>9;
end
end
//------------------------------------------
//Divide 512 and get the result
//{xx[19:11], xx[10:0]}
reg [7:0] R, G, B;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
R <= 0;
G <= 0;
B <= 0;
end
else
begin
R <= XOUT[10] ? 8'd0 : (XOUT[9:0] > 9'd255) ? 8'd255 : XOUT[7:0];
G <= YOUT[10] ? 8'd0 : (YOUT[9:0] > 9'd255) ? 8'd255 : YOUT[7:0];
B <= ZOUT[10] ? 8'd0 : (ZOUT[9:0] > 9'd255) ? 8'd255 : ZOUT[7:0];
end
end
//------------------------------------------
//lag n clocks signal sync
reg [2:0] post_frame_vsync_r;
reg [2:0] post_frame_href_r;
reg [2:0] post_frame_clken_r;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
post_frame_vsync_r <= 0;
post_frame_href_r <= 0;
post_frame_clken_r <= 0;
end
else
begin
post_frame_vsync_r <= {post_frame_vsync_r[1:0], per_frame_vsync};
post_frame_href_r <= {post_frame_href_r[1:0], per_frame_href};
post_frame_clken_r <= {post_frame_clken_r[1:0], per_frame_clken};
end
end
assign post_frame_vsync = post_frame_vsync_r[2];
assign post_frame_href = post_frame_href_r[2];
assign post_frame_clken = post_frame_clken_r[2];
assign post_img_red = post_frame_href ? R : 8'd0;
assign post_img_green = post_frame_href ? G : 8'd0;
assign post_img_blue = post_frame_href ? B : 8'd0;
endmodule
2、同样将rgb转ycbcr422时,也通常先将rgb转成ycbcr444,再讲ycbcr444在转成ycbcr422
2.1 rgb转成ycbcr444
`timescale 1ns/1ps
module RGB_to_YCbCr444_Processor(
input clk,
input wire[7 : 0] i_r_8b,
input wire[7 : 0] i_g_8b,
input wire[7 : 0] i_b_8b,
input wire i_h_sync,
input wire i_v_sync,
input wire i_data_en,
output wire[7 : 0] o_y_8b,
output wire[7 : 0] o_cb_8b,
output wire[7 : 0] o_cr_8b,
output reg o_h_sync,
output reg o_v_sync,
output reg o_data_en
);
/***************************************parameters*******************************************/
//multiply 256
/*
parameter para_0183_10b = 10'd47;
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_0183_10b = 10'd66;
parameter para_0614_10b = 10'd129;
parameter para_0062_10b = 10'd25;
parameter para_0101_10b = 10'd38;
parameter para_0338_10b = 10'd74;
parameter para_0439_10b = 10'd112;
parameter para_0399_10b = 10'd94;
parameter para_0040_10b = 10'd18;
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 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;
/********************************************************************************************/
/***************************************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;
o_h_sync <= 1'd0;
o_v_sync <= 1'd0;
o_data_en <= 1'd0;
end
/********************************************************************************************/
/***************************************arithmetic*******************************************/
//LV1 pipeline : mult
always @ (posedge clk)
begin
mult_r_for_y_18b <= i_r_8b * para_0183_10b;//*47
mult_r_for_cb_18b <= i_r_8b * para_0101_10b;//*26
mult_r_for_cr_18b <= i_r_8b * para_0439_10b;//*112
end
always @ (posedge clk)
begin
mult_g_for_y_18b <= i_g_8b * para_0614_10b;//*157
mult_g_for_cb_18b <= i_g_8b * para_0338_10b;//*86
mult_g_for_cr_18b <= i_g_8b * para_0399_10b;//*102
end
always @ (posedge clk)
begin
mult_b_for_y_18b <= i_b_8b * para_0062_10b;//*16
mult_b_for_cb_18b <= i_b_8b * para_0439_10b;//*112
mult_b_for_cr_18b <= i_b_8b * para_0040_10b;//*10
end
//LV2 pipeline : 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;//+4096
add_cb_0_18b <= mult_b_for_cb_18b + para_128_18b;//+32768
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;//+32768
add_cr_1_18b <= mult_g_for_cr_18b + mult_b_for_cr_18b;
end
//LV3 pipeline : 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
//output
assign o_y_8b = (result_y_18b[17:16] == 2'b00) ? result_y_18b[15 : 8] : 8'hFF;
assign o_cb_8b = (result_cb_18b[17:16] == 2'b00) ? result_cb_18b[15 : 8] : 8'hFF;
assign o_cr_8b = (result_cr_18b[17:16] == 2'b00) ? result_cr_18b[15 : 8] : 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;
o_h_sync <= i_h_sync_delay_2;
o_v_sync <= i_v_sync_delay_2;
o_data_en <= i_data_en_delay_2;
end
endmodule
2.2 ycbcr444在转成ycbcr422
`timescale 1ns/1ps
module ycbcr444_to_ycbcr422(
input sys_clk, /*系统时钟*/
input i_hs, /*视频输入行同步*/
input line_end, /*在某些情况下可能没有行同步信号,只能自己生成一个行结束信号 */
input i_vs,
input i_de, /*视频数据有效*/
input [7:0] i_y, /*视频输入Y分量 */
input [7:0] i_cb, /*视频输入Cb(U)分量 */
input [7:0] i_cr, /*视频输入Cr(V)分量 */
output o_hs,
output o_vs,
output o_de, /* 输出数据有效*/
output[7:0] o_y, /* 输出视频Y分量*/
output[7:0] o_c, /*输出视频CbCr分量复合,先输出Cb,后输出Cr */
output[19:0] data_out
);
reg i_de_d0 = 1'b0;
reg i_de_d1 = 1'b0;
reg i_hs_d0 = 1'b0;
reg i_hs_d1 = 1'b0;
reg i_vs_d0 = 1'b0;
reg i_vs_d1 = 1'b0;
reg [7:0] i_y_d0 = 8'd0;
reg [7:0] i_y_d1 = 8'd0;
reg [7:0] i_cb_d0 = 8'd0;
reg [7:0] i_cr_d0 = 8'd0;
reg [7:0] cb = 8'd0;
reg [7:0] cr = 8'd0;
reg [7:0] cr_d0 = 8'd0;
reg line_end_d0;
reg line_end_d1;
wire[8:0] cb_add;
wire[8:0] cr_add;
reg c_flag = 1'b0;
assign cb_add = {1'b0,i_cb} + {1'b0,i_cb_d0}; /*两个像素的cb相加,待求平均值 */
assign cr_add = {1'b0,i_cr} + {1'b0,i_cr_d0}; /*两个像素的cr相加,待求平均值 */
always@(posedge sys_clk)
begin
if(i_hs | i_vs)
begin
i_y_d0 <= 8'h10;
i_cb_d0 <= 8'h80;
i_cr_d0 <= 8'h80;
line_end_d0 <= 1'b0;
end
else if(i_de)
begin
i_y_d0 <= i_y;
i_cb_d0 <= i_cb;
i_cr_d0 <= i_cr;
line_end_d0 <= line_end;
end
else
begin
i_y_d0 <= i_y_d0;
i_cb_d0 <= i_cb_d0;
i_cr_d0 <= i_cr_d0;
line_end_d0 <= line_end_d0;
end
i_de_d0 <= i_de;
end
always@(posedge sys_clk)
begin
if(i_hs | i_vs)
begin
i_y_d1 <= 8'h10;
cb <= 8'h80;
cr <= 8'h80;
line_end_d1 <= 1'b0;
end
else if(i_de_d0)
begin
i_y_d1 <= i_y_d0;
cb <= cb_add[8:1];
cr <= cr_add[8:1];
line_end_d1 <= line_end_d0;
end
else
begin
i_y_d1 <= i_y_d1;
cb <= cb;
cr <= cr;
line_end_d1 <= line_end_d1;
end
i_de_d1 <= i_de_d0;
end
always@(posedge sys_clk)
begin
i_hs_d0 <= i_hs;
i_hs_d1 <= i_hs_d0;
end
always@(posedge sys_clk)
begin
i_vs_d0 <= i_vs;
i_vs_d1 <= i_vs_d0;
end
always@(posedge sys_clk)
begin
if((i_hs_d0 & ~i_hs_d1) | line_end_d1)
begin
c_flag <= 1'b0;
end
else if(i_de_d1)///////////////////////////
begin
c_flag <= ~c_flag;/*该寄存器标记C(色度信号)取Cb还是Cr */
end
else
begin
c_flag <= c_flag;
end
end
always@(posedge sys_clk)
begin
if(i_de_d1)
cr_d0 <= cr;
else
cr_d0 <= cr_d0;
end
assign o_c = c_flag ? cr_d0 : cb;/*C(色度信号)的选取 */
assign o_y = i_y_d1;/////////////////
assign o_de = i_de_d1;/////////////////
assign o_hs = i_hs_d1;
assign o_vs = i_vs_d1;
assign data_out[19:10] = {i_y_d1, 2'b0};
assign data_out[9:0] = {c_flag ? cr_d0 : cb, 2'b0};
endmodule