YCbCr 转 RGB算法
0赞YUV422_YUV444
http://www.cnblogs.com/crazybingo/archive/2012/06/07/2540595.html
http://www.fdworkshop.me/read.php?tid=37
YUV
Y:亮度(16-235) U:色彩 V:饱和度
YCbCr
Y:亮度(16-235) Cb:色度(16-240)(B-Y) Cr:色度(16-240)(R-Y)
YUV2RGB(gamma校正)
YUV
Y:亮度(16-235) U:色彩 V:饱和度
1) RGB转YUV
Y= 0.299R + 0.587G + 0.114B
U= -0.147R - 0.289G + 0.436B = 0.492(B- Y)
V= 0.615R - 0.515G - 0.100B = 0.877(R- Y)
2) YUV转RGB
R = Y + 1.140V
G = Y - 0.394U - 0.581V
B = Y + 2.032U
R = (Y*512 + V*584)>>9
G = (Y*512 - U*202 - V*297)>>9
B = (Y*512 + U*1040)>>9
RGB2YCbCr(视频系统 ITU-RBT.656)(gamma校正)
YCbCr
Y:亮度(16-235) Cb:色度(16-240)(B-Y) Cr:色度(16-240)(R-Y)
(1)不适合使用在计算机中16-235
R = Y + 1.371(Cr-128)
G = Y - 0.698(Cr-128) - 0.336(Cb-128)
B = Y + 1.732(Cb-128)
=>*512
XOUT = Y*512 + 702(Cr-128)
YOUT = Y*512 + 257(Cr-128) - 172(Cb-128)
ZOUT = Y*512 + 887(Cb-128)
=>/512
R <= (XOUT[8:0] > 9'd255) ? 8'hff : XOUT[7:0];
G <= (YOUT[8:0] > 9'd255) ? 8'hff : YOUT[7:0];
B <= (ZOUT[8:0] > 9'd255) ? 8'hff : ZOUT[7:0];
(2)适用在计算机中 0-255(0V7670已设置为1-FE)
YCbCr is a scaled and offset version of the YUV color space.
RGB取值0-255
1) RGB转YCbCr
Y = 0.257R + 0.504G + 0.098B + 16
Cb = -0.148R - 0.291G + 0.439B + 128
Cr = 0.439R - 0.368G - 0.071B + 128
2) YCbCr转 RGB
原式=>
R = 1.164(Y-16) + 1.596(Cr-128)
G = 1.164(Y-16) - 0.813(Cr-128) - 0.391(Cb-128)
B = 1.164(Y-16) + 2.018(Cb-128)
转换(1)=>分离变量
R = 1.164Y + 1.596Cr - 222.912
G = 1.164Y - 0.391Cb - 0.813Cr + 135.488
B = 1.164Y + 2.018Cb - 276.928
<1>方法1:转换(2)=>放大512倍(<<9)----当然也可以直接用ALTMULT_ADD(乘法器)
XOUT[19:0] = ((Y*10'd596) + (Cr*10'd817) - 18'd114131)>>9;
YOUT[19:0] = ((Y*10'd596) - (Cb*10'd200) - (Cr*10'd416) + 18'd69370)>>9;
ZOUT[19:0] = ((Y*10'd596) + (Cb*11'd1033) - 18'd141787)>>9;
<2>方法2:转换(3)=>放大512倍(<<9)----移位实现
XOUT = (((Y<<9)+(Y<<6)+(Y<<4)+(Y<<2)) + ((Cr<<9)+(Cr<<8)+(Cr<<5)+(Cr<<4)+Cr) - 18'd114131)>>9;
YOUT = (((Y<<9)+(Y<<6)+(Y<<4)+(Y<<2)) - ((Cb<<7)+(Cb<<6)+(Cb<<3)) - ((Cr<<8)+(Cr<<7)+(Cr<<5)) + 18'd69370)>>9;
ZOUT = (((Y<<9)+(Y<<6)+(Y<<4)+(Y<<2)) + ((Cb<<10)+(Cb<<3)+Cb) - 18'd141787)>>9;
最终结果:转换(4)=>缩小512倍(>>9)
R <= XOUT[19] ? 8'h0 : (XOUT[8:0] > 9'd255) ? 8'hff : XOUT[7:0];
G <= YOUT[19] ? 8'h0 : (YOUT[8:0] > 9'd255) ? 8'hff : YOUT[7:0];
B <= ZOUT[19] ? 8'h0 : (ZOUT[8:0] > 9'd255) ? 8'hff : ZOUT[7:0];
在Quartus中综合编译,发现用流水线+移位操作实现YUV2RGB(能达到80M),远比用乘法器(只能50M)速度要快,当然在一定范围内,两者都可以。最后,移位转换RTL如下所示:
(当然也可以通过ROM查找表来实现,但我认为这个不适合因为浪费了很多资源,而且不适合在CPLD实现,有兴趣可以看如下论文http://www.chinaaet.com/lib/detail.aspx?id=89671)
实际经过测试,从OV7670捕获YUV数据,在转换为RGB在VGA显示,效果还好,相关代码如下所示
YCbCr2RGB verilog代码如下所示:
/*------------------------------------------------------------------------- This confidential and proprietary software may be only used as authorized by a licensing agreement from CrazyBingo.www.cnblogs.com/crazybingo (C) COPYRIGHT 2012 CrazyBingo. ALL RIGHTS RESERVED Filename : yuv444_rgb888 Author : CrazyBingo Data : 2012-06-6 Version : 1.0 Description : I2C Configure Data of OV7670. Modification History : Data By Version Change Description =========================================================================== 12/06/06 CrazyBingo 1.0 Original --------------------------------------------------------------------------*/ `timescale 1ns/1ns module YCbCr2RGB ( input clk, input rst_n, input [7:0] Y, input [7:0] Cb, input [7:0] Cr, output reg [7:0] R, output reg [7:0] G, output reg [7:0] B ); //Way1 :shift //wire [19:0] XOUT = (((Y<<9)+(Y<<6)+(Y<<4)+(Y<<2)) + ((Cr<<9)+(Cr<<8)+(Cr<<5)+(Cr<<4)+Cr) - 18'd114131)>>9; //wire [19:0] YOUT = (((Y<<9)+(Y<<6)+(Y<<4)+(Y<<2)) - ((Cb<<7)+(Cb<<6)+(Cb<<3)) - ((Cr<<8)+(Cr<<7)+(Cr<<5)) + 18'd69370)>>9; //wire [19:0] ZOUT = (((Y<<9)+(Y<<6)+(Y<<4)+(Y<<2)) + ((Cb<<10)+(Cb<<3)+Cb) - 18'd141787)>>9; //Ways2 : mult //wire [19:0] XOUT = ((Y*10'd596) + (Cr*10'd817) - 18'd114131)>>9; //wire [19:0] YOUT = ((Y*10'd596) - (Cr*10'd416) - (Cb*10'd200) + 18'd69370)>>9; //wire [19:0] ZOUT = ((Y*10'd596) + (Cb*11'd1033) - 18'd141787)>>9; //------------------------------------------- //流水线1:计算XOUT通道每个Y Cb Cr数据,加速 reg [19:0] mY; reg [19:0] mCr1; reg [19:0] mCb2; reg [19:0] mCr2; reg [19:0] mCb3; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin mY <= 0; mCr1 <= 0; mCb2 <= 0; mCr2 <= 0; mCb3 <= 0; end else begin mY <= (Y<<9)+(Y<<6)+(Y<<4)+(Y<<2); mCr1 <= (Cr<<9)+(Cr<<8)+(Cr<<5)+(Cr<<4)+Cr; mCb2 <= (Cb<<7)+(Cb<<6)+(Cb<<3); mCr2 <= (Cr<<8)+(Cr<<7)+(Cr<<5); mCb3 <= (Cb<<10)+(Cb<<3)+Cb; end end //------------------------------------------- //流水线2:计算XOUT通道结果,加速 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 <= (mY + mCr1 - 18'd114131)>>9; YOUT <= (mY - mCb2 - mCr2 + 18'd69370)>>9; ZOUT <= (mY + mCb3 - 18'd141787)>>9;; end end //------------------------------------------- //流水线3:计算RGB通道结果,加速 always@(posedge clk or negedge rst_n) begin if(!rst_n) begin R <= 0; G <= 0; B <= 0; end else //when <0 ro <0 begin R <= XOUT[19] ? 8'h0 : (XOUT[8:0] > 9'd255) ? 8'hff : XOUT[7:0]; G <= YOUT[19] ? 8'h0 : (YOUT[8:0] > 9'd255) ? 8'hff : YOUT[7:0]; B <= ZOUT[19] ? 8'h0 : (ZOUT[8:0] > 9'd255) ? 8'hff : ZOUT[7:0]; end end endmodule