2009年6月18日 星期四

YUV to RGB optimization

1.Color space conversion

光是公式偶就找到至少三種,但是其中的差異並不清楚.

R = 1.164 * (Y-16) + + 1.596 * (V-128)
G = 1.164 * (Y-16) - 0.391 * (U-128) - 0.813 * (V-128)
B = 1.164 * (Y-16) + 2.018 * (U-128)


R = Y + 1.370705 (V-128)
G = Y - 0.698001 (V-128) - 0.337633 (U-128)
B = Y + 1.732446 (U-128)


R = Y + 1.4075 * (V-128)
G = Y – 0.3455 * (U –128) – 0.7169 * (V –128)
B = Y + 1.779 * (U – 128)

根據http://www.fourcc.org/indexyuv.htm
第三種"似乎"才是正確的.

由以上公式可看出都需要作浮點運算,而偶的target platform剛好沒有FPU.
直接運算將會是場災難.

2.選擇公式一作轉換.
YUV is 8 bits data. RGB format is  RGB565

R = 1.164 * (Y-16) + 1.596 * (V-128)
G = 1.164 * (Y-16) - 0.391 * (U-128) - 0.813 * (V-128)
B = 1.164 * (Y-16) + 2.018 * (U-128)

***Set variables***

YY = 1.164 * (Y-16)
RV = 1.596 * (V-128)
GU = 0.391 * (U-128)
GV = 0.813 * (V-128)
BU = 2.018 * (U-128)

So we got

R = YY + RV
G = YY - GU - GV
B = YY + BU

***Remove floating point by left shift 15***

YY = (YY << 15) = 38142(y-16)
RV = (RV << 15) = 52298(V-128)
GU = (GU << 15) = 12813(U-128)
GV = (GV << 15) = 26641(V-128)
BU = (BU << 15) = 66126(U-128)

Right shift R,G,B to get result

R = (YY + RV) >> 15
G = (YY - GU - GV) >> 15
B = (YY + BU) >> 15

***Create yuv coefficient tables***

由於YUV為8bits,以上的公式只需要5 * 2^8的表格即可.

int yy[256];

for(i=0;i<256;i++)
  yy[i] = 38142(i-16)

...
...


***Handle RGB565***

   B   G   R
|-----|------|-----|  16bits
   5    6    5

So

R = R >> 3
G = (G & 0xFC) << 3
B = B << 8

***Create RGB result tables***

According to cacluation we know

  481 >= R >= -223
  432 >=  G >= -172
  534 >= B >= -277

We'd like RGB value from 0 to 255, so create tables to map the final value.
Also consider RGB 565 into the tables .

unsigned short rt[481+223];
diffcoef = (double) 481 / 256; /*Ignore value less than zero*/

for(i=0;i<704;i++) {
    if((i + min) < 0)
      rt[i] = 0; /*Ignore value less than zero by setting it to zero*/
    else
    rt[i] = (unsigned short)(i / diffcoef);
    rt[i] >>= 3;  /*Handle RGB565*/
}

...
...

Finally we got

RGB565 = bt[((yy[y]+bu[u]) >> 15) - 277] |
  gt[((yy[y]+gv[v]+gu[u]) >> 15) -172] |
  rt[((yy[y]+rv[v]) >> 15) - 223]


***Reference***

http://realchecko.blogspot.com/2009/02/yuv420-rgb565.html
http://rgbbones.googlepages.com/yuv2rgb
http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
http://multimedia.cx/yuv-3d-rgb.txt

***Example code***

#define precision 32768

typedef struct _ColorSpaceConversion  {
  int yy[256];
  int rv[256];
  int gu[256], gv[256];
  int bu[256];
 
  unsigned short *_rt, *_gt, *_bt;
  unsigned short *rt, *gt, *bt;
} ColorSpaceConversion;

static ColorSpaceConversion csc;

/*
  R = 1.164 * (Y-16) + 1.596 * (V-128)
  G = 1.164 * (Y-16) - 0.391 * (U-128) - 0.813 * (V-128)
  B = 1.164 * (Y-16) + 2.018 * (U-128)
*/

static const int cy = 38142;  //(int)(1.164 * precision);
static const int crv = 52298; //(int)(1.596 * precision);
static const int cgu = 12813; //(int)(0.391 * precision);
static const int cgv = 26641; //(int)(0.813 * precision);
static const int cbu = 66126; //(int)(2.018 * precision);

void ColorSpaceConversion_Init()
{
  int y, u, v;

  for(y=0;y<256;y++)
    csc.yy[y] = cy * (y - 16);

  for(v=0;v<256;v++)
    csc.rv[v] = crv * (v - 128);

  for(u=0;u<256;u++)
    csc.gu[u] = -cgu * (u - 128);

  for(v=0;v<256;v++)
    csc.gv[v] = -cgv * (v - 128);

  for(u=0;u<256;u++)
    csc.bu[u] = cbu * (u - 128);
/*
  R : [ 481, -223 ] -> (481 + 223) / 256 = 2.75
  G : [ 432, -172 ] -> (432 + 172) / 256 = 2.359375
  B : [ 534, -277 ] -> (534 + 277) / 256 = 3.16796857
*/

  int i;
  int max, min, interval;
  double diffcoef;

  max = (csc.yy[255] + csc.rv[255]) >> 15;
  min = (csc.yy[0] + csc.rv[0]) >> 15;
  interval = max - min;
//  diffcoef = (double) interval / 256;
  diffcoef = (double) max / 256;
  printf("R : [ %d, %d ] = %d (%f)\n", max, min, interval, diffcoef);

  csc._rt = malloc(interval * sizeof(unsigned short));
  csc.rt = csc._rt - min;

  for(i=0;i
//    csc._rt[i] = (unsigned short)(i / diffcoef);
    if((i + min) < 0)
      csc._rt[i] = 0;
    else
      csc._rt[i] = (unsigned short)((i+min) / diffcoef);

    csc._rt[i] >>= 3;
  }

/**/

  max = (csc.yy[255] + csc.gu[0] + csc.gv[0]) >> 15;
  min = (csc.yy[0] + csc.gu[255] + csc.gv[255]) >> 15;
  interval = max - min;
//  diffcoef = (double) interval / 256;
  diffcoef = (double) max / 256;
  printf("G : [ %d, %d ] = %d (%f)\n", max, min, interval, diffcoef);

  csc._gt = malloc(interval * sizeof(unsigned short));
  csc.gt = csc._gt - min;

  for(i=0;i
//    csc._gt[i] = (unsigned short)(i / diffcoef);
    if((i + min) < 0)
      csc._gt[i] = 0;
    else
      csc._gt[i] = (unsigned short)((i+min) / diffcoef);

    csc._gt[i] &= 0xfc;
    csc._gt[i] <<= 3;
  }

/**/

  max = (csc.yy[255] + csc.bu[255]) >> 15;
  min = (csc.yy[0] + csc.bu[0]) >> 15;
  interval = max - min;
//  diffcoef = (double) interval / 256;
  diffcoef = (double) max / 256;
  printf("B : [ %d, %d ] = %d (%f)\n", max, min, interval, diffcoef);

  csc._bt = malloc(interval * sizeof(unsigned short));
  csc.bt = csc._bt - min;

  for(i=0;i
//    csc._bt[i] = (unsigned short)(i / diffcoef);
    if((i + min) < 0)
      csc._bt[i] = 0;
    else
      csc._bt[i] = (unsigned short)((i+min) / diffcoef);

    csc._bt[i] &= 0xf8;
    csc._bt[i] <<= 8;
  }
}

void ColorSpaceConversion_Deinit()
{
  free(csc.rt);
  free(csc.gt);
  free(csc.bt);
}


 




沒有留言:

張貼留言