Convert yuv420p to rgb888 in C
algorithm, c, rgb, yuv
Solution
You're getting the U and V values incorrectly.
The U and V values for pixel (`i`, `j`) are :
u[((j / 2) * (width / 2)) + (i / 2)];
v[((j / 2) * (width / 2)) + (i / 2)];
So, try a loop like this :
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
int yy = y[(j * width) + i];
int uu = u[((j / 2) * (width / 2)) + (i / 2)];
int vv = v[((j / 2) * (width / 2)) + (i / 2)];
r = 1.164 * (yy - 16) + 1.596 * (vv - 128);
g = 1.164 * (yy - 16) - 0.813 * (vv - 128) - 0.391 * (uu - 128);
b = 1.164 * (yy - 16) + 2.018 * (uu - 128);
*ptr++ = CLAMP(r);
*ptr++ = CLAMP(g);
*ptr++ = CLAMP(b);
}
}
Problem
I'm trying to convert planar YUV (yuv420p) to RGB24 in C. I'm not controlling the input, and have the YUV data as 3 separate buffers, one for Y, one for U and one for V. I want to create a single output RGB buffer from these 3 input buffers. I followed the following schema on wiki but I have a problem with my code, since the output image have wrong colors. Here is my function (excuse the ulgyness…) ``` static uint8_t* yuv420p_to_rgb2(const uint8_t* y, const uint8_t* u, const uint8_t* v, const size_t width, const size_t height) { const size_t size = width * height; uint8_t* rgb = (uint8_t*)calloc((size * 3), sizeof(uint8_t)); int uv_index = 0, pass = 0; int b,g,r; uint8_t* ptr = rgb; for (size_t i = 0; i < size; i += 6) { if (pass == 2) { pass = 0; uv_index += 3; } int y1 = y[i]; int y2 = y[i+1]; int y3 = y[i+2]; int y4 = y[i+3]; int y5 = y[i+4]; int y6 = y[i+5]; int u1 = u[uv_index]; int u2 = u[uv_index+1]; int u3 = u[uv_index+2]; int v1 = v[uv_index]; int v2 = v[uv_index+1]; int v3 = v[uv_index+2]; //1 r = 1.164 * (y1 - 16) + 1.596 * (v1 - 128); g = 1.164 * (y1 - 16) - 0.813 * (v1 - 128) - 0.391 * (u1 - 128); b = 1.164 * (y1 - 16) + 2.018 * (u1 - 128); *ptr++ = CLAMP(r); *ptr++ = CLAMP(g); *ptr++ = CLAMP(b); //2 r = 1.164 * (y2 - 16) + 1.596 * (v1 - 128); g = 1.164 * (y2 - 16) - 0.813 * (v1 - 128) - 0.391 * (u1 - 128); b = 1.164 * (y2 - 16) + 2.018 * (u1 - 128); *ptr++ = CLAMP(r); *ptr++ = CLAMP(g); *ptr++ = CLAMP(b); //3 r = 1.164 * (y3 - 16) + 1.596 * (v2 - 128); g = 1.164 * (y3 - 16) - 0.813 * (v2 - 128) - 0.391 * (u2 - 128); b = 1.164 * (y3 - 16) + 2.018 * (u2 - 128); *ptr++ = CLAMP(r); *ptr++ = CLAMP(g); *ptr++ = CLAMP(b); //4 r = 1.164 * (y4 - 16) + 1.596 * (v2 - 128); g = 1.164 * (y4 - 16) - 0.813 * (v2 - 128) - 0.391 * (u2 - 128); b = 1.164 * (y4 - 16) + 2.018 * (u2 - 128); *ptr++ = CLAMP(r); *ptr++ = CLAMP(g); *ptr++ = CLAMP(b); //5 r = 1.164 * (y5 - 16) + 1.596 * (v3 - 128); g = 1.164 * (y5 - 16) - 0.813 * (v3 - 128) - 0.391 * (u3 - 128); b = 1.164 * (y5 - 16) + 2.018 * (u3 - 128); *ptr++ = CLAMP(r); *ptr++ = CLAMP(g); *ptr++ = CLAMP(b); //6 r = 1.164 * (y6 - 16) + 1.596 * (v3 - 128); g = 1.164 * (y6 - 16) - 0.813 * (v3 - 128) - 0.391 * (u3 - 128); b = 1.164 * (y6 - 16) + 2.018 * (u3 - 128); *ptr++ = CLAMP(r); *ptr++ = CLAMP(g); *ptr++ = CLAMP(b); pass++; } return rgb; } ``` Result (top image is my result, bottom is what it should be): Thanks for your help.