RGB数据写bmp图片文件遇到的这些坑
2016-09-12 19:03
399 查看
用ffmpeg解码MP4后,得到YUV数据,然后YUV转换成RGB.
没隔一段时间需要保存一张图片,这里就打算直接将RGB数据写成BMP文件。
因为BMP文件是直接写RGB数据,并不编码,减少CPU的损耗。
就这么一个功能,遇到了好多坑。
一,如何用RGB写BMP文件
BMP文件的图片数据是原始RGB数据,不需要编码。但是需要在文件最开始打上BMP文件头,后面直接写RGB的数据就可以了。
BMP文件头信息如下:
也就是说,整个BMP文件就是:BMPFILEHEADER_T+BMPINFOHEADER_T+RGB原始数据。简单吧。
然后直接写文件就可以了:
二,坑一:4字节对齐
按照上面的代码写出来的文件,文件图片打开失败,说文件破损。
后来才发现BMPFILEHEADER_T这个数据接口的内部变量排序,并没有4字节对齐,导致sizeof(BMPFILEHEADER_T)比预想的大!
所以直接用宏设置数据结构的字节对齐方式为:1字节对齐。
现在图片可以打开,但是人物的颜色都是绿色,都变成“绿巨人”
三、坑二:图片颜色不对--RGB24还是BRG24?
YUV转RGB用的是ffmpeg的swscale代码:
修改成BRG24问题得到解决,如下:
今后还是需要确认一下BMP文件内部不压缩图片的格式是BGR24,而不是RGB24.
没隔一段时间需要保存一张图片,这里就打算直接将RGB数据写成BMP文件。
因为BMP文件是直接写RGB数据,并不编码,减少CPU的损耗。
就这么一个功能,遇到了好多坑。
一,如何用RGB写BMP文件
BMP文件的图片数据是原始RGB数据,不需要编码。但是需要在文件最开始打上BMP文件头,后面直接写RGB的数据就可以了。
BMP文件头信息如下:
typedef struct { WORD bfType;//0x4d42 DWORD bfSize;//sizeof(BMPFILEHEADER_T)+sizeof(BMPINFOHEADER_T)+width*height*3, 整个文件的大小 WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits;//sizeof(BMPFILEHEADER_T)+sizeof(BMPINFOHEADER_T),就是RGB数据的偏移量, 偏移这两个数据结构 } BMPFILEHEADER_T; typedef struct{ DWORD biSize;//sizeof(BMPINFOHEADER_T) LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount;//RGB24, 就是24位 DWORD biCompression;//0, 不压缩 DWORD biSizeImage;//RGB24数据大小 LONG biXPelsPerMeter;// LONG biYPelsPerMeter;// DWORD biClrUsed;//0 DWORD biClrImportant;//0 } BMPINFOHEADER_T;
也就是说,整个BMP文件就是:BMPFILEHEADER_T+BMPINFOHEADER_T+RGB原始数据。简单吧。
然后直接写文件就可以了:
bmpheader.bfType = 0x4d42; bmpheader.bfReserved1 = 0; bmpheader.bfReserved2 = 0; bmpheader.bfOffBits = <span style="font-family: Arial, Helvetica, sans-serif;">sizeof(BMPFILEHEADER_T) </span>+ sizeof(BMPINFOHEADER_T); bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp/8; bmpinfo.biSize = sizeof(BMPINFOHEADER_T); bmpinfo.biWidth = width; bmpinfo.biHeight = -height; bmpinfo.biPlanes = 1; bmpinfo.biBitCount = bpp; bmpinfo.biCompression = 0; bmpinfo.biSizeImage = (width*bpp+31)/32*4*height; bmpinfo.biXPelsPerMeter = 100; bmpinfo.biYPelsPerMeter = 100; bmpinfo.biClrUsed = 0; bmpinfo.biClrImportant = 0; fwrite(&bmpheader, sizeof(BMPFILEHEADER_T), 1, fp); fwrite(&bmpinfo, sizeof(bmpinfo), 1, fp); fwrite(pFrameRGB, width*height*bpp/8, 1, fp); fclose(fp);
二,坑一:4字节对齐
按照上面的代码写出来的文件,文件图片打开失败,说文件破损。
后来才发现BMPFILEHEADER_T这个数据接口的内部变量排序,并没有4字节对齐,导致sizeof(BMPFILEHEADER_T)比预想的大!
所以直接用宏设置数据结构的字节对齐方式为:1字节对齐。
#pragma pack(1) typedef struct { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BMPFILEHEADER_T; typedef struct{ DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BMPINFOHEADER_T; #pragma pack()这些好了,程序运行图片可以打开了,但是还有另外一个坑。
现在图片可以打开,但是人物的颜色都是绿色,都变成“绿巨人”
三、坑二:图片颜色不对--RGB24还是BRG24?
YUV转RGB用的是ffmpeg的swscale代码:
_swsContext = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, <span style="background-color: rgb(51, 51, 255);">AV_PIX_FMT_RGB24</span>, SWS_BICUBIC, NULL, NULL, NULL);YUV转换的结果是RGB24,但是这样出来的RGB数据,写成的BMP文件,显然是颜色错误。
修改成BRG24问题得到解决,如下:
_swsContext = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
今后还是需要确认一下BMP文件内部不压缩图片的格式是BGR24,而不是RGB24.
相关文章推荐
- 24位RGB数据保存为BMP图片
- mfc把rgb图像数据存为bmp文件
- VC6.0中使用Stream Object读取数据中流文件并显示Bmp,JPG等图片
- VC6.0中使用Stream Object读取数据中流文件并显示Bmp,JPG等图片
- linux下将bmp图片的RGB数值打印到文件中,并另存。
- c语言读取BMP图片的RGB数据
- 利用COM组件IPicture读取jpg、gif、bmp图片文件数据和显示图片的两个函数
- 将RGB数据写入BMP位图文件
- 利用COM组件IPicture读取jpg、gif、bmp图片文件数据和显示图片
- windows 保存rgb数据为bmp文件
- RGB数据保存为BMP图片
- 利用COM组件IPicture读取jpg、gif、bmp图片文件数据和显示图片的两个函数
- BMP文件RGB颜色数据存放方式
- 将RGB数据写入BMP位图文件
- 24位RGB数据保存为BMP图片
- 24位RGB数据保存为BMP图片
- VC6.0中使用Stream Object读取数据中流文件并显示Bmp,JPG等图片
- RGB裸数据生成bmp文件的demo
- 存储过程中的二进制图片数据转换为图片文件
- BCB实现BMP图片的RGB分解,BMP与JPG格式的相互转换