优化RGB->YUV

网上随处可见YUV到RGB的优化,其中被借鉴最多的应该就是VP8的源码了吧:

// Copyright 2010 Google Inc.
//
// This code is licensed under the same terms as WebM:
//  Software License Agreement:  http://www.webmproject.org/license/software/
//  Additional IP Rights Grant:  http://www.webmproject.org/license/additional/
// -----------------------------------------------------------------------------
//
// YUV->RGB conversion function
//
// Author: Skal (pascal.massimino@gmail.com)

#include "yuv.h"

#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif

enum { YUV_HALF = 1 << (YUV_FIX - 1) };

int16_t VP8kVToR[256], VP8kUToB[256];
int32_t VP8kVToG[256], VP8kUToG[256];
uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];

static int done = 0;

void VP8YUVInit() {
  int i;
  if (done) {
    return;
  }
  for (i = 0; i < 256; ++i) {
    VP8kVToR[i] = (89858 * (i - 128) + YUV_HALF) >> YUV_FIX;
    VP8kUToG[i] = -22014 * (i - 128) + YUV_HALF;
    VP8kVToG[i] = -45773 * (i - 128);
    VP8kUToB[i] = (113618 * (i - 128) + YUV_HALF) >> YUV_FIX;
  }
  for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
    const int k = ((i - 16) * 76283 + YUV_HALF) >> YUV_FIX;
    VP8kClip[i - YUV_RANGE_MIN] = (k < 0) ? 0 : (k > 255) ? 255 : k;
  }
  done = 1;
}

#if defined(__cplusplus) || defined(c_plusplus)
}    // extern "C"
#endif

但罕见RGB到YUV的转换(太冷门了么亲。。。)

移位(浮点转整型)建表后通过查表法来加速转换的代码有这么复杂么。。。


做回好人吧。

在上面代码的基础上,增加:(对,我为了看得懂还特意把对应的转换公式(包括YUV->RGB的)放上去了,这公式见仁见智,有特殊需要的自行替换修改)

  int16_t Itable257[I_TABLE_SIZE], Itable504[I_TABLE_SIZE], Itable098[I_TABLE_SIZE], Itable148[I_TABLE_SIZE], Itable291[I_TABLE_SIZE], Itable439[I_TABLE_SIZE], Itable368[I_TABLE_SIZE], Itable071[I_TABLE_SIZE];

  static int done = 0;

  /*
  Y' = 0.257*R' + 0.504*G' + 0.098*B' + 16
  Cb' = -0.148*R' - 0.291*G' + 0.439*B' + 128
  Cr' = 0.439*R' - 0.368*G' - 0.071*B' + 128
  R' = 1.164*(Y'-16) + 1.596*(Cr' - 128) = 1.164*(Y'-16 + 1.371*(Cr'-128) //vise versa
  G' = 1.164*(Y'-16) - 0.813*(Cr' - 128) - 0.392*(Cb'-128)
  B' = 1.164*(Y'-16) + 2.017*(Cb' - 128)
  */

  void TransformTableInit() {
    int i;
    if (done) {
      return;
    }
    for (i = 0; i < I_TABLE_SIZE; ++i) {
      Itable257[i] = (16842 * i + YUV_HALF) >> YUV_FIX;
      Itable504[i] = (33030 * i + YUV_HALF) >> YUV_FIX;
      Itable098[i] = (6422 * i + YUV_HALF) >> YUV_FIX;
      Itable148[i] = (-9699 * i + YUV_HALF) >> YUV_FIX;
      Itable291[i] = (-19070 * i + YUV_HALF) >> YUV_FIX;
      Itable439[i] = (28770 * i + YUV_HALF) >> YUV_FIX;
      Itable368[i] = (-24117 * i + YUV_HALF) >> YUV_FIX;
      Itable071[i] = (-4653 * i + YUV_HALF) >> YUV_FIX;
    }
    done = 1;
  }

还是熟悉的用法,还是熟悉的味道:

  inline static void RgbToY(uint8_t* rgb, uint8_t* const y) {
    *y = Itable257[rgb[0]] + Itable504[rgb[1]] + Itable098[rgb[2]] + 16;
  }

  inline static void RgbToU(uint8_t* rgb, uint8_t* const u) {
    *u = Itable148[rgb[0]] + Itable291[rgb[1]] + Itable439[rgb[2]] + 128;
  }

  inline static void RgbToV(uint8_t* rgb, uint8_t* const v) {
    *v = Itable439[rgb[0]] + Itable368[rgb[1]] + Itable071[rgb[2]] + 128;
  }

  inline static void RgbToYuv(uint8_t* rgb, uint8_t* const y, uint8_t* const u, uint8_t* const v) {
    RgbToY(rgb, y);
    RgbToU(rgb, u);
    RgbToV(rgb, v);
  }

  inline static void RgbaToYuv(uint8_t* rgba, uint8_t* const y, uint8_t* const u, uint8_t* const v) {
    RgbToYuv(rgba, y, u, v);
  }