文章目录
一:RGB32转RGB24
RGB32与RGB24相比多个Alpha分量,因此在转化的时候可以选择直接丢弃Alpha分量,也可以选择将r、g和b分别乘以归一化的Alpha因子。例如RGBA转RGB:
void rgba_to_rgb(const uint8_t *src, uint8_t *dst, uint32_t width, uint32_t height, bool alpha)
{
uint8_t *src_ptr = const_cast<uint8_t *>(src);
uint8_t *dst_ptr = dst;
float a = 1.f;
int src_pos = 0;
int dst_pos = 0;
if (alpha) {
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
src_pos = i * 4 + j;
dst_pos = i * 3 + j;
a = (*(src_ptr + src_pos + 3)) / 255.f;
*(dst_ptr + dst_pos) = *(src_ptr + src_pos) * a;
*(dst_ptr + dst_pos + 1) = *(src_ptr + src_pos + 1) * a;
*(dst_ptr + dst_pos + 2) = *(src_ptr + src_pos + 2) * a;
}
}
}
else {
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
src_pos = i * 4 + j;
dst_pos = i * 3 + j;
*(dst_ptr + dst_pos) = *(src_ptr + src_pos);
*(dst_ptr + dst_pos + 1) = *(src_ptr + src_pos + 1);
*(dst_ptr + dst_pos + 2) = *(src_ptr + src_pos + 2);
}
}
}
}
二:YUV与RGB相互转换
Keith Jack’s的书《Video Demystified》(ISBN 1-878707-09-4) 给出的转换公式:
RGB->YUV:
Y = 0.257 R + 0.504 G + 0.098 B + 16 C r = V = 0.439 R − 0.368 G − 0.071 B + 128 C b = U = − 0.148 R − 0.291 G + 0.439 B + 128 Y=0.257R+0.504G+0.098B+16\\ Cr=V=0.439R-0.368G-0.071B+128\\ Cb=U=-0.148R-0.291G+0.439B+128 Y=0.257R+0.504G+0.098B+16Cr=V=0.439R−0.368G−0.071B+128Cb=U=−0.148R−0.291G+0.439B+128
YUV->RGB:
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 ) 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) 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)
上述式子RGB范围为 [ 0 , 255 ] [0,255] [0,255] ;Y范围为 [ 16 , 235 ] [16, 235] [16,235] ;UV范围为 [ 16 , 239 ] [16, 239] [16,239] 。计算超出范围后需要截断处理。
CCIR 601定义的转换公式为:
RGB->YUV:
Y = 0.299 R + 0.587 G + 0.114 B C r = V = 0.713 ( R − Y ) = 0.500 R − 0.419 G − 0.081 B C b = U = 0.564 ( B − Y ) = − 0.169 R − 0.331 G + 0.500 B Y=0.299R+0.587G+0.114B\\ Cr=V=0.713(R-Y)=0.500R-0.419G-0.081B\\ Cb=U=0.564(B-Y)=-0.169R-0.331G+0.500B Y=0.299R+0.587G+0.114BCr=V=0.713(R−Y)=0.500R−0.419G−0.081BCb=U=0.564(B−Y)=−0.169R−0.331G+0.500B
YUV->RGB:
R = Y + 1.403 V G = Y − 0.344 U − 0.714 V B = Y + 1.770 U R=Y+1.403V\\ G=Y-0.344U-0.714V\\ B=Y+1.770U R=Y+1.403VG=Y−0.344U−0.714VB=Y+1.770U
上述式子RGB范围为 [ 0 , 1 ] [0, 1] [0,1] ;Y范围为 [ 0 , 1 ] [0, 1] [0,1] ;Cr和Cb范围为 [ − 0.5 , 0.5 ] [-0.5, 0.5] [−0.5,0.5] 。
如果把RGB和YUV的范围都缩放到 [ 0 , 255 ] [0, 255] [0,255] ,常用的转换公式为:
RGB->YUV:
Y = 0.299 R + 0.587 G + 0.114 B C r = V = 0.500 R − 0.419 G − 0.081 B + 128 C b = U = − 0.169 R − 0.331 G + 0.500 B + 128 Y=0.299R+0.587G+0.114B\\ Cr=V=0.500R-0.419G-0.081B+128\\ Cb=U=-0.169R-0.331G+0.500B+128 Y=0.299R+0.587G+0.114BCr=V=0.500R−0.419G−0.081B+128Cb=U=−0.169R−0.331G+0.500B+128
YUV->RGB:
R = Y + 1.403 ∗ ( V − 128 ) G = Y − 0.343 ∗ ( U − 128 ) − 0.714 ∗ ( V − 128 ) B = Y + 1.770 ∗ ( U − 128 ) R=Y+1.403*(V-128)\\ G=Y-0.343*(U-128)-0.714*(V-128)\\ B=Y+1.770*(U-128) R=Y+1.403∗(V−128)G=Y−0.343∗(U−128)−0.714∗(V−128)B=Y+1.770∗(U−128)
2.1 YUV->RGB
2.1.1 常规转换
按照公式进行常规运算,包含浮点运算和乘法运算。
void yuv_to_rgb(uint8_t y, uint8_t u, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b)
{
int _r = y + 1.403 * (v - 128);
int _g = y - 0.343 * (u - 128) - 0.714 * (v - 128);
int _b = y + 1.770 * (u - 128);
*r = _r > 255 ? 255 : (_r < 0 ? 0 : (uint8_t)_r);
*g = _g > 255 ? 255 : (_g < 0 ? 0 : (uint8_t)_g);
*b = _b > 255 ? 255 : (_b < 0 ? 0 : (uint8_t)_b);
}
2.1.2 去浮点转换
去除转换公式中的浮点运算,但会有精度损失:
R
=
Y
+
1.403
∗
(
V
−
128
)
G
=
Y
−
0.343
∗
(
U
−
128
)
−
0.714
∗
(
V
−
128
)
B
=
Y
+
1.770
∗
(
U
−
128
)
R=Y+1.403*(V-128)\\ G=Y-0.343*(U-128)-0.714*(V-128)\\ B=Y+1.770*(U-128)
R=Y+1.403∗(V−128)G=Y−0.343∗(U−128)−0.714∗(V−128)B=Y+1.770∗(U−128)
转换为:
V
′
=
V
−
128
U
′
=
U
−
128
R
=
Y
+
1.403
∗
V
′
=
Y
+
V
′
+
0.403
∗
V
′
≈
Y
+
V
′
+
(
(
V
′
∗
103
)
>
>
8
)
G
=
Y
−
0.343
∗
U
′
−
0.714
∗
V
′
≈
Y
−
(
(
U
′
∗
88
)
>
>
8
)
−
(
(
V
′
∗
183
)
>
>
8
)
B
=
Y
+
1.770
∗
U
′
≈
Y
+
U
′
+
(
(
U
′
∗
198
)
>
>
8
)
V'=V-128\\ U'=U-128\\ R=Y+1.403*V'=Y+V'+0.403*V'≈Y+V'+((V'*103)>>8)\\ G=Y-0.343*U'-0.714*V'≈Y-((U'*88)>>8)-((V'*183)>>8)\\ B=Y+1.770*U'≈Y+U'+((U'*198)>>8)
V′=V−128U′=U−128R=Y+1.403∗V′=Y+V′+0.403∗V′≈Y+V′+((V′∗103)>>8)G=Y−0.343∗U′−0.714∗V′≈Y−((U′∗88)>>8)−((V′∗183)>>8)B=Y+1.770∗U′≈Y+U′+((U′∗198)>>8)
void yuv_to_rgb_faster(uint8_t y, uint8_t u, uint8_t v,
uint8_t *r, uint8_t *g, uint8_t *b)
{
int _u = u - 128;
int _v = v - 128;
int _r = y + _v + ((_v * 103) >> 8);
int _g = y - ((_u * 88) >> 8) - ((_v * 183) >> 8);
int _b = y + _u + ((_u * 198) >> 8);
*r = _r > 255 ? 255 : (_r < 0 ? 0 : (uint8_t)_r);
*g = _g > 255 ? 255 : (_g < 0 ? 0 : (uint8_t)_g);
*b = _b > 255 ? 255 : (_b < 0 ? 0 : (uint8_t)_b);
}
2.1.3 去浮点去乘法转换
接上面优化,去除乘法操作(改乘法为右移操作):
R
≈
Y
+
V
′
+
(
(
V
′
∗
(
64
+
32
+
4
+
2
+
1
)
)
>
>
8
)
=
Y
+
V
′
+
(
(
(
V
′
<
<
6
)
+
(
V
′
<
<
5
)
+
(
V
′
<
<
2
)
+
(
V
′
<
<
1
)
+
V
′
)
>
>
8
)
G
≈
Y
−
(
(
U
′
∗
(
64
+
16
+
8
)
)
>
>
8
)
−
(
(
V
′
∗
(
128
+
32
+
16
+
4
+
2
+
1
)
)
>
>
8
)
=
Y
−
(
(
(
U
′
<
<
6
)
+
(
U
′
<
<
4
)
+
(
U
′
<
<
3
)
>
>
8
)
−
(
(
(
V
′
<
<
7
)
+
(
V
′
<
<
5
)
+
(
V
′
<
<
4
)
+
(
V
′
<
<
2
)
+
(
V
′
<
<
1
)
+
V
′
)
>
>
8
)
B
≈
Y
+
U
′
+
(
(
U
′
∗
(
128
+
64
+
4
+
2
)
)
>
>
8
)
=
Y
+
U
′
+
(
(
(
U
′
<
<
7
)
+
(
U
′
<
<
6
)
+
(
U
′
<
<
2
)
+
(
U
′
<
<
1
)
)
>
>
8
)
R≈Y+V'+((V'*(64 + 32 + 4 + 2 + 1))>>8)\\ =Y+V'+(((V'<<6)+(V'<<5)+(V'<<2)+(V'<<1)+V')>>8)\\ G≈Y-((U'*(64 + 16 + 8))>>8)-((V'*(128+32+16+4+2+1))>>8)\\ =Y-(((U'<<6)+(U'<<4)+(U'<<3)>>8)-(((V'<<7)+(V'<<5)+(V'<<4)+(V'<<2)+(V'<<1)+V')>>8)\\ B≈Y+U'+((U'*(128+64+4+2))>>8)\\ =Y+U'+(((U'<<7)+(U'<<6)+(U'<<2)+(U'<<1))>>8)
R≈Y+V′+((V′∗(64+32+4+2+1))>>8)=Y+V′+(((V′<<6)+(V′<<5)+(V′<<2)+(V′<<1)+V′)>>8)G≈Y−((U′∗(64+16+8))>>8)−((V′∗(128+32+16+4+2+1))>>8)=Y−(((U′<<6)+(U′<<4)+(U′<<3)>>8)−(((V′<<7)+(V′<<5)+(V′<<4)+(V′<<2)+(V′<<1)+V′)>>8)B≈Y+U′+((U′∗(128+64+4+2))>>8)=Y+U′+(((U′<<7)+(U′<<6)+(U′<<2)+(U′<<1))>>8)
void yuv_to_rgb_speed(uint8_t y, uint8_t u, uint8_t v,
uint8_t *r, uint8_t *g, uint8_t *b)
{
int _u = u - 128;
int _v = v - 128;
int _r = y + _v + (((_v << 6) + (_v << 5) + (_v << 2) + (_v << 1) + _v) >> 8);
int _g = y - (((_u << 6) + (_u << 4) + (_u << 3)) >> 8) - (((_v << 7) + (_v << 5)
+ (_v << 4) + (_v << 2) + (_v << 1) + _v) >> 8);
int _b = y + _u + (((_u << 7) + (_u << 6) + (_u << 2) + (_u << 1)) >> 8);
*r = _r > 255 ? 255 : (_r < 0 ? 0 : (uint8_t)_r);
*g = _g > 255 ? 255 : (_g < 0 ? 0 : (uint8_t)_g);
*b = _b > 255 ? 255 : (_b < 0 ? 0 : (uint8_t)_b);
}
2.1.4 查表转换
查表法为事先将计算结果存储在表中,之后在表中查找。由于Y、U和V分量为 [ 0 , 255 ] [0, 255] [0,255] 之间的离散值,所以可以采用查表法:
uint8_t g_r[256][256];
uint8_t g_g[256][256][256];
uint8_t g_b[256][256];
void setup_yuv_to_rgb_table()
{
// R = Y + 1.403 * (V - 128);
// g_r[Y][V]
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
int r = i + 1.403 * (j - 128);
g_r[i][j] = r > 255 ? 255 : (r < 0 ? 0 : (uint8_t)r);
}
}
// G = Y - 0.343 * (U - 128) - 0.714 * (V - 128);
// g_g[Y][U][V]
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
for (int k = 0; k < 256; k++) {
int g = i - 0.343 * (j - 128) - 0.714 * (k - 128);
g_g[i][j][k] = g > 255 ? 255 : (g < 0 ? 0 : (uint8_t)g);
}
}
}
// B = Y + 1.770 * (U - 128);
// g_b[Y][U]
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
int b = i + 1.770 * (j - 128);
g_b[i][j] = b > 255 ? 255 : (b < 0 ? 0 : (uint8_t)b);
}
}
}
void yuv_to_rgb_table(uint8_t y, uint8_t u, uint8_t v,
uint8_t *r, uint8_t *g, uint8_t *b)
{
*r = g_r[y][v];
*g = g_g[y][u][v];
*b = g_b[y][u];
}
2.1.5 测试
void test_yuv_to_rgb()
{
uint8_t y = 100, u = 100, v = 100;
uint8_t r = 0, g = 0, b = 0;
uint64_t loop = 1000000000;
// Normal
auto time_start = std::chrono::system_clock::now();
for (uint64_t i = 0; i < loop; i++) {
yuv_to_rgb(y, u, v, &r, &g, &b);
}
std::cout << std::to_string(r) << ", " << std::to_string(g) << " ," << std::to_string(b) << std::endl;
std::chrono::duration<double> time_spend = std::chrono::system_clock::now() - time_start;
double time_cost = time_spend.count() * 1000;
std::cout << "Normal Time: " << time_cost << " ms" << std::endl;
// Faster
time_start = std::chrono::system_clock::now();
for (uint64_t i = 0; i < loop; i++) {
yuv_to_rgb_faster(y, u, v, &r, &g, &b);
}
std::cout << std::to_string(r) << ", " << std::to_string(g) << " ," << std::to_string(b) << std::endl;
time_spend = std::chrono::system_clock::now() - time_start;
time_cost = time_spend.count() * 1000;
std::cout << "Faster Time: " << time_cost << " ms" << std::endl;
// Speed
time_start = std::chrono::system_clock::now();
for (uint64_t i = 0; i < loop; i++) {
yuv_to_rgb_speed(y, u, v, &r, &g, &b);
}
std::cout << std::to_string(r) << ", " << std::to_string(g) << " ," << std::to_string(b) << std::endl;
time_spend = std::chrono::system_clock::now() - time_start;
time_cost = time_spend.count() * 1000;
std::cout << "Speed Time: " << time_cost << " ms" << std::endl;
// Table
setup_yuv_to_rgb_table();
time_start = std::chrono::system_clock::now();
for (uint64_t i = 0; i < loop; i++) {
yuv_to_rgb_table(y, u, v, &r, &g, &b);
}
std::cout << std::to_string(r) << ", " << std::to_string(g) << " ," << std::to_string(b) << std::endl;
time_spend = std::chrono::system_clock::now() - time_start;
time_cost = time_spend.count() * 1000;
std::cout << "Table Time: " << time_cost << " ms" << std::endl;
}
测试结果:
移位操作替代乘法操作的优化实际运行结果并不一定好于乘法算法,另外Release模式下要去除全程序优化,否则时间测量无效。
2.2 RGB->YUV
2.2.1 常规转换
按照公式进行常规运算,包含浮点运算和乘法运算。
void rgb_to_yuv(uint8_t r, uint8_t g, uint8_t b, uint8_t *y, uint8_t *u, uint8_t *v)
{
int _y = 0.299 * r + 0.587 * g + 0.114 * b;
int _u = -0.169 * r - 0.331 * g + 0.500 * b + 128;
int _v = 0.500 * r - 0.419 * g - 0.081 * b + 128;
*y = _y > 255 ? 255 : (_y < 0 ? 0 : (uint8_t)_y);
*u = _u > 255 ? 255 : (_u < 0 ? 0 : (uint8_t)_u);
*v = _v > 255 ? 255 : (_v < 0 ? 0 : (uint8_t)_v);
}
2.2.2 去浮点转换
Y
=
0.299
R
+
0.587
G
+
0.114
B
C
r
=
V
=
0.500
R
−
0.419
G
−
0.081
B
+
128
C
b
=
U
=
−
0.169
R
−
0.331
G
+
0.500
B
+
128
Y=0.299R+0.587G+0.114B\\ Cr=V=0.500R-0.419G-0.081B+128\\ Cb=U=-0.169R-0.331G+0.500B+128
Y=0.299R+0.587G+0.114BCr=V=0.500R−0.419G−0.081B+128Cb=U=−0.169R−0.331G+0.500B+128
转化为:
Y
=
0.299
R
+
0.587
G
+
0.114
B
=
(
77
R
+
150
G
+
29
B
)
>
>
8
C
r
=
V
=
0.500
R
−
0.419
G
−
0.081
B
+
128
=
(
128
R
−
107
G
−
21
B
+
32768
)
>
>
8
C
b
=
U
=
−
0.169
R
−
0.331
G
+
0.500
B
+
128
=
(
−
43
R
−
85
G
+
128
B
+
32768
)
>
>
8
Y=0.299R+0.587G+0.114B=(77R+150G+29B)>>8\\ Cr=V=0.500R-0.419G-0.081B+128=(128R-107G-21B+32768)>>8\\ Cb=U=-0.169R-0.331G+0.500B+128=(-43R-85G+128B+32768)>>8
Y=0.299R+0.587G+0.114B=(77R+150G+29B)>>8Cr=V=0.500R−0.419G−0.081B+128=(128R−107G−21B+32768)>>8Cb=U=−0.169R−0.331G+0.500B+128=(−43R−85G+128B+32768)>>8
void rgb_to_yuv_faster(uint8_t r, uint8_t g, uint8_t b, uint8_t *y, uint8_t *u, uint8_t *v)
{
int _y = ((77 * r + 150 * g + 29 * b) >> 8);
int _u = ((128 * r - 107 * g - 21 * b + 32768) >> 8);
int _v = ((-43 * r - 85 * g + 128 * b + 32768) >> 8);
*y = _y > 255 ? 255 : (_y < 0 ? 0 : (uint8_t)_y);
*u = _u > 255 ? 255 : (_u < 0 ? 0 : (uint8_t)_u);
*v = _v > 255 ? 255 : (_v < 0 ? 0 : (uint8_t)_v);
}
2.2.3 去浮点去乘法转换
Y = ( R < < 6 + R < < 3 + R < < 2 + R + G < < 7 + G < < 4 + G < < 2 + G < < 1 + B < < 4 + B < < 3 + B < < 2 + B ) > > 8 U = ( R < < 7 − G < < 6 − G < < 5 − G < < 3 − G < < 1 − G − B < < 4 − B < < 2 − B + 32768 ) > > 8 V = ( − R < < 5 − R < < 3 − R < < 1 − R − G < < 6 − G < < 4 − G < < 2 − G + B < < 7 + 32768 ) > > 8 Y=(R<<6+R<<3+R<<2+R+G<<7+G<<4+G<<2+G<<1+B<<4+B<<3+B<<2+B)>>8\\ U=(R<<7-G<<6-G<<5-G<<3-G<<1-G-B<<4-B<<2-B+32768)>>8\\ V=(-R<<5-R<<3-R<<1-R-G<<6-G<<4-G<<2-G+B<<7+32768)>>8 Y=(R<<6+R<<3+R<<2+R+G<<7+G<<4+G<<2+G<<1+B<<4+B<<3+B<<2+B)>>8U=(R<<7−G<<6−G<<5−G<<3−G<<1−G−B<<4−B<<2−B+32768)>>8V=(−R<<5−R<<3−R<<1−R−G<<6−G<<4−G<<2−G+B<<7+32768)>>8
void rgb_to_yuv_speed(uint8_t r, uint8_t g, uint8_t b, uint8_t *y, uint8_t *u, uint8_t *v)
{
int _y = (((r << 6) + (r << 3) + (r << 2) + r + (g << 7) + (g << 4) + (g << 2) + (g << 1)
+ (b << 4) + (b << 3) + (b << 2) + b) >> 8);
int _u = (((r << 7) - (g << 6) - (g << 5) - (g << 3) - (g << 1) - g
- (b << 4) - (b << 2) - b + 32768) >> 8);
int _v = ((-(r << 5) - (r << 3) - (r << 1) - r - (g << 6) - (g << 4) - (g << 2) - g
+ (b << 7) + 32768) >> 8);
*y = _y > 255 ? 255 : (_y < 0 ? 0 : (uint8_t)_y);
*u = _u > 255 ? 255 : (_u < 0 ? 0 : (uint8_t)_u);
*v = _v > 255 ? 255 : (_v < 0 ? 0 : (uint8_t)_v);
}
2.2.4 查表转换
事先存储计算结果,转换时直接查表:
uint8_t g_y[256][256][256];
uint8_t g_u[256][256][256];
uint8_t g_v[256][256][256];
void setup_rgb_to_yuv_table()
{
// Y = 0.299 * R + 0.587 * G + 0.114 * B;
// g_y[r][g][b]
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
for (int k = 0; k < 256; k++) {
int y = 0.299 * i + 0.587 * j + 0.114 * k;
g_y[i][j][k] = y > 255 ? 255 : (y < 0 ? 0 : (uint8_t)y);
}
}
}
// U = -0.169 * R - 0.331 * G + 0.500 * B + 128;
// g_u[r][g][b]
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
for (int k = 0; k < 256; k++) {
int u = -0.169 * i - 0.331 * j + 0.500 * k + 128;
g_u[i][j][k] = u > 255 ? 255 : (u < 0 ? 0 : (uint8_t)u);
}
}
}
// V = 0.500 * R - 0.419 * G - 0.081 * B + 128;
// g_v[r][g][b]
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
for (int k = 0; k < 256; k++) {
int v = 0.500 * i - 0.419 * j - 0.081 * k + 128;
g_v[i][j][k] = v > 255 ? 255 : (v < 0 ? 0 : (uint8_t)v);
}
}
}
}
void rgb_to_yuv_table(uint8_t r, uint8_t g, uint8_t b, uint8_t *y, uint8_t *u, uint8_t *v)
{
*y = g_y[r][g][b];
*u = g_u[r][g][b];
*v = g_v[r][g][b];
}
2.2.5 测试
void test_rgb_to_yuv()
{
uint8_t r = 100, g = 100, b = 100;
uint8_t y = 0, u = 0, v = 0;
uint64_t loop = 1000000000;
// Normal
auto time_start = std::chrono::system_clock::now();
for (uint64_t i = 0; i < loop; i++) {
rgb_to_yuv(r, g, b, &y, &u, &v);
}
std::cout << std::to_string(y) << ", " << std::to_string(u) << " ," << std::to_string(v) << std::endl;
std::chrono::duration<double> time_spend = std::chrono::system_clock::now() - time_start;
double time_cost = time_spend.count() * 1000;
std::cout << "Normal Time: " << time_cost << " ms" << std::endl;
// Faster
time_start = std::chrono::system_clock::now();
for (uint64_t i = 0; i < loop; i++) {
rgb_to_yuv_faster(r, g, b, &y, &u, &v);
}
std::cout << std::to_string(y) << ", " << std::to_string(u) << " ," << std::to_string(v) << std::endl;
time_spend = std::chrono::system_clock::now() - time_start;
time_cost = time_spend.count() * 1000;
std::cout << "Faster Time: " << time_cost << " ms" << std::endl;
// Speed
time_start = std::chrono::system_clock::now();
for (uint64_t i = 0; i < loop; i++) {
rgb_to_yuv_speed(r, g, b, &y, &u, &v);
}
std::cout << std::to_string(y) << ", " << std::to_string(u) << " ," << std::to_string(v) << std::endl;
time_spend = std::chrono::system_clock::now() - time_start;
time_cost = time_spend.count() * 1000;
std::cout << "Speed Time: " << time_cost << " ms" << std::endl;
// Table
setup_rgb_to_yuv_table();
time_start = std::chrono::system_clock::now();
for (uint64_t i = 0; i < loop; i++) {
rgb_to_yuv_table(r, g, b, &y, &u, &v);
}
std::cout << std::to_string(y) << ", " << std::to_string(u) << " ," << std::to_string(v) << std::endl;
time_spend = std::chrono::system_clock::now() - time_start;
time_cost = time_spend.count() * 1000;
std::cout << "Table Time: " << time_cost << " ms" << std::endl;
}
测试结果:
移位操作替代乘法操作的优化实际运行结果并不一定好于乘法算法,但在移动设备上效果可能有较大提升。查表法依然最快。
reference:
YUV 格式与 RGB 格式的相互转换公式及C++ 代码
色彩转换系列之RGB格式与YUV格式互转原理及实现