CrazyBingo

YCbCr 转 RGB算法

0
阅读(32543)

wps_clip_image-21606

YUV422_YUV444

wps_clip_image-15972

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

wps_clip_image-8894

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)

wps_clip_image-12896

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如下所示:

wps_clip_image-8792

(当然也可以通过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