转载请注明来源。
色度空间转换RGB空间到YCrCb,按以下公式实现转换:
Y = (0.299R + 0.587G + 0.114B);
Cr = (0.511R - 0.428G - 0.083B) + 128;
Cb = (-0.172R - 0.339G + 0.511B) + 128;
1、定义10组RGB值作为测试向量(文件名:rgb_in.file),编写matlab程序按以上公式转换为YCrCb值。
2、编写可综合的Verilog代码程序(文件名:rgb_to_ycrcb.v)实现以上公式(需有时钟节拍,而非纯组合逻辑),要求添加File Header及Comment信息。
3、编写Testbench(文件名:tb_rgb_to_ycrcb.v),从测试向量文件(文件名:rgb_in.file)读取RGB测试向量值,生成的YCrCb值存入结果文件(文件名:ycrcb_out.file),同时生成波形文件tb_rgb_to_ycrcb.vcd。
4、Verilog仿真后生成的YCrCb值同matlab程序生成的YCrCb值进行比较,看是否一致,如不一致,请分析原因。
5、要求分别采用ModelSim和NCVerilog工具进行仿真,打印提交源代码及波形图,波形图中生成YCrCb值应对齐(即对应同一组RGB值转换而来,应在同一时钟Clock生成;如未对齐,则采用数据延迟。
程序代码
1. rgb_in.txt101011011000110101010011
010110110110101111011010
011011011110111000011011
010101011101001000111101
010100010110101101010100
010101000110011010101010
010111011101110001101010
010110101101010101010101
101001000011101010010101
010110101000100110001110
100010001110101010101011
101011100101000111101101
110101011011011100011001
101011100101011000101010
101010111011100001010101
110111010111101110000010
//************************************************************************//
// Y = (0.299R + 0.587G + 0.114B); //
// Cr = (0.511R - 0.428G - 0.083B) + 128; //
// Cb = (-0.172R - 0.339G + 0.511B) + 128; //
//*************************************************************************//
`timescale 1ns/10ps
module rgb_to_ycbcr(clk,ngreset,R,G,B,Y,Cb,Cr);
input clk,ngreset;
input [7:0] R,G,B;
output[7:0] Y,Cb,Cr;
wire [7:0] Y,Cb,Cr;
/************Y =(1_0011_0010R + 10_0101_1001G + 111_0101B)/1024*************/
reg [16:0] r_256_32;
reg [12:0] r_16_2;
reg [17:0] g_512_64;
reg [12:0] g_16_8;
reg [7:0] g_1;
reg [14:0] b_64_32;
reg [12:0] b_16_4;
reg [7:0] b_1;
always@(posedge clk or negedge ngreset)
if(!ngreset)
begin
r_256_32<=17'h1ffff;
r_16_2 <=13'h1fff;
g_512_64<=18'h3ffff;
g_16_8 <=13'h1fff;
g_1 <=8'hff;
b_64_32 <=15'h7fff;
b_16_4 <=13'h1fff;
b_1 <=8'hff;
end
else
begin
r_256_32<={R,8'd0}+{R,5'd0} ;
r_16_2 <={R,4'd0}+{R,1'd0} ;
g_512_64<={G,9'd0}+{G,6'd0} ;
g_16_8 <={G,4'd0}+{G,3'd0} ;
g_1 <=G;
b_64_32 <={B,6'd0}+{B,5'd0} ;
b_16_4 <={B,4'd0}+{B,2'd0} ;
b_1 <=B;
end
reg[17:0] r_256_32_16_2;
reg[17:0] g_512_64_16_8;
reg[7:0] g_1_d1;
reg[17:0] b_64_32_16_4;
reg[7:0] b_1_d1;
always@(posedge clk or negedge ngreset)
if(!ngreset)
begin
r_256_32_16_2<=18'h3ffff;
g_512_64_16_8<=18'h3ffff;
g_1_d1 <=8'hff;
b_64_32_16_4 <=18'h3ffff;
b_1_d1 <=8'hff;
end
else
begin
r_256_32_16_2<=r_256_32+r_16_2;
g_512_64_16_8<=g_512_64+g_16_8;
g_1_d1 <=g_1;
b_64_32_16_4 <=b_64_32+b_16_4;
b_1_d1 <=b_1;
end
reg[17:0] y_r;
reg[17:0] y_g;
reg[17:0] y_b;
always@(posedge clk or negedge ngreset)
if(!ngreset)
begin
y_r <=18'h3ffff;
y_g <=18'h3ffff;
y_b <=18'h3ffff;
end
else
begin
y_r <=r_256_32_16_2;
y_g <=g_512_64_16_8+g_1_d1;
y_b <=b_64_32_16_4+b_1_d1;
end
reg[17:0] y_rg;
reg[17:0] y_b_d1;
always@(posedge clk or negedge ngreset)
if(!ngreset)
begin
y_rg <=18'h0;
y_b <=18'h0;
end
else
begin
y_rg <=y_r+y_g;
y_b_d1 <=y_b;
end
reg[17:0] y_rgb;
always@(posedge clk or negedge ngreset)
if(!ngreset)
y_rgb<=18'h0;
else
y_rgb<=y_rg+y_b_d1;
wire[7:0] y_tmp;
assign y_tmp=y_rgb[17:10];
/***************Cr = (10_0000_1011R - 1_1011_0110G - 101_0101B)/1024 + 128**************/
reg[17:0] r_512_8;
reg[9:0] r_2_1;
reg[16:0] g_256_128;
reg[13:0] g_32_16;
reg[10:0] g_4_2;
reg[14:0] b_64_16;
reg[10:0] b_4_1;
always@(posedge clk or negedge ngreset)
if(!ngreset)
begin
r_512_8 <= 18'h1ffff;
r_2_1 <= 10'h3ff;
g_256_128<= 17'h1ffff;
g_32_16 <= 14'h3fff;
g_4_2 <= 11'h7ff;
b_64_16 <= 15'h7fff;
b_4_1 <= 11'h7ff;
end
else
begin
r_512_8 <={R,9'd0}+{R,3'd0} ;
r_2_1 <={R,1'd0}+R;
g_256_128<={G,8'd0}+{G,7'd0} ;
g_32_16 <={G,5'd0}+{G,4'd0} ;
g_4_2 <={G,2'd0}+{G,1'd0} ;
b_64_16 <={B,6'd0}+{B,4'd0} ;
b_4_1 <={B,2'd0}+B;
end
reg[17:0] r_512_8_2_1;
reg[17:0] g_256_128_32_16;
reg[10:0] g_4_2_d1;
reg[17:0] b_64_16_4_1;
always@(posedge clk or negedge ngreset)
if(!ngreset)
begin
r_512_8_2_1 <=18'h3ffff;
g_256_128_32_16 <=18'h3ffff;
g_4_2_d1 <=11'hff;
b_64_16_4_1 <=18'h3ffff;
end
else
begin
r_512_8_2_1 <= r_512_8+r_2_1;
g_256_128_32_16 <= g_256_128+g_32_16;
g_4_2_d1 <= g_4_2;
b_64_16_4_1 <= b_64_16+b_4_1;
end
reg[17:0] r_512_8_2_1_d1;
reg[17:0] g_256_128_32_16_4_2;
reg[17:0] b_64_16_4_1_d1;
always@(posedge clk or negedge ngreset)
if(!ngreset)
begin
r_512_8_2_1_d1 <=18'h3ffff;
g_256_128_32_16_4_2<=18'h3ffff;
b_64_16_4_1_d1 <=18'h3ffff;
end
else
begin
r_512_8_2_1_d1 <=r_512_8_2_1;
g_256_128_32_16_4_2<=g_256_128_32_16+g_4_2_d1;
b_64_16_4_1_d1 <=b_64_16_4_1;
end
reg[17:0] cr_r;
reg[17:0] cr_gb;
always@(posedge clk or negedge ngreset)
if(!ngreset)
begin
cr_r <=18'd0;
cr_gb<=18'd0;
end
else
begin
cr_r <=r_512_8_2_1_d1;
cr_gb<=g_256_128_32_16_4_2+b_64_16_4_1_d1;
end
reg[17:0] cr_rgb;
always@(posedge clk or negedge ngreset)
if(!ngreset)
cr_rgb<=18'h0;
else if(cr_r>cr_gb)
cr_rgb<=cr_r-cr_gb;
else
cr_rgb<=cr_gb-cr_r;
wire[7:0] cr_rgb_d;
assign cr_rgb_d=cr_rgb[17:10];
reg[17:0] cr_r_d1;
reg[17:0] cr_gb_d1;
always@(posedge clk or negedge ngreset)
if(!ngreset)
{cr_r_d1,cr_gb_d1}<=36'h0;
else
{cr_r_d1,cr_gb_d1}<={cr_r,cr_gb};
reg[7:0] cr_tmp;
always@(posedge clk or negedge ngreset)
if(!ngreset)
cr_tmp<=8'd0;
else if(cr_r_d1>cr_gb_d1)
cr_tmp<=8'd128+cr_rgb_d;
else
cr_tmp<=8'd128-cr_rgb_d;
/***********Cb = (-1011_0000R - 1_0101_1011G + 10_0000_1011B)/1024 + 128********/
reg[15:0] r_128_32;
reg[12:0] r_16;
reg[16:0] g_256_64;
reg[9:0] g_2_1;
reg[17:0] b_512_8;
reg[9:0] b_2_1;
always@(posedge clk or negedge ngreset)
if(!ngreset)
begin
r_128_32<=16'hffff;
r_16 <=13'h1fff;
g_256_64<=17'h1ffff;
g_2_1 <=10'h3ff;
b_512_8 <=18'h3ffff;
b_2_1 <=10'h3ff;
end
else
begin
r_128_32<={R,7'd0}+{R,5'd0} ;
r_16 <={R,4'd0};
g_256_64<={G,8'd0}+{G,6'd0} ;
g_2_1 <={G,1'd0}+G ;
b_512_8 <={B,9'd0}+{B,3'd0} ;
b_2_1 <={B,1'd0}+B ;
end
reg[17:0] r_128_32_16;
reg[17:0] g_256_64_16_8;
reg[9:0] g_2_1_d1;
reg[17:0] b_512_8_2_1;
always@(posedge clk or negedge ngreset)
if(!ngreset)
begin
r_128_32_16 <=18'h3ffff;
g_256_64_16_8<=18'h3ffff;
g_2_1_d1 <=10'h3ff;
b_512_8_2_1 <=18'h3ffff;
end
else
begin
r_128_32_16 <= r_128_32+r_16;
g_256_64_16_8 <= g_256_64+g_16_8;
g_2_1_d1 <= g_2_1;
b_512_8_2_1 <= b_512_8+b_2_1;
end
reg[17:0] cb_r;
reg[17:0] cb_g;
reg[17:0] cb_b;
always@(posedge clk or negedge ngreset)
if(!ngreset)
begin
cb_r<=18'h3ffff;
cb_g<=18'h3ffff;
cb_b<=18'h3ffff;
end
else
begin
cb_r<=r_128_32_16;
cb_g<=g_256_64_16_8+g_2_1_d1;
cb_b<=b_512_8_2_1;
end
reg[17:0] cb_rg;
reg[17:0] cb_b_d1;
always@(posedge clk or negedge ngreset)
if(!ngreset)
begin
cb_rg<=18'h3ffff;
cb_b_d1<=18'h3ffff;
end
else
begin
cb_rg<=cb_r+cb_g;
cb_b_d1<=cb_b;
end
reg[17:0] cb_rgb;
always@(posedge clk or negedge ngreset)
if(!ngreset)
cb_rgb<=18'h3ffff;
else if(cb_rg>cb_b_d1)
cb_rgb<=cb_rg-cb_b_d1;
else
cb_rgb<=cb_b_d1-cb_rg;
wire[7:0] cb_rgb_d1;
assign cb_rgb_d1=cb_rgb[17:10];
reg[7:0] cb_tmp;
always@(posedge clk or negedge ngreset)
if(!ngreset)
cb_tmp<=8'h0;
else if(cb_rg>cb_b_d1)
cb_tmp<=8'd128-cb_rgb_d1;
else
cb_tmp<=8'd128+cb_rgb_d1;
reg[7:0] y_tmp_d1;
always@(posedge clk or negedge ngreset)
if(!ngreset)
y_tmp_d1<=8'd0;
else
y_tmp_d1<=y_tmp;
assign Y=y_tmp_d1;
assign Cb=cb_tmp;
assign Cr=cr_tmp;
endmodule
3. tb_rgb_to_ycbcr.v
`timescale 1ns/1ps
module tb_rgb_to_ycbcr();
reg clk,ngreset;
wire [7:0] R,G,B;
wire [7:0] Y,Cb,Cr;
initial
begin
clk=0;
ngreset=1;
#50 ngreset=0;
#100 ngreset=1;
end
always #5 clk=~clk;
reg[23:0] rgb_in[0:15];
initial begin
$readmemb("rgb_in.txt",rgb_in);
end
integer i;
always@(posedge clk or negedge ngreset)
if(!ngreset)
i<=0;
else if(i==15)
i<=0;
else
i<=i+1;
wire[23:0] data;
assign data=rgb_in[i];
assign R = data[23:16];
assign G = data[15:8 ];
assign B = data[7 :0 ];
rgb_to_ycbcr rgb_to_ycbcr_tmpt(.R(R),
.G(G),
.B(B),
.clk(clk),
.ngreset(ngreset),
.Y(Y),
.Cb(Cb),
.Cr(Cr));
initial
begin
$fsdbDumpfile("csc.fsdb");
$fsdbDumpvars(0,tb_rgb_to_ycbcr);
#100000 $finish;
end
//initial begin
// $dumpfile("ycbcr_out.dump");
// $dumplimit(409600);
// $dumpvars(0,rgb_to_ycbcr_tmpt);
// $dumpvars(0,rgb_to_ycbcr_tmpt.Y,rgb_to_ycbcr_tmpt.Cb,rgb_to_ycbcr_tmpt.Cr);
//end
endmodule
仿真波形图
1. Modelsim仿真波形图
2. Nc-verilog仿真波形图
总结
1. 由于本代码采用可综合的代码方式编写,因此代码的长度较长,例如加法时候只相加两个数,用移位的方式实现乘法,以后可以采用乘法器加以改进。
2. 本代码完整实现了色度空间转换的任务,并且是可综合的代码,最后输出的YCBCR信号比输入的RGB信号延迟了6个时钟,三个输出信号实现对齐。
3. 通过本代码的编写熟悉了从文件中读取数据和输出数据到文件的过程。
4. 熟悉了通过移位实现乘法的思想,对以后编写代码有启发意义。