视频色度空间变换
0赞由于使用VGA进行显示,需要对色彩进行CrCbY数据进行变换为RGB数据,色彩空间变换公式为:
R = 1.164(Y-16) + 1.596(Cr-128)
G = 1.164(Y-16) - 0.813(Cr-128) -0 .392(Cb-128)
B = 1.164(Y-16) + 2.017(Cb-128)
由上面的公式可知,色度空间变换涉及到浮点数运算。在硬件描述语言中,对于浮点数的运算,会占用很多的资源,速度比较慢。所以通常运算方法是将小数乘以一个数A转化为整数,这个数A必须取2的幂次。这样当计算完成后,将结果除以这个数A,就实现了浮点数的运算。由于A为2的整数次幂,所以除以A就可转换为对A进行移位操作来实现。我们取A为1024,则公式(2-2)可以变换为公式(3-3):
R_B =1024×R=[1.164(Y-16) +1.596(Cr-128)]×1024
G_B =1024×G=[1.164(Y-16)-0.813(Cr-128)-0.392(Cb-128)]×1024 式(3-3)
B_B =1024×B=[1.164(Y-16)+2.017(Cb-128)]×1024
这样,设计程序计算出公式(2-3)的R_B,G_Bt,B_B。最后将计算结果R_B,G_B,B_B均除以1024,即右移10位,即可得到原来R,G,B的值。
//******************************************************************************************
//* COMPANY : TERASIC. www.terasic.com (c) 2005 all rights reserved. *
//* NAME : ITU-R BT.656 YCrCb 4:2:2 DECODER *
//* Created : 7/5/2005 *
//* Author : Joe Yang *
//******************************************************************************************
`define sync 8'd101
module itu_r656_decoder
(
CLOCK, //system clock
TD_D, //4:2:2 video data stream
TD_HS, //Decoder_hs
TD_VS, //Decoder_vs
Y, //4:4:4 Y
Cb, //4:4:4 Cb
Cr, //4:4:4 Cr
Ypix_clock, //Y pixel clock
HSx2,
VSx1,
Y_check,
START,
COUNTER,
R,G,B,
h_tr,
SW0,SW1,
blank
);
input CLOCK;
input [7:0]TD_D;
input TD_HS;
input TD_VS;
input SW0;
input SW1;
output [7:0]Y;
output [7:0]Cb;
output [7:0]Cr;
output HSx2;
output VSx1;
output Ypix_clock;
//test
output Y_check;
output START;
output [1:0]COUNTER;
output [9:0]R;
output [9:0]G;
output [9:0]B;
output h_tr;
output blank;
reg [7:0]YY;
reg [7:0]CCb,Cbb;
reg [7:0]CCr,Crr;
reg HSx2 ;//TD_HS;
wire VSx1=TD_VS;
reg[7:0]R1,R2,R3;
reg[7:0]RR1,RR2,RR3;
wire [7:0]cr={2'b0,Cr[6:1]};
wire [7:0]cb={3'b0,Cb[6:2]};
wire [7:0]Rr=(Y-16)-{1'b0,Cr[7:0]};
wire [7:0]Gg=(Y-16)-cr -cb;
wire [7:0]Bb=(Y-16)-{1'b0,Cb[7:0]};
wire [9:0]R={Rr,2'b00};
wire [9:0]G={Gg,2'b00};
wire [9:0]B={Bb,2'b00};
//
wire Y_check=( (R3==8'hff) && (R2==8'h00) && (R1==8'h00) )?1:0;
always @(posedge CLOCK) begin
RR1=TD_D;
RR2=R1;
RR3=R2;
end
always @(negedge CLOCK) begin
R1=RR1;
R2=RR2;
R3=RR3;
end
reg START,Field;
always @(posedge CLOCK) begin
if (Y_check==1)
begin
START=~TD_D[4];
Field= TD_D[6];
end
end
reg [1:0]COUNTER;
always @(posedge CLOCK) begin
if (!START)
COUNTER=0;
else COUNTER=COUNTER+1;
end
/*4:2:2中,4个27MCLK中有两个是Y,其他两个是Cb和Cr,转成4:4:4,其实也就是重复读一次Cb和Cr,程序中已经完成这个工作,不需要特殊的转换模块,具体你看看。
在下面的程序中,4个27MCLK中Y被改变了2次,而Cb,Cr 被赋值一次。读的时候读两次就变4:4:4了。
*/
reg Ypix_clock;
always @(posedge CLOCK) begin
case (COUNTER)
0:begin Cbb=TD_D; Ypix_clock =0;end
1:begin YY =TD_D;CCr=Crr;CCb=Cbb; Ypix_clock =1;end
2:begin Crr=TD_D; Ypix_clock =0;end
3:begin YY =TD_D;CCr=Crr;CCb=Cbb; Ypix_clock =1;end
endcase
end
reg [10:0]H_COUNTER;
reg [10:0]RH_COUNTER;
always @(posedge CLOCK) begin
if (TD_HS) H_COUNTER=0;
else H_COUNTER=H_COUNTER+1;
end
always @(posedge TD_HS) begin
RH_COUNTER=H_COUNTER;
end
always @(posedge CLOCK) begin
if (
((H_COUNTER >= 0) && (H_COUNTER < `sync)) ||
((H_COUNTER >= RH_COUNTER[10:1]) && (H_COUNTER < (RH_COUNTER[10:1]+`sync+1)))
)
HSx2=0;
else
HSx2=1;
end
reg [10:0]h;
reg h_tr;
reg h_tr_h;
always @(posedge CLOCK) begin
if(!HSx2) h=0;
else
h=h+1;
end
always @(posedge CLOCK) begin
if ((h< 51) || (h > 771))
h_tr=0;
else
h_tr=1;
end
always @(posedge CLOCK) begin
if ((h< 41) || (h > 781))
h_tr_h=0;
else
h_tr_h=1;
end
wire [7:0]Yw,YYw;
wire [7:0]Cwr,CCwr;
wire [7:0]Cwb,CCwb;
reg [10:0]pcounter_h;
reg [10:0]pcounter_v;
always @(posedge CLOCK) begin
if (!h_tr) pcounter_h=0;
else pcounter_h=pcounter_h+1;
end
always @(posedge h_tr) begin
if (!TD_VS) pcounter_v=0;
else pcounter_v=pcounter_v+1;
end
wire t=(
// ((pcounter_h >=0) && (pcounter_h < 45) && (pcounter_v[9:5]==5'b00000)) ||
((pcounter_h >=0) && (pcounter_h < 90) && (pcounter_v[9:5]==5'b00001)) ||
((pcounter_h >=0) && (pcounter_h < 135) && (pcounter_v[9:5]==5'b00010)) ||
((pcounter_h >=0) && (pcounter_h < 180) && (pcounter_v[9:5]==5'b00011)) ||
((pcounter_h >=0) && (pcounter_h < 225) && (pcounter_v[9:5]==5'b00100)) ||
((pcounter_h >=0) && (pcounter_h < 270) && (pcounter_v[9:5]==5'b00101)) ||
((pcounter_h >=0) && (pcounter_h < 315) && (pcounter_v[9:5]==5'b00110)) ||
//((pcounter_h >=0) && (pcounter_h < 360) && (pcounter_v[9:5]==5'b00111)) ||
((pcounter_h >=0) && (pcounter_h < 405) && (pcounter_v[9:5]==5'b01000)) ||
((pcounter_h >=0) && (pcounter_h < 450) && (pcounter_v[9:5]==5'b01001)) ||
((pcounter_h >=0) && (pcounter_h < 495) && (pcounter_v[9:5]==5'b01010)) ||
((pcounter_h >=0) && (pcounter_h < 540) && (pcounter_v[9:5]==5'b01011)) ||
((pcounter_h >=0) && (pcounter_h < 585) && (pcounter_v[9:5]==5'b01100)) ||
// ((pcounter_h >=0) && (pcounter_h < 630) && (pcounter_v[9:5]==5'b01101)) ||
((pcounter_h >=0) && (pcounter_h < 675) && (pcounter_v[9:5]==5'b01110)) ||
((pcounter_h >=0) && (pcounter_h < 720) && (pcounter_v[9:5]==5'b01111))
)?1:0;
wire [7:0]ym= t? 8'hff:8'h80;
wire [7:0]crm=t? 8'h80:8'h80;
wire [7:0]cbm=t? 8'h80:8'h80;
assign YYw =((h_tr==1) && (VSx1==1))?Yw : 8'h10;//current set
assign CCwr =((h_tr==1) && (VSx1==1))?Cwr: 8'h80;
assign CCwb =((h_tr==1) && (VSx1==1))?Cwb: 8'h80;
wire [7:0]Ymm =SW1? ym :Yw ;
wire [7:0]Crmm =SW1? crm:Cwr;
wire [7:0]Cbmm =SW1? cbm:Cwb;
reg[10:0]Hde_counter;
reg[10:0]Vde_counter;
always @(posedge CLOCK)begin
if(HSx2==0)
Hde_counter=0;
else
Hde_counter=Hde_counter+1;
end
always@(posedge HSx2)begin
if (TD_VS==0)
Vde_counter=0;
else
Vde_counter=Vde_counter+1;
end
wire hde=((Hde_counter > 51) && (Hde_counter < 691)) ? 1:0;//720
wire vde=((Vde_counter > 31) && (Vde_counter < 511)) ? 1:0;//480
wire blank_h = h_tr & vde;
wire blank = h_tr_h & vde;
wire [7:0]Y = (blank_h)?Ymm :8'h10;
wire [7:0]Cr = (blank_h)?Crmm :8'h80;
wire [7:0]Cb = (blank_h)?Cbmm :8'h80;
dul_port_c1024 YYYR(
.iDATA(YY[7:0]),
.iHSYNC(TD_HS),
// .iHSYNCx2(HSx2),
.iHSYNCx2(blank),
.Y_CLOCK(Ypix_clock),
.Y_CLOCKx2(CLOCK),
.oDATA(Yw[7:0]),
.field(Field),
.VS(TD_VS)
);
dul_port_c1024 CBB(
.iDATA(CCb[7:0]),
.iHSYNC(TD_HS),
// .iHSYNCx2(HSx2),
.iHSYNCx2(blank),
.Y_CLOCK(Ypix_clock),
.Y_CLOCKx2(CLOCK),
.oDATA(Cwb[7:0]),
.field(Field),
.VS(TD_VS)
);
dul_port_c1024 CRR(
.iDATA(CCr[7:0]),
.iHSYNC(TD_HS),
// .iHSYNCx2(HSx2),
.iHSYNCx2(blank),
.Y_CLOCK(Ypix_clock),
.Y_CLOCKx2(CLOCK),
.oDATA(Cwr[7:0]),
.field(Field),
.VS(TD_VS)
);
endmodule
(转自Altera FPGA小组,作者:youzizhile )