1、读取akiyo_qcif.yuv YUV420文件,按帧读取,转RGB,并存储到BMP文件。2、暂时实现读取一帧并存储一张BMP图片。 若要读取YUV序列,写成循环方式即可。3、生成的BMP文件还有一点小问题:图像的倒立的,而且红色偏多。
YUV是qcif分辨率。
估计是YUV到RGB的计算公式有点问题。解决中。。。。
图像倒立问题已经解决。红色不知道是不是公式变换和RGB数值区间限制的时候产生的。估计和UV的差值方式也有关系。
红色的问题已经解决,采用的变换公式不正确。 但是还是有一些横纹,不知道是怎么回事。 头文件Ex1.h
typedef unsigned char BYTE;typedef unsigned short WORD;typedef unsigned int DWORD;typedef long LONG;
//位图文件头定义;//其中不包含文件类型信息(由于结构体的内存结构决定,//要是加了的话将不能正确读取文件信息)typedef struct tagBITMAPFILEHEADER{// WORD bfType;//文件类型,必须是0x424D,即字符“BM” DWORD bfSize;//文件大小 WORD bfReserved1;//保留字 WORD bfReserved2;//保留字 DWORD bfOffBits;//从文件头到实际位图数据的偏移字节数}BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER{ DWORD biSize;//信息头大小 LONG biWidth;//图像宽度 LONG biHeight;//图像高度 WORD biPlanes;//位平面数,必须为1 WORD biBitCount;//每像素位数 DWORD biCompression; //压缩类型 DWORD biSizeImage; //压缩图像大小字节数 LONG biXPelsPerMeter; //水平分辨率 LONG biYPelsPerMeter; //垂直分辨率 DWORD biClrUsed; //位图实际用到的色彩数 DWORD biClrImportant; //本位图中重要的色彩数}BITMAPINFOHEADER; //位图信息头定义
typedef struct tagRGBQUAD{ BYTE rgbBlue; //该颜色的蓝色分量 BYTE rgbGreen; //该颜色的绿色分量 BYTE rgbRed; //该颜色的红色分量 BYTE rgbReserved; //保留值}RGBQUAD;//调色板定义
//像素信息typedef struct tagIMAGEDATA{ BYTE blue;///8位灰度图用其中1个 BYTE green; BYTE red;}IMAGEDATA;
源文件Ex1.cpp
#include "stdafx.h"#include "Ex1.h"#include <stdio.h>#include <math.h>#include <stdlib.h>#include <iostream.h>
#define qcif
#ifdef qcif
#define Y_WIDTH 176#define Y_HEIGHT 144
#define U_WIDTH 88#define U_HEIGHT 72
#define V_WIDTH 88#define V_HEIGHT 72
#endif
//变量定义BITMAPFILEHEADER strHead; //位图文件头BITMAPINFOHEADER strInfo; //位图信息头
unsigned char Y_space[Y_WIDTH*Y_HEIGHT];unsigned char U_space[U_WIDTH*U_HEIGHT];unsigned char V_space[V_WIDTH*V_HEIGHT];
unsigned char R_space[Y_WIDTH*Y_HEIGHT];unsigned char G_space[Y_WIDTH*Y_HEIGHT];unsigned char B_space[Y_WIDTH*Y_HEIGHT];
void ReadImage(unsigned char *pImage,char *cFileName,int nWidth,int nHeight,long offset);////读取YUV文件
int main(int argc, char* argv[]){ long origin=0+Y_WIDTH*Y_HEIGHT+U_WIDTH*U_HEIGHT+V_WIDTH*V_HEIGHT;///YUV文件起始位置 int i,j,u_j,v_j; int width,height; width=Y_WIDTH; height=Y_HEIGHT;
FILE *fpw; WORD bfType_w=0x4d42; IMAGEDATA *imagedata = NULL; //动态分配存储BMP图片的像素信息的二维数组 imagedata = (IMAGEDATA*)malloc(width*height* sizeof(IMAGEDATA)); //按IMAGEDATA结构体大小,分配存储BMP图片的存储空间
//初始化原始图片的像素数组 for( i = 0;i < height;++i) { for(int j = 0;j <width;++j) { (*(imagedata + i * width + j)).blue = 0; (*(imagedata + i * width + j)).green = 0; (*(imagedata + i * width + j)).red = 0; } } // origin=0;///读第一帧// for(i=0,origin=0;i<148;i++,origin+=(Y_WIDTH*Y_HEIGHT+U_WIDTH*U_HEIGHT+V_WIDTH*V_HEIGHT))// {///读取第一帧图像 ReadImage(Y_space,"akiyo_qcif.yuv",Y_WIDTH,Y_HEIGHT,origin);//carphone001.yuv ReadImage(V_space,"akiyo_qcif.yuv",V_WIDTH,V_HEIGHT,Y_WIDTH*Y_HEIGHT);///读取方法涉及YUV的存储顺序。 存储顺序是所有Y,随后是所有V,最后是所有U。 ReadImage(U_space,"akiyo_qcif.yuv",U_WIDTH,U_HEIGHT,Y_WIDTH*Y_HEIGHT+V_WIDTH*V_HEIGHT);// }
///YUV转成RGB 176*144 88*72 width * height u_j=0;v_j=0;
int y,cb,cr;//y u v int r,g,b;
for(i = 0; i <Y_HEIGHT; i++) { for(j = 0; j <Y_WIDTH; j++) { u_j=j/2;///取倍数 v_j=j/2;///取倍数,U和V的宽度是Y的一半。 /////对应4:2:0 YUV 采样方式 参考文章:http://blog.youkuaiyun.com/shallon_luo/article/details/5544796 y = Y_space[j+i*Y_WIDTH]; cb = U_space[u_j+i*U_WIDTH]; cr = V_space[v_j+i*V_WIDTH]; /* R = Y + 1.14V,G = Y - 0.39U - 0.58V,B = Y + 2.03U YUV对应YCbCr r = y + 1.14*cr; g = y - 0.39*cb - 0.58*cr; b = y + 2.03*cb; */
/* YCbCr与RGB的关系 */ r = 1.164*(y-16) + 1.596*(cr-128); g = 1.164*(y-16) - 0.813*(cr-128) - 0.392*(cb-128); b = 1.164*(y-16) + 2.017*(cb-128);
/* r=1.0*y+1.402*(cr-128) ; g=1.0*y-0.34413*(cb-128)-0.71414*(cr-128); b=1.0*y+1.772*(cb-128);*/
r = r > 255 ? 255 : r; g = g > 255 ? 255 : g; b = b > 255 ? 255 : b;
r = r < 0 ? 0 : r; g = g < 0 ? 0 : g; b = b < 0 ? 0 : b;
B_space[j+i*Y_WIDTH] = b; G_space[j+i*Y_WIDTH] = g; R_space[j+i*Y_WIDTH] = r; } }
for(i =0;i<Y_HEIGHT;++i) { for(int j = 0;j < Y_WIDTH;++j) { (*(imagedata + i * Y_WIDTH + j)).blue=B_space[j+i*Y_WIDTH]; (*(imagedata + i * Y_WIDTH + j)).green=G_space[j+i*Y_WIDTH]; (*(imagedata + i * Y_WIDTH + j)).red=R_space[j+i*Y_WIDTH]; } } ///保存BMP图像 if((fpw=fopen("result033.bmp","wb"))==NULL) { cout<<"create the bmp file error!"<<endl; return NULL; } fwrite(&bfType_w,1,sizeof(WORD),fpw);
strHead.bfSize=Y_WIDTH*Y_HEIGHT*3+54;//位图文件大小,说明文件的大小,用字节为单位 strHead.bfReserved1=0; strHead.bfReserved2=0; strHead.bfOffBits=54;//从文件头到实际位图数据的偏移字节数14+40,无调色板。 fwrite(&strHead,1,sizeof(tagBITMAPFILEHEADER),fpw);
strInfo.biWidth = Y_WIDTH;//指定图象的宽度,单位是象素。 strInfo.biHeight = Y_HEIGHT;//指定图象的高度,单位是象素。 strInfo.biBitCount=24;////指定表示颜色时要用到的位数,常用的值为1(黑白二色图), 4(16色图), 8(256色), 24(真彩色图)( strInfo.biClrImportant=0;///指定本图象中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。 strInfo.biClrUsed=0;///指定本图象实际用到的颜色数,如果该值为零,则用到的颜色数为2的biBitCount次方。 strInfo.biCompression=0;//指定位图是否压缩。 strInfo.biPlanes=1;///平面数,必须是1 strInfo.biSize=40;///指定这个结构的长度,必须是40。 strInfo.biSizeImage=3*width*height;//指定实际的位图数据占用的字节数,似乎填什么都可以。
fwrite(&strInfo,1,sizeof(tagBITMAPINFOHEADER),fpw);
//保存像素数据 for(i =Y_HEIGHT;i > 0;--i)///从上往下写。图像上下翻转 { for(int j = 0;j < Y_WIDTH;++j) //for(int j = Y_WIDTH;j > 0;--j)///从右往左写 图像左右对调 { fwrite( &((*(imagedata + i * Y_WIDTH + j)).blue),1,sizeof(BYTE),fpw); fwrite( &((*(imagedata + i * Y_WIDTH + j)).green),1,sizeof(BYTE),fpw); fwrite( &((*(imagedata + i * Y_WIDTH + j)).red),1,sizeof(BYTE),fpw); } }
fclose(fpw); //释放内存 delete[] imagedata;
return 0;}void ReadImage(unsigned char *pImage,char *cFileName,int nWidth,int nHeight,long offset){ int j,i; unsigned char *pWork; FILE *fp=0; if ( fp=fopen(cFileName,"rb" ) ) //打开一幅图像 { fseek(fp,offset,SEEK_SET); //文件定位 pWork=pImage; //指针指向 for ( j=0;j<nHeight;j++,pWork+=nWidth ) for ( i=0;i<nWidth;i++ ) fread(pWork+i,1,1,fp); //顺序读取,每次读一个字节存入pwork[]中 fclose(fp); }};
【数字图像处理】YUV420转RGB并BMP存储<纯C++实现>
最新推荐文章于 2025-01-27 09:30:15 发布
本文介绍如何从YUV420格式的akiyo_qcif.yuv文件读取一帧图像,并将其转换为RGB格式,最终存储为BMP文件。解决了图像倒立和颜色偏差问题,并探讨了YUV到RGB的转换公式。
1021

被折叠的 条评论
为什么被折叠?



