3

Im developing in android, and want to convert the byte-array from the camera's previewCallback, which is in YUV-format, to rgb-format.

I have used the function given in this answer: Getting frames from Video Image in Android

It works perfectly in java, but my problem is that I want to make the function in c++ (I'm using the ndk, and not very familiar with c++).

I have tried to create the function in c++, but it always makes strange results (eg the picture is all green).

Does anyone have a similar function or this function working in c++?

Thanks.

Community
  • 1
  • 1
igr
  • 4,529
  • 2
  • 15
  • 20
  • Post your c++ conversion of that function on the other post. I use the answer from user "Codevalley" to great success. – weston Feb 03 '12 at 16:58

2 Answers2

9

Conversion from YUYV to RGB in C++:

unsigned char* rgb_image = new unsigned char[width * height * 3]; //width and height of the image to be converted

int y;
int cr;
int cb;

double r;
double g;
double b;

for (int i = 0, j = 0; i < width * height * 3; i+=6 j+=4) {
    //first pixel
    y = yuyv_image[j];
    cb = yuyv_image[j+1];
    cr = yuyv_image[j+3];

    r = y + (1.4065 * (cr - 128));
    g = y - (0.3455 * (cb - 128)) - (0.7169 * (cr - 128));
    b = y + (1.7790 * (cb - 128));

    //This prevents colour distortions in your rgb image
    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;

    rgb_image[i] = (unsigned char)r;
    rgb_image[i+1] = (unsigned char)g;
    rgb_image[i+2] = (unsigned char)b;

    //second pixel
    y = yuyv_image[j+2];
    cb = yuyv_image[j+1];
    cr = yuyv_image[j+3];

    r = y + (1.4065 * (cr - 128));
    g = y - (0.3455 * (cb - 128)) - (0.7169 * (cr - 128));
    b = y + (1.7790 * (cb - 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;

    rgb_image[i+3] = (unsigned char)r;
    rgb_image[i+4] = (unsigned char)g;
    rgb_image[i+5] = (unsigned char)b;
}

This method assumes that your yuyv_image is an unsigned char* as well.

More information on YUYV can be found here

And for more clarification on YUYV --> RGB check out this

Redek
  • 1,311
  • 1
  • 13
  • 20
  • 1
    I think there is a better way to prevent colour distortions: The solution I know, it to limit the range of the input to valid range of Y, Cb and Cr. Valid range of Y is [16, 235], Valid range of Cb,Cr is [16, 240]. Clamping the input: `y = max(min(y, 235), 16); Cb = max(min(y, 240), 16); Cr = max(min(y, 240), 16);` – Rotem Jun 23 '16 at 21:50
  • Why does your YUV image has (3 * width * height) bytes of data? Isn't it supposed to have (1.5 * width * height) pixels? – user972014 Aug 27 '16 at 13:20
  • this code was incomplete and had errors. things like `rgb_image[+1]` had to be rooted out – Force Gaia Apr 18 '17 at 14:33
  • It appears one of the scaling factors here is incorrect. For the red channel, 1.4065 is used here, but cross-checking with other sources suggests the correct number is 1.4075. All other numbers are exact matches for numbes quoted from thousands of other sources, but this one number differs slightly, suggesting it was copied incorrectly. – Roger Sanders May 21 '18 at 11:59
  • 1
    This is impressive and worked like a charm. OpenCV was becoming annoying so I grab webcam footage from OpenBSD's v4l layer directly. This conversion was the missing piece. Also, did you type this out just from your head? (The missing ',' between i+=6 j+=4 in the for loop suggests so). So this is even more impressive ;) – Karsten Pedersen Jul 25 '21 at 22:17
1

Look at this: http://pastebin.com/mDcwqJV3

Fixed-point conversion from YUYV to RGB24

Also, some cameras return raw images in 'UYVY' byte orger, so make corresponding changes in the conversion function.

qehgt
  • 2,972
  • 1
  • 22
  • 36