与我们熟知的RGB类似,YUV也是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题。
并且,YUV不像RGB那样要求三个独立的视频信号同时传输,所以用YUV方式传送占用极少的频宽
1、RGB---->YUV转换
// BmptoYuv420.cpp : Defines the entry point for the console application. // #include "stdafx.h" // 说明:下面的代码用C\C++执行都可以,用C的时候请把#include<iostream> 删除。 // 代码的详细说明视频即将推出,请时刻关注我的Blog: http://hexun.com/ctfysj // // RGB to YUV420 原代码: RGB2YUV.CPP文件 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> //转换矩阵 #define MY(a,b,c) (( a* 0.2989 + b* 0.5866 + c* 0.1145)) #define MU(a,b,c) (( a*(-0.1688) + b*(-0.3312) + c* 0.5000 + 128)) #define MV(a,b,c) (( a* 0.5000 + b*(-0.4184) + c*(-0.0816) + 128)) //大小判断 #define DY(a,b,c) (MY(a,b,c) > 255 ? 255 : (MY(a,b,c) < 0 ? 0 : MY(a,b,c))) #define DU(a,b,c) (MU(a,b,c) > 255 ? 255 : (MU(a,b,c) < 0 ? 0 : MU(a,b,c))) #define DV(a,b,c) (MV(a,b,c) > 255 ? 255 : (MV(a,b,c) < 0 ? 0 : MV(a,b,c))) //只处理352*288文件 #define WIDTH /*352*/320 #define HEIGHT /*288*/240 //读BMP void ReadBmp(unsigned char *RGB,FILE *fp); //转换函数 void Convert(unsigned char *RGB, unsigned char *YUV); //入口 int main() { int i=1; char file[255]; FILE *fp; FILE *fp2; unsigned char *YUV = NULL; unsigned char *RGB = NULL; unsigned int imgSize = WIDTH*HEIGHT; if((fp2 = fopen("test.cif", "wb")) == NULL)//生成文件名 { return 0; } RGB = (unsigned char*)malloc(imgSize*6); YUV = (unsigned char*)malloc(imgSize + (imgSize>>1)); for(i=1; i<2; i++) { sprintf(file, "test.bmp", i);//读取文件 if((fp = fopen(file, "rb")) == NULL) continue; printf("打开文件%s\n", file); ReadBmp(RGB, fp); Convert(RGB, YUV); fwrite(YUV, 1, imgSize+(imgSize>>1), fp2);//写入文件 fclose(fp); } fclose(fp2); if(RGB) free(RGB); if(YUV) free(YUV); printf("完成\n"); system("pause"); return 1; } //读BMP void ReadBmp(unsigned char *RGB,FILE *fp) { int i,j; unsigned char temp; fseek(fp,54, SEEK_SET); fread(RGB+WIDTH*HEIGHT*3, 1, WIDTH*HEIGHT*3, fp);//读取 for(i=HEIGHT-1,j=0; i>=0; i--,j++)//调整顺序 { memcpy(RGB+j*WIDTH*3,RGB+WIDTH*HEIGHT*3+i*WIDTH*3,WIDTH*3); } //顺序调整 for(i=0; (unsigned int)i < WIDTH*HEIGHT*3; i+=3) { temp = RGB[i]; RGB[i] = RGB[i+2]; RGB[i+2] = temp; } } void Convert(unsigned char *RGB, unsigned char *YUV) { //变量声明 unsigned int i,x,y,j; unsigned char *Y = NULL; unsigned char *U = NULL; unsigned char *V = NULL; Y = YUV; U = YUV + WIDTH*HEIGHT; V = U + ((WIDTH*HEIGHT)>>2); for(y=0; y < HEIGHT; y++) for(x=0; x < WIDTH; x++) { j = y*WIDTH + x; i = j*3; Y[j] = (unsigned char)(DY(RGB[i], RGB[i+1], RGB[i+2])); if(x%2 == 1 && y%2 == 1) { j = (WIDTH>>1) * (y>>1) + (x>>1); //上面i仍有效 U[j] = (unsigned char) ((DU(RGB[i ], RGB[i+1], RGB[i+2]) + DU(RGB[i-3], RGB[i-2], RGB[i-1]) + DU(RGB[i -WIDTH*3], RGB[i+1-WIDTH*3], RGB[i+2-WIDTH*3]) + DU(RGB[i-3-WIDTH*3], RGB[i-2-WIDTH*3], RGB[i-1-WIDTH*3]))/4); V[j] = (unsigned char) ((DV(RGB[i ], RGB[i+1], RGB[i+2]) + DV(RGB[i-3], RGB[i-2], RGB[i-1]) + DV(RGB[i -WIDTH*3], RGB[i+1-WIDTH*3], RGB[i+2-WIDTH*3]) + DV(RGB[i-3-WIDTH*3], RGB[i-2-WIDTH*3], RGB[i-1-WIDTH*3]))/4); } } }
说明:生成一个YUV格式的文件,此处取名为:test.cif
2、YUV---->RGB转换(把test.cif转换成bmp图片)
// YuvtoRgb.cpp : Defines the entry point for the console application. // #include "stdafx.h" // // int main(int argc, char* argv[]) // { // return 0; // } #include <stdio.h> #include <stdlib.h> #include <iostream> #define WIDTH /*352*/320 #define HEIGHT /*288*/240 //转换矩阵 double YuvToRgb[3][3] = {1, 0, 1.4022, 1, -0.3456, -0.7145, 1, 1.771, 0}; //根据RGB三分量写BMP,不必关注 int WriteBmp(int width, int height, unsigned char *R,unsigned char *G,unsigned char *B, char *BmpFileName); //转换函数 int Convert(char *file, int width, int height, int n) { //变量声明 int i = 0; int temp = 0; int x = 0; int y = 0; int fReadSize = 0; int ImgSize = width*height; FILE *fp = NULL; unsigned char* yuv = NULL; unsigned char* rgb = NULL; unsigned char* cTemp[6]; char BmpFileName[256]; //申请空间 int FrameSize = ImgSize + (ImgSize >> 1); yuv = (unsigned char *)malloc(FrameSize); rgb = (unsigned char *)malloc(ImgSize*3); //读取指定文件中的指定帧 if((fp = fopen(file, "rb")) == NULL) return 0; fseek(fp, FrameSize*(n-1), SEEK_CUR); fReadSize = fread(yuv, 1, FrameSize, fp); fclose(fp); if(fReadSize < FrameSize) return 0; //转换指定帧 如果你不是处理文件 主要看这里 cTemp[0] = yuv; //y分量地址 cTemp[1] = yuv + ImgSize; //u分量地址 cTemp[2] = cTemp[1] + (ImgSize>>2); //v分量地址 cTemp[3] = rgb; //r分量地址 cTemp[4] = rgb + ImgSize; //g分量地址 cTemp[5] = cTemp[4] + ImgSize; //b分量地址 for(y=0; y < height; y++) for(x=0; x < width; x++) { //r分量 temp = cTemp[0][y*width+x] + (cTemp[2][(y/2)*(width/2)+x/2]-128) * YuvToRgb[0][2]; cTemp[3][y*width+x] = temp<0 ? 0 : (temp>255 ? 255 : temp); //g分量 temp = cTemp[0][y*width+x] + (cTemp[1][(y/2)*(width/2)+x/2]-128) * YuvToRgb[1][1] + (cTemp[2][(y/2)*(width/2)+x/2]-128) * YuvToRgb[1][2]; cTemp[4][y*width+x] = temp<0 ? 0 : (temp>255 ? 255 : temp); //b分量 temp = cTemp[0][y*width+x] + (cTemp[1][(y/2)*(width/2)+x/2]-128) * YuvToRgb[2][1]; cTemp[5][y*width+x] = temp<0 ? 0 : (temp>255 ? 255 : temp); } //写到BMP文件中 sprintf(BmpFileName, "test.bmp", file, n); WriteBmp(width, height, cTemp[3], cTemp[4], cTemp[5], BmpFileName); free(yuv); free(rgb); return n; } //入口 没啥东西 void main() { int i=1; // for( i=0; i<260; i++) Convert("test.cif", WIDTH, HEIGHT, i);//调用上面的Convert,获取文件的第i帧 } //写BMP 不必关注 int WriteBmp(int width, int height, unsigned char *R,unsigned char *G,unsigned char *B, char *BmpFileName) { int x=0; int y=0; int i=0; int j=0; FILE *fp; unsigned char *WRGB; unsigned char *WRGB_Start; int yu = width*3%4; int BytePerLine = 0; yu = yu!=0 ? 4-yu : yu; BytePerLine = width*3+yu; if((fp = fopen(BmpFileName, "wb")) == NULL) return 0; WRGB = (unsigned char*)malloc(BytePerLine*height+54); memset(WRGB, 0, BytePerLine*height+54); //BMP头 WRGB[0] = 'B'; WRGB[1] = 'M'; *((unsigned int*)(WRGB+2)) = BytePerLine*height+54; *((unsigned int*)(WRGB+10)) = 54; *((unsigned int*)(WRGB+14)) = 40; *((unsigned int*)(WRGB+18)) = width; *((unsigned int*)(WRGB+22)) = height; *((unsigned short*)(WRGB+26)) = 1; *((unsigned short*)(WRGB+28)) = 24; *((unsigned short*)(WRGB+34)) = BytePerLine*height; WRGB_Start = WRGB + 54; for(y=height-1,j=0; y >= 0; y--,j++) { for(x=0,i=0; x<width; x++) { WRGB_Start[y*BytePerLine+i++] = B[j*width+x]; WRGB_Start[y*BytePerLine+i++] = G[j*width+x]; WRGB_Start[y*BytePerLine+i++] = R[j*width+x]; } } fwrite(WRGB, 1, BytePerLine*height+54, fp); free(WRGB); fclose(fp); return 1; }