转换YV12到RGB565图像转换,附YUV转RGB测试

背景:

许多年前,自己做了很久的播放客户端,遇到了一个问题,有些显示器无法显示YV12视频图像,需要转换为RGB显示,就是用了这么个函数方法,进行转换,然后把数据塞给Frame进行显示,下面是使用的代码。
    
    转换YUV420P到RGB565,并写入ddraw表面显存pdst中,先创建转换表,然后把每一个像素进行转换。


代码


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);
        }
    }
}

转换公式


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)

参考


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.
 

转换函数测试用例


#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;
}

猜你喜欢

转载自blog.csdn.net/lgs790709/article/details/125487041