RGB格式
RGB,其实就是R(red:红色)+G(green:绿色)+B(blue:蓝色);像彩色电视或者计算机显示屏都是通过这三种颜色按照不同比例混合叠加而构成图像而显示的。红色、绿色和蓝色又称为三基色。之所以称为‘基色’是因为这三种颜色按照不同比例混合后几乎可以变成人类示例所能感知的所有颜色。
RGB555、RGB565、RGB24(RGB888)和RGB32
RGB555(高彩色)
RGB555是一种16位的RGB格式,R、G、B分量都用5位来表示,剩下的一位不用,存储格式如下图:
假设计算机中存储某一个像素点的变量为color, 数据类型为short.,那么则有:
R = color & 0x7C00, (获取高字节的5个bit)
G = color & 0x03E0, (获取中间5个bit)
B = color & 0x001F, (获取低字节5个bit)
RGB565
RGB565同样是一种16位的RGB格式,R和B分量用5位来表示,G分量用6位标志。存储格式如下图:
假设计算机中存储某一个像素点的变量为color, 数据类型为short, 那么则有:
R = color & 0xF800, (获取高字节的5个bit)
G = color & 0x07E0, (获取中间6个bit)
B = color & 0x001F, (获取低字节5个bit)
RGB24(真彩色)
RGB24是一种24位的RGB格式,R、G、B分量都用8位来表示,每位取值范围都为0-255。存储格式如下图:
假设计算机中存储某一个像素点的变量为color, 数据类型为int, 那么则有:
R = color & 0x000000FF,
G = color & 0x0000FF00,
B = color & 0x00FF0000,
RGB32(真彩色)
RGB32使用32位来表示一个像素,RGB分量各用去8位,剩下的8位用作Alpha通道或者不用。Alpha通道是一个8位的灰度通道,该通道用256级灰度来记录图像中的透明度信息,定义透明、不透明和半透明区域,其中白表示不透明,黑表示透明,灰表示半透明。其结构如下:
假设计算机中存储某一个像素点的变量为color, 数据类型为int,那么则有:
a、低8位保留
R = color & 0x0000FF00
G = color & 0x00FF0000,
B = color & 0xFF000000,
b、低8位为ALPHA值
R = color & 0x0000FF00,
G = color & 0x00FF0000,
B = color & 0xFF000000,
A = color & 0x000000FF,
RGB数据常见处理
(8) 分离RGB24像素数据中的R、G、B分量
与YUV420P三个分量分开存储不同,RGB24格式的每个像素的三个分量是连续存储的。一帧宽高分别为w、h的RGB24图像一共占用wh3 Byte的存储空间。RGB24格式规定首先存储第一个像素的R、G、B,然后存储第二个像素的R、G、B…以此类推。类似于YUV420P的存储方式称为Planar方式,而类似于RGB24的存储方式称为Packed方式。
思路
RGB24是8,8,8,一个像素3个字节,按BBBBBBBB GGGGGGGG RRRRRRRR 排列的 属于Packet格式。
读取3wh, 3个字节一读取,然后分别写在三个分别存储 R,G,B的文件里。最后用yuvplayer设置500*500分别打开r,g,b文件 会发现
原图
R数据图像如下所示。
G数据图像如下所示。
B数据图像如下所示。
(9) 将RGB24格式像素数据封装为BMP图像
BMP文件组成 |
BITMAP_FILE_HEADER |
BITMAP_INFO_HEADER |
RGB像素数据 |
typedef struct tagBITMAPFILEHEADER { unsigned short int bfType; //位图文件的类型,必须为BM unsigned long bfSize; //文件大小,以字节为单位 unsigned short int bfReserverd1; //位图文件保留字,必须为0 unsigned short int bfReserverd2; //位图文件保留字,必须为0 unsigned long bfbfOffBits; //位图文件头到数据的偏移量,以字节为单位 }BITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER { long biSize; //该结构大小,字节为单位 long biWidth; //图形宽度以象素为单位 long biHeight; //图形高度以象素为单位 short int biPlanes; //目标设备的级别,必须为1 short int biBitcount; //颜色深度,每个象素所需要的位数 short int biCompression; //位图的压缩类型 long biSizeImage; //位图的大小,以字节为单位 long biXPelsPermeter; //位图水平分辨率,每米像素数 long biYPelsPermeter; //位图垂直分辨率,每米像素数 long biClrUsed; //位图实际使用的颜色表中的颜色数 long biClrImportant; //位图显示过程中重要的颜色数 }BITMAPINFOHEADER;
BMP采用的是小端(Little Endian)存储方式。
这种存储方式中“RGB24”格式的像素的分量存储的先后顺序为B、G、R。由于RGB24格式存储的顺序是R、G、B,所以需要将“R”和“B”顺序作一个调换再进行存储。
思路
- 将RGB数据前面加上文件头
- 将RGB数据中每个像素的“B”和“R”的位置互换。
(10) 将RGB24格式像素数据转换为YUV420P格式像素数据
思路
RGB24是packet格式(连续rgb rgb),yuv420p是planar格式(平面分块yyyy uu v)。故需要连续读写3字节RGB 根据公式算出yuv之后然后分别存y,u,v。
RGB到YUV的转换公式:
Y= 0.299R+0.587G+0.114B
U=-0.147R-0.289G+0.463BV= 0.615R-0.515G-0.100*B
//RGB to YUV420 bool RGB24_TO_YUV420(unsigned char *RgbBuf,int w,int h,unsigned char *yuvBuf) { unsigned char*ptrY, *ptrU, *ptrV, *ptrRGB; memset(yuvBuf,0,w*h*3/2); ptrY = yuvBuf; ptrU = yuvBuf + w*h; ptrV = ptrU + (w*h*1/4); unsigned char y, u, v, r, g, b; for (int j = 0; j<h;j++){ ptrRGB = RgbBuf + w*j*3 ; for (int i = 0;i<w;i++){ r = *(ptrRGB++); g = *(ptrRGB++); b = *(ptrRGB++); y = (unsigned char)( ( 66 * r + 129 * g + 25 * b + 128) >> 8) + 16 ; u = (unsigned char)( ( -38 * r - 74 * g + 112 * b + 128) >> 8) + 128 ; v = (unsigned char)( ( 112 * r - 94 * g - 18 * b + 128) >> 8) + 128 ; *(ptrY++) = clip_value(y,0,255); if (j%2==0&&i%2 ==0){ *(ptrU++) =clip_value(u,0,255); } else{ if (i%2==0){ *(ptrV++) =clip_value(v,0,255); } } } } return true; }
以上是雷神的转换代码,指出其中
y = (unsigned char)( ( 66 * r + 129 * g + 25 * b + 128) >> 8) + 16 ; u = (unsigned char)( ( -38 * r - 74 * g + 112 * b + 128) >> 8) + 128 ; v = (unsigned char)( ( 112 * r - 94 * g - 18 * b + 128) >> 8) + 128 ;
是为了减少浮点运算 从而优化运算时间
以下代码是减少浮点和乘法运算
转自 图像处理-RGB24转YUV420遇到的坑以及执行效率对比
/**********************不包含浮点和乘法运算*****************/ #define RGB2Y_SHIFT(r,g,b) \ ((unsigned char)((((r << 6) + (r << 3) + (r << 2) + r + (g << 7) + (g << 4) + (g << 2) + (g << 1) + (b << 4) + (b << 3) + (b << 2) + b) + 128) >> 8) + 16) #define RGB2U_SHIFT(r,g,b) \ ((unsigned char)(((-((r << 5) + (r << 2) + (r << 1)) - ((g << 6) + (g << 3) + (g << 1)) + ((b << 6) + (b << 5) + (b << 4))) + 128) >> 8) + 128) #define RGB2V_SHIFT(r,g,b) \ ((unsigned char)(((r << 7) + (r << 4) + (r << 3) + (r << 2) + (r << 1) - ((g << 7) + (g << 2)) - ((b << 4) + (b << 3) + (b << 1)) + 128) >> 8) + 128)
(11) 生成RGB24格式的彩条测试图
颜色 | (R,G,B) |
白 | (255, 255, 255) |
黄 | (255, 255, 0) |
青 | ( 0, 255, 255) |
绿 | ( 0, 255, 0) |
品 | (255, 0, 255) |
红 | (255, 0, 0) |
蓝 | ( 0, 0, 255) |
黑 | ( 0, 0, 0) |
思路
分为8条色带,area = width /8 为一个区域,按如上表设置rgb值
[0, area]为白色 [area,area*2]为黄色 [area*2,area*3]为青色 [area*3,area*4]为绿色 [area*4,area*5]为品色 [area*5,area*6]为红色 [area*6,area*7]为蓝色 [area*7,area*8]为黑色
RGB和YUV转换
关于RGB与YUV之间的转换,有如下一条矩阵公式:
1)、YUV(256 级别) 可以从8位 RGB 直接计算:
Y = 0.299 R + 0.587 G + 0.114 B
U = - 0.1687 R - 0.3313 G + 0.5 B + 128
V = 0.5 R - 0.4187 G - 0.0813 B + 128
2)、反过来,RGB 也可以直接从YUV (256级别) 计算:
R = Y + 1.402 (Cr-128)
G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
B = Y + 1.772 (Cb-128)
注意:浮点数和乘法会比较耗时 转化为定点运算会比较快