项目中碰到了YUV420 planer格式转BGR24的要求(原文中写为RGB24,但实际应为BGR),BGR格式可直接应用于opencv,发现网上涉及这方面的内容不少,但能用的代码非常少,据说最新的opencv 已经可以实现这一功能,下面的代码在项目中可用,转换成功;
标记一下,防止以后再次用到;
unsigned char clip(int valid){
return valid<0 ? 0 : valid>255 ? 255 : valid;
}
void yuv2bgr(unsigned char *rgbout,unsigned char *yuvin, int width,int height){
int x,y;
int temp=0;
unsigned long idx=0;
unsigned char *ybase,*ubase,*vbase;
unsigned char Y,U,V;
//分别得到y、u、v分量的指针;planar format
ybase=yuvin;
ubase=ybase+width*height;
vbase=ubase+(width*height)/4;
for(y=0;y<Height;y++){
idx=(Height-y-1)*Width*3;//该值保证所生成的rgb数据逆序存放在rgbbuf中
//printf("this is %dth x and index is %d!!!!!!\n",x,idx);
for(x=0;x<Width;x++){
Y=ybase[y*Width+x];
U=ubase[(y/2)*(Width/2)+x/2];//注意UV分量的取值方法,y/2的含义
V=vbase[(y/2)*(Width/2)+x/2];
temp=(int)(Y+1.771*(U - 128));
rgbout[idx++]=clip(temp);
temp=(int)(Y-0.7145*(V - 128)-0.3456*(U - 128));
rgbout[idx++]=clip(temp);
temp=(int)(Y+ 1.4022*(V - 128));
rgbout[idx++]=clip(temp);
}
}
}
int writebmp(char *filename,unsigned char *rgbbuf,int width,int height){
BITMAPFILEHEADER bmpHeader;
BITMAPINFOHEADER bmpInfo;
int linebyte=width*3;//(width*3+3)/4*4;
int rgb_size=linebyte*height;
int count;
unsigned long k=0;
FILE *bmpfp;
memset(&bmpHeader,0,sizeof(BITMAPFILEHEADER));
memset(&bmpInfo,0,sizeof(BITMAPINFOHEADER));
bmpHeader.bfType=0x4D42;//"MB"
bmpHeader.bfSize=rgb_size+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
bmpHeader.bfReserved1=0;
bmpHeader.bfReserved2=0;
bmpHeader.bfOffBits=54;//sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFODEADER);
bmpInfo.biSize=sizeof(BITMAPINFOHEADER);
bmpInfo.biWidth=width;
bmpInfo.biHeight=height;
bmpInfo.biPlanes=1;
bmpInfo.biBitCount=24;
bmpInfo.biCompression=BI_RGB;
bmpInfo.biSizeImage=rgb_size;
bmpInfo.biXPelsPerMeter=0;
bmpInfo.biYPelsPerMeter=0;
bmpInfo.biClrUsed=0;
bmpInfo.biClrImportant=0;
bmpfp=fopen(filename,"wb");
if(bmpfp==NULL){
printf("Failed to open file %s\n",filename);
return -1;
}
count=fwrite(&bmpHeader,sizeof(BITMAPFILEHEADER),1,bmpfp);
if(count!=1){
printf("Failed to write bmpheader to file the count is %d\n",count);
return -1;
}
count=fwrite(&bmpInfo,sizeof(BITMAPINFOHEADER),1,bmpfp);
if(count!=1){
printf("Failed to write bmpinfo to file the count is %d %d\n",count,sizeof(BITMAPINFOHEADER));
fclose(bmpfp);
return -1;
}
count=fwrite(rgbbuf,1,rgb_size,bmpfp);
if(count!=rgb_size){
printf("Failed to write rgbbuf to file the count is %d\n",count);
fclose(bmpfp);
return -1;
}
fclose(bmpfp);
return 1;
}
int main(){
int i;
FILE *file_in;
int yuvsize=Width*Height*3/2;
int count;
unsigned char *yuvbuf;
unsigned char *rgbbuf;
char bmpfilename[]="first.bmp";
file_in=fopen("D:\\work\\yuv2rgb\\foreman_cif.yuv","rb");
if(file_in==NULL){
printf("failed to open file\n");
return;
}
yuvbuf=(unsigned char*)malloc(yuvsize);
rgbbuf=(unsigned char*)malloc(Width*Height*3);
memset(yuvbuf,0,yuvsize);
memset(rgbbuf,0,Width*Height*3);
if(yuvbuf==NULL){
printf("failed to malloc the yuv buffer\n");
return;
}
if(rgbbuf==NULL){
printf("failed to malloc the rgb buffer\n");
return;
}
fseek(file_in,0, SEEK_CUR);//移动文件指针的位置
count=fread(yuvbuf,yuvsize,1,file_in);
if(count!=1){
printf("failed to read yuv data!\n");
return;
}
fclose(file_in);
for(i=0;i<1;i++){
printf("Frame number is %d\n",i);
yuv2rgb(rgbbuf,yuvbuf,Width,Height);
if(writebmp(bmpfilename,rgbbuf,Width,Height)==1)
printf("Success to generate a bmp file\n");
}
free(yuvbuf);
free(rgbbuf);
}
转自:http://yumingfu.blog.163.com/blog/static/17507717720126307641853/