例说FPGA连载71:AV视频采集之YCbCr转RGB实现
特权同学,版权所有
配套例程和更多资料下载链接:
http://pan.baidu.com/s/1c0nf6Qc
该模块的内部功能框图如图12.40所示。YCrCb输入视频流经过该模块内部缓存排序、乘累积运算(放大256倍)、加法运算以及溢出与缩小(256倍)处理后,输出RGB视频流。
图12.40 色彩格式转换模块功能框图
在视频图像显示、处理时,采用的颜色空间主要有RGB和YCrCb两种。RGB基于三基色原理,颜色实现简单,在计算机、电视机显示系统中应用广泛。YCrCb将颜色的亮度信号与色度信号分离,易于实现压缩,方便传输和处理。在视频压缩、传输等应用中经常需要实现RGB与YCbCr颜色空间的相互变换。
在RGB颜色空间中,自然界所有颜色都可以用红(R)、绿(G)、蓝(B)三种颜色的不同强度组合而重现。RGB的取值范围分别为0~255。
RGB生成颜色容易实现,被广泛应用在计算机、彩色电视机的显示系统中。但是RGB表示颜色的效率并不是很高,3个颜色分量同等重要,而且亮度信息存在于所有颜色分量中,当需要对像素点的亮度或者色度值进行修改时,必须同时改变RGB三者的值。
在YCRCb颜色空间中,Y表示亮度信号,取值范围为16~235;Cr,Cb表示色度信号,取值范围为16~240,亮度信号与色度信号相互独立。这种颜色表示方法可以利用人眼的特性降低数字彩色图像的存储空间。人眼视觉系统对亮度细节的敏感度高于颜色细节,适当减少色度分辨率不会明显影响图像的画质,易于实现数据压缩。
由于人眼对亮度Y的信息最敏感,因此ITU656送出的YCrCb数据格式每个像素都包含Y信息,而相邻两个像素公用一组CrCb信息,这样它相对RGB模式就能够减少传输数据量。ITU656的YCrCb数据对应所属的像素点如图12.41所示。
图12.41 ITU656格式的像素色彩对应关系
RGB与YCrCb的转换关系式如下。
由于FPGA逻辑运算中,我们无法直接运用浮点数进行运算,因此可以先将等式左右分别放大256倍进行运算,运算完成后再缩小256倍即可。等式左右放大后的结果如下所示。
我们接下来看看逻辑代码中如何实现这个矩阵运算的。我们把上面的等式分别展开为3个等式如下。
R*256 = 256*Y + 359*Cr – 45941
G*256 = 256*Y – 88*Cb – 183*Cr + 34678
B*256 = 256*Y + 454*Cb - 58065
我们可以进一步把前面的3个等式拆分为以下3步运算。
步骤1:
R’ = 256*Y + 359*Cr
G’ = 256*Y – 88*Cb – 183*Cr
B’ = 256*Y + 454*Cb
步骤2:
R’’ = R’ – 45941
G’’ = G’ + 34678
B’’ = B’ - 58065
步骤3:
R = R’’>>8
G = G’’>>8
B = B’’>>8
对于步骤1的公式,Y、Cr、Cb本身是8bit的无符号数,而与他们相乘法的参数最大值为454,并且“有加有减”,因此我们可以取这些参数为10bit的有符号数,即最高位bit9为符号位,可表示的数值范围是-512到511。那么,步骤1运算等式可以表示如下:
R’*256 = 18’d256*Y + 18’d359*Cr
G’*256 = 18’d256*Y + 18'h3ffa8*Cb + 18'h3ff49*Cr
B’*256 = 18’d256*Y + 18’d454*Cb
基于这3个公式,我们再去看3个乘累加器的输入,就可以很好的理解了,其代码如下。
//R
muxadd2 muxadd_instr (
.aclr0 ( !rst_n ),
.clock0 ( clk ),
.dataa_0 ( {1'd0,dy} ),
.dataa_1 ( {1'd0,dcr} ),
.datab_0 ( 18'd256 ),
.datab_1 ( 18'd359 ),
.result ( dtr )
);
//G
muxadd muxadd_instg (
.aclr0 ( !rst_n ),
.clock0 ( clk ),
.dataa_0 ( {1'd0,dy} ),
.dataa_1 ( {1'd0,dcb} ),
.dataa_2 ( {1'd0,dcr} ),
.datab_0 ( 18'd256 ),
.datab_1 ( 18'h3ffa8 ),
.datab_2 ( 18'h3ff49 ),
.result ( dtg )
);
//B
muxadd2 muxadd_instb (
.aclr0 ( !rst_n ),
.clock0 ( clk ),
.dataa_0 ( {1'd0,dy} ),
.dataa_1 ( {1'd0,dcb} ),
.datab_0 ( 18'd256 ),
.datab_1 ( 18'd454 ),
.result ( dtb )
);
● dataa_0、dataa_1、dataa_2都是9bit的有符号数,datab_0、datab_1、datab_2都是18bit的有符号数。
● Dy、dcb、dcr对应公式中的Y、Cb、Cr,由于他们都是8bit的无符号数,因此给他们补1bit的1'b0。
● dataa_0和datab_0是一组乘法输入;dataa_1和datab_1是一组乘法输入;dataa_2和datab_2是一组乘法输入。
对于步骤2的公式,由于步骤1得到的结果都是18bit的有符号数,并且步骤2中需要运算的加减参数也都是18bit有符号数计数范围之内,因此我们也去18bit有符号数。那么步骤2的公式可以表示为:
R’’ = R’ + 18'h34c8b
G’’ = G’ + 18’d34678
B’’ = B’ + 18'h31d2e
那么,我们第2步运算的逻辑代码如下。
//------------------------------------------------------
reg[17:0] dor,dog,dob; //第二步中间处理数据
always @(posedge clk or negedge rst_n)
if(!rst_n) begin
dor 12'd6)来作为drgb_rdy输出的一个条件。drgb_rdy产生的逻辑代码如下。
//------------------------------------------------------
reg drgb_rdyr; //转换后的RGB有效数据指示信号,高电平有效
reg[10:0] rcnt; //输出控制计数器
always @(posedge clk or negedge rst_n)
if(!rst_n) rcnt 11'd1276)&& (rcnt 12'd6)) drgb_rdyr <= 1'b1;//转换后的RGB有效数据指示信号
else drgb_rdyr <= 1'b0;
assign drgb_rdy = drgb_rdyr;