COMPGROUPS.NET | Search | Post Question | Groups | Stream | About | Register

### 4:2:0 colour sampling question

• Email
• Follow

```Hi! Can you help me to convert an RGB[4*n][4*n] array to 4:4:0 format?
My algorithm just averages Chroma for every 4 pixels and fills the
array. But the white zones of my image becomes blue. Here is some code:
void makeYUV(byte RGB[128][96][3],float YUV[128][96][3]){
for(int i=0;i<128;i++)
for(int j=0;j<96;j++){
YUV[i][j][0]=0.299*RGB[i][j][0]+0.587*RGB[i][j][1]+0.114*RGB[i][j][2];
YUV[i][j][1]=0.564*(RGB[i][j][2]-YUV[i][j][0]);
YUV[i][j][2]=0.713*(RGB[i][j][0]-YUV[i][j][0]);
}
for(int i=0;i<128;i+=2)
for(int j=0;j<96;j+=2){
float f1,f2;
f1=(YUV[i][j][1]+YUV[i][j+1][1]+YUV[i+1][j][1]+YUV[i+1][j+1][1])/4;
YUV[i][j][1]=f1;
YUV[i][j+1][1]=f1;
YUV[i+1][j][1]=f1;
YUV[i+1][j+1][1]=f1;
f2=(YUV[i][j][2]+YUV[i][j+1][2]+YUV[i+1][j][2]+YUV[i+1][j+1][2])/4;
YUV[i][j][2]=f2;
YUV[i][j+1][2]=f2;
YUV[i+1][j][2]=f2;
YUV[i+1][j+1][2]=f2;
}
}
void makeRGB(float YUV[128][96][3],byte RGB[128][96][3]){
for(int i=0;i<128;i++)
for(int j=0;j<96;j++){
RGB[i][j][0]=(byte)(YUV[i][j][0]+1.402*YUV[i][j][2]);
RGB[i][j][1]=(byte)(YUV[i][j][0]-0.334*YUV[i][j][1]-0.714*YUV[i][j][2]);
RGB[i][j][2]=(byte)(YUV[i][j][0]+1.772*YUV[i][j][1]);
}
}
It's ok if I use 4:4:4 format.

```
 0

See related articles to this posting

```azsx wrote:
> Hi! Can you help me to convert an RGB[4*n][4*n] array to 4:4:0 format?
> My algorithm just averages Chroma for every 4 pixels and fills the
> array. But the white zones of my image becomes blue.

If your formula is lossy/not reversible, then such type of mess can
happen, no surprise.
Make it sure that formula you are using for the conversion is not lossy
one..

> void makeYUV(byte RGB[128][96][3],float YUV[128][96][3]){
> 	for(int i=0;i<128;i++)
> 		for(int j=0;j<96;j++){
> 			YUV[i][j][0]=0.299*RGB[i][j][0]+0.587*RGB[i][j][1]+0.114*RGB[i][j][2];
> 			YUV[i][j][1]=0.564*(RGB[i][j][2]-YUV[i][j][0]);
> 			YUV[i][j][2]=0.713*(RGB[i][j][0]-YUV[i][j][0]);
> 		}
> 	for(int i=0;i<128;i+=2)
> 		for(int j=0;j<96;j+=2){
> 			float f1,f2;
> 			f1=(YUV[i][j][1]+YUV[i][j+1][1]+YUV[i+1][j][1]+YUV[i+1][j+1][1])/4;
> 			YUV[i][j][1]=f1;
> 			YUV[i][j+1][1]=f1;
> 			YUV[i+1][j][1]=f1;
> 			YUV[i+1][j+1][1]=f1;
> 			f2=(YUV[i][j][2]+YUV[i][j+1][2]+YUV[i+1][j][2]+YUV[i+1][j+1][2])/4;
> 			YUV[i][j][2]=f2;
> 			YUV[i][j+1][2]=f2;
> 			YUV[i+1][j][2]=f2;
> 			YUV[i+1][j+1][2]=f2;
> 		}
> }
> void makeRGB(float YUV[128][96][3],byte RGB[128][96][3]){
> 	for(int i=0;i<128;i++)
> 		for(int j=0;j<96;j++){
> 			RGB[i][j][0]=(byte)(YUV[i][j][0]+1.402*YUV[i][j][2]);
> 			RGB[i][j][1]=(byte)(YUV[i][j][0]-0.334*YUV[i][j][1]-0.714*YUV[i][j][2]);
> 			RGB[i][j][2]=(byte)(YUV[i][j][0]+1.772*YUV[i][j][1]);
> 		}
> }
> It's ok if I use 4:4:4 format.

```
 0

```> If your formula is lossy/not reversible, then such type of mess can
> happen, no surprise.
> Make it sure that formula you are using for the conversion is not lossy
> one..
the problem is that i've just tried 4:2:2 format which should give good
results and there are still big blue spots instead of light areas.

```
 0

```Hi aszx,

r=256, g=256, b=255
and writing these values as bytes results in
r=0, g=0, b=255?
Then you need to clip your rgb-values to stay
between 0 and 255.
See below for some working code, though I
use a different formula.

Hope it helps,

Carsten Neubauer
http://www.c14sw.de/

_______________________________________

//get source values
//RGB2YUV
Y = ( 0.257 * r + 0.504 * g + 0.098 * b +  16.0);
U = ( 0.439 * r - 0.368 * g - 0.071 * b + 128.0);
V = (-0.148 * r - 0.291 * g + 0.439 * b + 128.0);

and back:

//get source values
V = (pfFrame[0] - 128);
U = (pfFrame[1] - 128);
Y = (pfFrame[2] -  16);
//YUV2RGB
r = ((1.164 * Y + 1.596 * U            ) + 128);
g = ((1.164 * Y - 0.813 * U - 0.392 * V) + 128);
b = ((1.164 * Y             + 2.017 * V) + 128);

if (r < 0)
r = 0;
else if (r > 255)
r = 255;

if (g < 0)
g = 0;
else if (g > 255)
g = 255;

if (b < 0)
b = 0;
else if (b > 255)
b = 255;

```
 0

```azsx wrote:
> YUV[i][j][0]=0.299*RGB[i][j][0]+0.587*RGB[i][j][1]+0.114*RGB[i][j][2];
> YUV[i][j][1]=0.564*(RGB[i][j][2]-YUV[i][j][0]);
> YUV[i][j][2]=0.713*(RGB[i][j][0]-YUV[i][j][0]);

You need to add 128 to the U and V components. I think you also need to
check for overflow in the U and V components. The Y component can't overflow.

Also, depending on the application, you may be using the wrong gamuts here.
The Y component usually runs from 16 to 235 (not 0 to 255) and the U and V
(Cb and Cr) usually run from 16 to 240. An exception is JPEG/JFIF, where
they're all 0..255.

-- Ben
```
 0

```Thanks!

```
 0

```Thanks!

```
 0

6 Replies
112 Views

Similar Articles

12/6/2013 2:03:40 PM
[PageSpeed]