<Excerpt in index | 首页摘要>
RGB的一些基础知识
<The rest of contents | 余下全文>
前提 最近在看FFMPEG的东西,发现很多内容由于没有相关基础知识支撑 导致看得人云里雾里的。
所以决定先好好学习学习基础理论知识。
昨天学习YUV博文地址
今天学习RGB
什么是RGB RGB描述一个像素点的颜色值是利用Red、Green、Blue值来描述(3原色)
1 2 3 4 5 6 7 8 9 10 计算机彩色显示器显示色彩的原理与彩色电视机一样, 都是采用R(Red)、G(Green)、B(Blue)相加混色的原理: 通过发射出三种不同强度的电子束,使屏幕内侧覆盖的红、绿、蓝磷光材料发光而产生色彩。 这种色彩的表示方法称为RGB色彩空间表示(它也是多媒体计算机技术中用得最多的一种色彩空间表示方法)。 根据三基色原理,任意一种色光F都可以用不同分量的R、G、B三色相加混合而成
RGB的处理 让我们直接上代码看看吧
本文中RGB一律采用的24位的不带A通道(Alpha)即1个byte占一位 RGB文件的播放器就是上篇文章的YUV播放器 分离RGB24像素数据中的R、G、B 先看一下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <stdio.h> #include <stdlib.h> void rgb24_split(int w, int h, int num){ FILE *fp = fopen("../source/RGB_24bit_500x500.rgb","rb+"); FILE *fp1 = fopen("../source/RGB_24bit_500x500_r.y","wb+"); FILE *fp2 = fopen("../source/RGB_24bit_500x500_g.y","wb+"); FILE *fp3 = fopen("../source/RGB_24bit_500x500_b.y","wb+"); unsigned char *pic=(unsigned char *)malloc(w*h*3); for(int i = 0; i < num; i ++){ fread(pic, 1, w * h * 3, fp); for(int j = 0; j < w * h * 3; j+=3){ fwrite(pic + j, 1, 1, fp1);//R fwrite(pic + j + 1, 1, 1, fp2);//G fwrite(pic + j + 2, 1, 1, fp3);//B } } free(pic); fclose(fp3); fclose(fp2); fclose(fp1); fclose(fp); } int main(){ rgb24_split(500, 500, 1); return 0; }
RGB文件的大小就是宽度x高度x3
跑起来之后让我们看一下对比图(顺序依次为:原图、R、G、B):
注意播放后三个视频的时候,像素格式选择为RGB24,分辨率大小是500x500
通过RGB文件创建BMP文件 BMP是无损图片的格式,它就是一个在RGB的描述基础之上加了一些头文件。
先看看代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 #include <stdio.h> #include <stdlib.h> typedef struct { long imageSize; long blank; long startPosition; } BmpHead; typedef struct { long Length; long width; long height; unsigned short colorPlane; unsigned short bitColor; long zipFormat; long realSize; long xPels; long yPels; long colorUse; long colorImportant; } InfoHead; void rgb24_2_bmp(int width, int height){ int i=0,j=0; BmpHead m_BMPHeader={0}; InfoHead m_BMPInfoHeader={0}; char bfType[2]={'B','M'}; int header_size = sizeof(bfType) + sizeof(BmpHead) + sizeof(InfoHead); unsigned char *rgb24_buffer = NULL; FILE *fp_rgb24=NULL,*fp_bmp=NULL; fp_rgb24 = fopen("../source/RGB_24bit_500x500.rgb","rb"); fp_bmp = fopen("../source/RGB_24bit_500x500.bmp","wb"); rgb24_buffer = (unsigned char *)malloc(width * height * 3); fread(rgb24_buffer, 1, width * height * 3, fp_rgb24); //拼装头部的信息数据 m_BMPHeader.imageSize=3*width*height+header_size; m_BMPHeader.startPosition=header_size; m_BMPInfoHeader.Length=sizeof(InfoHead); m_BMPInfoHeader.width=width; //说明图象的高度,以象素为单位。 //注:这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图。 //如果该值是一个正数,说明图像是倒向的, //即:数据的第一行其实是图像的最后一行,如果该值是一个负数,则说明图像是正向的。 //大多数的BMP文件都是倒向的位图,也就是时,高度值是一个正数。 //我们这里是正图,所以需要要用取反 m_BMPInfoHeader.height=-height; m_BMPInfoHeader.colorPlane=1; m_BMPInfoHeader.bitColor=24; m_BMPInfoHeader.realSize=3*width*height; //写出保存 fwrite(bfType, 1, sizeof(bfType), fp_bmp); fwrite(&m_BMPHeader, 1, sizeof(m_BMPHeader), fp_bmp); fwrite(&m_BMPInfoHeader, 1, sizeof(m_BMPInfoHeader), fp_bmp); for(j =0;j<height;j++){ for(i=0;i<width;i++){ char temp=rgb24_buffer[(j*width+i)*3+2]; rgb24_buffer[(j*width+i)*3+2]=rgb24_buffer[(j*width+i)*3+0]; rgb24_buffer[(j*width+i)*3+0]=temp; } } //写出保存 fwrite(rgb24_buffer, 3 * width * height, 1,fp_bmp); free(rgb24_buffer); fclose(fp_bmp); fclose(fp_rgb24); } int main(){ rgb24_2_bmp(500, 500); return 0; }
然后先来看看效果图
说一些BMP对像素点的描述是B、G、R的顺序,所以需要颠倒一下。
BMP的文件编码格式具体的可以去看看这里
BMP编码格式
RGB24->YUV420P 还是先看代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 #include <stdio.h> #include <stdlib.h> unsigned char clip_value(unsigned char x,unsigned char min_val,unsigned char max_val){ if(x > max_val){ return max_val; }else if(x<min_val){ return min_val; }else{ return x; } } void rgb_2_yuv420(int width, int height, int num){ FILE *fp_rgb = fopen("../source/RGB_24bit_500x500.rgb","rb"); FILE *fp_yuv = fopen("../source/RGB_24bit_500x500.yuv","wb"); unsigned char *pic_rgb24 = (unsigned char *)malloc(width * height * 3); unsigned char *pic_yuv420 = (unsigned char *)malloc(width * height * 3 / 2); for(int i=0;i<num;i++){ fread(pic_rgb24, 1, width * height * 3, fp_rgb); unsigned char*ptrY, *ptrU, *ptrV, *ptrRGB; for(int j = 0; j < width * height * 3 / 2; j++){ pic_yuv420[j] = 0; } ptrY = pic_yuv420; ptrU = pic_yuv420 + width * height; ptrV = ptrU + (width * height * 1 / 4); unsigned char y, u, v, r, g, b; for (int k = 0; k < height ; k++){ ptrRGB = pic_rgb24 + width * k * 3 ; for (int l = 0; l < width; l++){ 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 (k % 2 == 0 && l % 2 == 0){ *(ptrU++) = clip_value(u, 0, 255); } else{ if (l % 2 == 0){ *(ptrV++) = clip_value(v, 0, 255); } } } } fwrite(pic_yuv420, 1, width * height * 3 / 2, fp_yuv); } free(pic_rgb24); free(pic_yuv420); fclose(fp_yuv); fclose(fp_rgb); } int main(){ rgb_2_yuv420(500, 500, 1);//宽、高、帧数 return 0; }
预览图:
转换公式是:
1 2 3 4 5 Y= 0.299*R+0.587*G+0.114*B U=-0.147*R-0.289*G+0.463*B V= 0.615*R-0.515*G-0.100*B
U,V在水平和垂直方向的取样数是Y的一半
生成RGB24格式的彩条测试图 这个就太简单了看看代码就好了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 #include <stdio.h> #include <stdlib.h> void create_rgb(int width, int height){ unsigned char *data = (unsigned char *)malloc(width*height*3); int barwidth= width / 8; FILE *fp = fopen("../source/rgb_test.rgb", "wb"); for(int j=0;j<height;j++){ for(int i=0;i<width;i++){ int barnum=i/barwidth; switch(barnum){ case 0:{ data[(j*width+i)*3+0]=255; data[(j*width+i)*3+1]=255; data[(j*width+i)*3+2]=255; break; } case 1:{ data[(j*width+i)*3+0]=255; data[(j*width+i)*3+1]=255; data[(j*width+i)*3+2]=0; break; } case 2:{ data[(j*width+i)*3+0]=0; data[(j*width+i)*3+1]=255; data[(j*width+i)*3+2]=255; break; } case 3:{ data[(j*width+i)*3+0]=0; data[(j*width+i)*3+1]=255; data[(j*width+i)*3+2]=0; break; } case 4:{ data[(j*width+i)*3+0]=255; data[(j*width+i)*3+1]=0; data[(j*width+i)*3+2]=255; break; } case 5:{ data[(j*width+i)*3+0]=255; data[(j*width+i)*3+1]=0; data[(j*width+i)*3+2]=0; break; } case 6:{ data[(j*width+i)*3+0]=0; data[(j*width+i)*3+1]=0; data[(j*width+i)*3+2]=255; break; } case 7:{ data[(j*width+i)*3+0]=0; data[(j*width+i)*3+1]=0; data[(j*width+i)*3+2]=0; break; } } } } fwrite(data,width*height*3,1,fp); free(data); fclose(fp); } int main(){ create_rgb(500, 500); return 0; }
效果图:
源码下载 ok,RGB的学习就到这里为止。
Github下载