文章目录
一、编码介绍
1.1 RGB 编码
RGB 图像中,每个像素点都有红、绿、蓝三个基底颜色,将 RGB 分别取不同的值,就会展示不同的颜色。标准的RGB 编码,每个基底颜色都占据 8 bit位,也就是一个字节(0-255),所以一个像素点占据了 8 * 3 = 24 bit位,也就是三个字节。例如一张 1920 * 1080大小的图片,就代表着它有 1920 * 1080 个像素点,其中每个像素点都采用 RGB 编码,那么这张图片的存储空间就是:1920 * 1080 * 3 / 1024 / 1024 = 5.93 MB 存储空间。
考虑到带宽限制,也有16bit的RGB,R和B用5bit表示,G用6bit表示(因为人眼对绿色更敏感)。常见的RGB格式有RGB888,RGB565,RGB555,RGB24,RGB32(每个分量8比特,剩余8位空着),ARGB32(每个分量8比特,Alpha通道值8bit)等。
RGB的存储格式通常为BGRBGRBGR的顺序。Bitmap就是在RGB像素数据上加上数据头形成的文件格式。
1.2 YUV 编码
在本专栏第一节 一、YUV图像基础 已经大致讲过YUV编码基础。对于 YUV 图像来说,并不是每个像素点都需要包含了 Y、U、V 三个分量,根据不同的采样格式,可以每个 Y 分量都对应自己的 UV 分量,也可以几个 Y 分量共用 UV 分量。
1.3 RGB和YUV的优缺点
-
YUV主要用于优化彩色视频信号的传输,与RGB视频信号传输相比占用极少的频宽(RGB要求三个独立的视频信号同时传输)
-
YUV的亮度信号Y和色度信号U、V是可以分离的。如果只有Y信号分量而没有U、V分量,那么这样表示的图像就是黑白灰度图像,这样就做到了对黑白电视机的兼容
二、转换公式
2.1 BT.601标准
2.1.1 Limited Range
Y=16+((66*R+129*G+25*B+128)>>8)
Cb=128+((-38*R-74*G+112*B+128)>>8)
Cr=128+((112*R-94*G-18*B+128)>>8)
RGB值要归一化到0-255区间
R=(298*(Y-16)+409*(Cr-128)+128)>>8
G=(298*(Y-16)-100*(Cb-128)-208*(Cr-128)+128)>>8
B=(298*(Y-16)+516*(Cb-128)+128)>>8
2.1.2 Full Range
Y=((77*R+150*G+29*B+128)>>8)
Cb=128+((-43*R-85*G+128*B+128)>>8)
Cr =128+((128*R-107*G-21*B+128)>>8)
RGB值要归一化到0-255区间
R=(Y+359*(Cr-128)+128)>>8
G=(Y-88*(Cb-128)+183*(Cr-128)+128)>>8
B=(Y+454*(Cb-128)+128)>>8
2.2 BT.709标准
2.2.1 Limited Range
Y=16+((47*R+157*G+16*B+128)>>8)
Cb=128+((-26*R-87*G+112*B+128)>>8)
Cr=128+((112*R-102*G-10*B+128)>>8)
RGB值要归一化到0-255区间
R=(298*(Y-16)+459*(Cr-128)+128)>>8
G=(298*(Y-16)-55*(Cb-128)-137*(Cr-128)+128)>>8
B=(298*(Y -16)+541*(Cb-128)+128)>>8
2.2.2 Full Range
Y=((55*R+183*G+19*B+128)>>8)
Cb=128+((-30*R-101*G+130*B+128)>>8)
Cr=128+((130*R-119*G-12*B+128)>>8)
RGB值要归一化到0-255区间
R=(Y +394*(Cr-128)+128)>>8
G=(Y-47*(Cb-128)-118*(Cr-128)+128)>>8
B=(Y+465*(Cb-128)+128)>>8
三、RGBA到16进制YUV值
以YUV422的YUYV格式、BT.601标准的Limited Range为例
#include <stdlib.h>
#include <stdio.h>
int main()
{
unsigned int r = 255;
unsigned int g = 0;
unsigned int b = 0;
int y, u, v;
unsigned long yuyv;
y = ((66 * r + 129 *g + 25 * b +128) >> 8) + 16;
u = ((128 - 38 * r - 74 * g + 112 * b) >> 8) + 128;
v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
yuyv = v << 24 | y << 16 | u << 8 | y;
return 0;
}