优化RGB->YUV
Posted
网上随处可见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);
}