Convert YV12 to RGB565 image conversion, with YUV to RGB test

background:

Many years ago, I made a playback client for a long time and encountered a problem. Some monitors cannot display YV12 video images and need to be converted to RGB display. I used such a function method to convert and then stuff the data into the Frame. displayed, below is the code used.
    
    Convert YUV420P to RGB565, and write it into the ddraw surface memory pdst, first create a conversion table, and then convert each pixel.


the code


int* colortab;
int* u_b_tab;
int* u_g_tab;
int* v_g_tab;
int* v_r_tab;
unsigned int * r_2_pix;
unsigned int * g_2_pix;
unsigned int * b_2_pix;


//创建转换表
void CreateYUVTab()
{
    int i;
    int u, v;

    colortab = (int *)malloc(4*256*sizeof(int));
    u_b_tab = &colortab[0*256];
    u_g_tab = &colortab[1*256];
    v_g_tab = &colortab[2*256];
    v_r_tab = &colortab[3*256];

    for (i=0; i<256; i++)
    {
        u = v = (i-128);

        u_b_tab[i] = (int) ( 1.772 * u);
        u_g_tab[i] = (int) ( 0.34414 * u);
        v_g_tab[i] = (int) ( 0.71414 * v); 
        v_r_tab[i] = (int) ( 1.402 * v);
    }

    rgb_2_pix = (unsigned int *)malloc(3*768*sizeof(unsigned int));

    r_2_pix = &rgb_2_pix[0*768];
    g_2_pix = &rgb_2_pix[1*768];
    b_2_pix = &rgb_2_pix[2*768];

    for(i=0; i<256; i++)
    {
        r_2_pix[i] = 0;
        g_2_pix[i] = 0;
        b_2_pix[i] = 0;
    }

    for(i=0; i<256; i++)
    {
        r_2_pix[i+256] = (i & 0xF8) << 8;
        g_2_pix[i+256] = (i & 0xFC) << 3;
        b_2_pix[i+256] = (i ) >> 3;
    }

    for(i=0; i<256; i++)
    {
        r_2_pix[i+512] = 0xF8 << 8;
        g_2_pix[i+512] = 0xFC << 3;
        b_2_pix[i+512] = 0x1F;
    }

    r_2_pix += 256;
    g_2_pix += 256;
    b_2_pix += 256;
}
//转换YUV420P到RGB565,并写入ddraw表面显存pdst中
//y,u,v 三个向量字节序列
//src_ystride 源的y行宽
//src_uvstride 源的uv行宽
//dst_ystride 目的行宽
void DisplayYUV(unsigned int *pdst, unsigned char *y, unsigned char *u, unsigned char *v, int width, int height, int src_ystride, int src_uvstride, int dst_ystride)
{
    int i, j;
    int r, g, b, rgb;

    int yy, ub, ug, vg, vr;

    const int width2 = width/2;//图像宽的一半
    const int height2 = height/2;//图像高的一半

    unsigned char* yoff;
    unsigned char* uoff;
    unsigned char* voff;

    for(j=0; j<height2; j++)//逐行循环
    {
        yoff = y + j * 2 * src_ystride;
        uoff = u + j * src_uvstride;
        voff = v + j * src_uvstride;

        for(i=0; i<width2; i++)//逐列循环
        {
            yy  = *(yoff+(i<<1));
            ub = u_b_tab[*(uoff+i)];
            ug = u_g_tab[*(uoff+i)];
            vg = v_g_tab[*(voff+i)];
            vr = v_r_tab[*(voff+i)];

            b = yy + ub;
            g = yy - ug - vg;
            r = yy + vr;

            rgb = r_2_pix[r] + g_2_pix[g] + b_2_pix[b];

            yy = *(yoff+(i<<1)+1);
            b = yy + ub;
            g = yy - ug - vg;
            r = yy + vr;

            pdst[(j*dst_ystride+i)] = (rgb)+((r_2_pix[r] + g_2_pix[g] + b_2_pix[b])<<16);

            yy = *(yoff+(i<<1)+src_ystride);
            b = yy + ub;
            g = yy - ug - vg;
            r = yy + vr;

            rgb = r_2_pix[r] + g_2_pix[g] + b_2_pix[b];

            yy = *(yoff+(i<<1)+src_ystride+1);
            b = yy + ub;
            g = yy - ug - vg;
            r = yy + vr;

            pdst [((2*j+1)*dst_ystride+i*2)>>1] = (rgb)+((r_2_pix[r] + g_2_pix[g] + b_2_pix[b])<<16);
        }
    }
}

conversion formula


RGB to YUV Conversion

    Y  =      (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
    Cr = V =  (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
    Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128


YUV to RGB Conversion
    B = 1.164(Y - 16) + 2.018(U - 128)
    G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
    R = 1.164(Y - 16) + 1.596(V - 128)

reference


http://forum.videohelp.com/topic290086.html

I played a little with the code, and I found the right conversion formulas:

#define GETR(y,u,v) ((1.164 * (y - 16)) + (1.596 * ((v) - 128))) #define GETG(y,u,v) ((1.164 * (y
- 16)) - (0.813 * ((v) - 128)) - (0.391 * ((u) - 128))) #define
GETB(y,u,v) ((1.164 * (y - 16)) + ( 2.018 * ((u) - 128)))

Images seems to be in the right color using these formulas.
 

Conversion function test case


#include <TIME.H>
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
using namespace std;


void YUV2RGB(unsigned char Y, unsigned char U, unsigned char V, unsigned char* pRGB)
{
	int R, G, B;
	B = (int)(1.164*(Y - 16) + 2.018*(U - 128));
	G = (int)(1.164*(Y - 16) - 0.813*(V - 128) - 0.391*(U - 128));
	R = (int)(1.164*(Y - 16) + 1.596*(V - 128));
// #define GETR(y,u,v) ((1.164 * (y - 16)) + (1.596 * ((v) - 128)))
// #define GETG(y,u,v) ((1.164 * (y - 16)) - (0.813 * ((v) - 128)) - (0.391 * ((u) - 128)))
// #define GETB(y,u,v) ((1.164 * (y - 16)) + (2.018 * ((u) - 128)))
//cout << "RGB("<<GETR(y,u,v)<<","<<GETG(y,u,v)<<","<<GETB(y,u,v)<<","<<")"<<endl;
//cout << "("<<(int)Y<<","<<(int)U<<","<<(int)V<<")->RGB("<<R<<","<<G<<","<<B<<","<<")"<<endl;

	R= min(255,max(0,R));
	G= min(255,max(0,G));
	B= min(255,max(0,B));

	pRGB[0] = R ;
	pRGB[1] = G;
	pRGB[2] = B;
	return;
}
void RGB2YUV(unsigned char R, unsigned char G, unsigned char B, unsigned char* pYUV)
{
	int Y, U, V;

	Y = 16  + 0.257*R + 0.504*G + 0.098*B;
	U = 128 - 0.148*R - 0.291*G + 0.439*B;
	V = 128 + 0.439*R - 0.368*G - 0.071*B;

	Y= min(255,max(0,Y));
	U= min(255,max(0,U));
	V= min(255,max(0,V));

 	pYUV[0] = Y;
 	pYUV[1] = U;
 	pYUV[2] = V;

	return;
}

int __cdecl main (int argc, CHAR **argv)
{
	unsigned char RGB[3];
	unsigned char YUV[3];

	int r=255,g=0,b=0;
	RGB2YUV(r, g, b, YUV);
	cout << "("<<(unsigned int)(YUV[0])<<","<<(unsigned int)(YUV[1])<<","<<(unsigned int)(YUV[2])<<")->RGB("<<r<<","<<g<<","<<b<<","<<")"<<endl;

	int y=(unsigned int)(YUV[0]),u=(unsigned int)(YUV[1]),v=(unsigned int)(YUV[2]);
	YUV2RGB(y, u, v, RGB);
	cout << "("<<(int)y<<","<<(int)u<<","<<(int)v<<")->RGB("<<(unsigned int)(RGB[0])<<","<<(unsigned int)(RGB[1])<<","<<(unsigned int)(RGB[2])<<","<<")"<<endl;

	system( "PAUSE" );
	return 0;
}

Guess you like

Origin blog.csdn.net/lgs790709/article/details/125487041