3

I'm developing an app using java which convert a YUV pixel(x,y) into a RGB pixel, here is what I did:(data is YUV byte array)

int Y = data[ y * width + x];
            int U = data[ (int) (width * height + Math.floor(y/2) * Math.floor(width/2) + Math.floor(x/2) + 1)];
            int V = data[ (int) (width * height + Math.floor(y/2) * (width/2) + Math.floor(x/2) + 0)];

            int B = (int) (1.164*(Y - 16)+ 2.018*(U - 128));

            int G = (int) (1.164*(Y - 16) - 0.813*(V - 128) - 0.391*(U - 128));

            int R = (int) (1.164*(Y - 16) + 1.596*(V - 128));

But in the end, I found that the RGB values I got are negative. Can someone help me with this? Thank you!

Junfei Wang
  • 578
  • 1
  • 13
  • 26
  • http://stackoverflow.com/questions/2905597/how-to-deal-with-rgb-to-yuv-conversion duplicated – 0x90 Dec 07 '12 at 00:58

3 Answers3

1

There are many "flavors" of YUV, and sometimes these get mixed up with YCbCr. Your formula appears appropriate for formats where Y is in [16,235], but, I can tell you that this is not correct for the NV21 image format (a type of standard YUV planar) returned in Android.

Sean Owen
  • 66,182
  • 23
  • 141
  • 173
  • [Here](https://software.intel.com/en-us/android/articles/trusted-tools-in-the-new-android-world-optimization-techniques-from-intel-sse-intrinsics-to) is a post that seems to contradict this answer. Is there something different they are doing? They seem to apply this exact formula (albeit an integer approximation) to 8-bit YUV values (NV21). – maverick1989 Sep 15 '14 at 18:04
  • I am sure that Android luminance values are in [0,255]. I don't know whether it's wrong to call one or the other NV21, but I think NV21 uses a full 8 bits of Y. The post in question seems to confirm that, although I agree the formula looks like it's doing something else. – Sean Owen Sep 15 '14 at 20:59
  • 1
    I did some more reading on this. The formula in the post linked above works. It is a pretty fast integer approximation (mobile devices do int ~2x faster usually). YUV values are in [0,255] like you say. However, it IS possible to get negative R, G or B values when doing a YUV to RGB conversion. Values greater than 255 are also possible. These are simply set to 0 or 255 respectively. – maverick1989 Sep 16 '14 at 20:04
0

A similar conversion in C++ is on this YUV Wikipedia page.

After the formulaic conversion code the R,G,B values are clamped 0-255.

Have you tried something similar in Java?

@MelindaGreen's answer to a different question includes a method that does yuv->rgb conversion which also produces negative RGB values.

Setting the negative values to 0 produced colors that look right to me.

Ryan
  • 2,061
  • 17
  • 28
0
//
// C++ code to convert between RGB and YUV where values are 0..255.
//

typedef struct XYZ {
    double x,y,z;
};

XYZ rgb2yuv(double r, double g, double b)
{
    XYZ xyz;

    double R = r/255.0;
    double G = g/255.0;
    double B = b/255.0;

    double Y =  0.299*R + 0.587*G + 0.114*B;
    double U = -0.147*R - 0.289*G + 0.436*B;
    double V =  0.615*R - 0.515*G - 0.100*B;

    xyz.x = Y*255.0;
    xyz.y = (U+0.5)*255.0;
    xyz.z = (V+0.5)*255.0;

    return xyz;
}

XYZ yuv2rgb(double y, double u, double v)
{
    XYZ xyz;

    double Y = y/255.0;
    double U = u/255.0-0.5;
    double V = v/255.0-0.5;

    double R = Y + 1.140*V;
    double G = Y - 0.395*U - 0.581*V;
    double B = Y + 2.032*U;

    xyz.x = R*255.0;
    xyz.y = G*255.0;
    xyz.z = B*255.0;

    return xyz;
}
Anthony.
  • 643
  • 7
  • 14