serena

视频色度空间变换

0
阅读(3166)

由于使用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 )