BMP文件读写以及RGB与YUV转换
2017-04-02 12:23
281 查看
最近学习图像信息处理,没想到会在BMP文件的读写以及RGB与YUV转换花费这么多时间。写下这篇文章,总结一下自己的经验教训。
一、BMP文件读写
1.1 BMP文件格式
位图文件(Bitmap-File,BMP)格式是Windows采用的图像文件存储格式,在Windows环境下运行的所有图像处理软件都支持这种格式。BMP位图文件默认的文件扩展名是bmp或者dib。BMP文件大体上分为四个部分:位图文件头、位图信息头、调色板
紧跟在调色板之后的是图像数据字节阵列。对于用到调色板的位图,图像数据就是该像素颜色在调色板中的索引值(逻辑色)。对于真彩色图,图像数据就是实际的R、G、B值。图像的每一扫描行由表示图像像素的连续的字节组成,每一行的字节数取决于图像的颜色数目和用像素表示的图像宽度。规定每一扫描行的字节数必需是4的整倍数,也就是DWORD对齐的。扫描行是由底向上存储的,这就是说,阵列中的第一个字节表示位图左下角的像素,而最后一个字节表示位图右上角的像素。
如果是没有调色板的24位真彩色BMP,其格式可用下列结构定义(共54字节):
可以参考这位大神的博客http://blog.csdn.net/leixiaohua1020/article/details/13506099 对1-8位与16位的BMP进行读写。
我为了方便操作,直接选用了24位BMP图片。这个比较简单,直接按照B/G/R的顺序写入缓冲区即可。
有一个坑点是图片前54个字节一定要写对 不然图片是无法正常显示的!!!
下面是我写的检测并读取BMP图片前54位字节的函数:
二、RGB转YUV 再转回RGB
YUV数据格式可以参考这篇文章:http://blog.csdn.net/beyond_cn/article/details/12998247
我的目标是RGB转YUV 再转回RGB,这个步骤的重点是解决转换过程中的溢出问题。为了简单,我直接用公式法;我选用的公式是
y= 0.2990*r1+0.5869*g1+0.1140*b1;
u= -0.1687*r1-0.3313*g1+0.5000*b1 +128;
v= 0.5000*r1-0.4187*g1-0.0813*b1 + 128;
中间再处理一下数据不在【0,255】之间的情况即可。
这个是含偏移量的公式。经验证可以正确转换出我想看到的效果。其他的公式总是会出bug
当然,这种方法没什么优化,都是浮点数运算。优化的话,可以参考这个:http://blog.csdn.net/chen825919148/article/details/7921475
附一张我用的测试图:【获得24位BMP图片的方式也很简单,直接用windows自带的画图工具,另存一下即可】
另外,我还学到了一点 #Pragma
Pack(n)与内存分配 的知识。
写完之后才发现,这个过程并没有那么复杂……但我还是花费了大量时间,两点原因:1.自己还是不喜欢动脑,没先搞清楚BMP的格式,就急着写代码;2.网上的资料良莠不齐,浪费了不少时间。都是泪……
对了,最后还有一点值得提一下:BMP是微软家的格式,window系统里的window.h头文件里有BMP文件结构的定义,可以直接用。我因为用的是Mac系统所以不得不重新定义
一、BMP文件读写
1.1 BMP文件格式
位图文件(Bitmap-File,BMP)格式是Windows采用的图像文件存储格式,在Windows环境下运行的所有图像处理软件都支持这种格式。BMP位图文件默认的文件扩展名是bmp或者dib。BMP文件大体上分为四个部分:位图文件头、位图信息头、调色板
紧跟在调色板之后的是图像数据字节阵列。对于用到调色板的位图,图像数据就是该像素颜色在调色板中的索引值(逻辑色)。对于真彩色图,图像数据就是实际的R、G、B值。图像的每一扫描行由表示图像像素的连续的字节组成,每一行的字节数取决于图像的颜色数目和用像素表示的图像宽度。规定每一扫描行的字节数必需是4的整倍数,也就是DWORD对齐的。扫描行是由底向上存储的,这就是说,阵列中的第一个字节表示位图左下角的像素,而最后一个字节表示位图右上角的像素。
如果是没有调色板的24位真彩色BMP,其格式可用下列结构定义(共54字节):
typedef struct bmp { //14字节 unsigned short bfType; //文件标识 2字节 必须为BM unsigned int bfSize; //文件大小 4字节 unsigned short bfReserved1; //保留,每字节以"00"填写 2字节 unsigned short bfReserved2; //同上 2字节 unsigned int bfOffBits; //记录图像数据区的起始位置(图象数据相对于文件头字节的偏移量)。 4字节 //40字节 unsigned int biSize; //表示本结构的大小 4字节 int biWidth; //位图的宽度 4字节 int biHeight; //位图的高度 4字节 unsigned short biPlanes; //永远为1 , 2字节 unsigned short biBitCount; //位图的位数 分为1 4 8 16 24 32 ,2字节 unsigned int biCompression; //压缩说明 4字节 unsigned int biSizeImage; //表示位图数据区域的大小以字节为单位 4字节 int biXPelsPerMeter; //用象素/米表示的水平分辨率 4字节 int biYPelsPerMeter; //用象素/米表示的垂直分辨率 4字节 unsigned int biClrUsed; //位图使用的颜色索引数,如果为0,则颜色数为2的biBitCount次方 4字节 unsigned int biClrImportant; //对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要 4字节 } BMP;1.2 BMP读写
可以参考这位大神的博客http://blog.csdn.net/leixiaohua1020/article/details/13506099 对1-8位与16位的BMP进行读写。
我为了方便操作,直接选用了24位BMP图片。这个比较简单,直接按照B/G/R的顺序写入缓冲区即可。
有一个坑点是图片前54个字节一定要写对 不然图片是无法正常显示的!!!
下面是我写的检测并读取BMP图片前54位字节的函数:
int ReadBmpHead(FILE * outfp,FILE* fp,char* buf_head,int* picwidth,int* picheight,long int biSizeImage){ short ind; char bm[2]; //读取文件头与图像头信息 判断是否为24位bmp图片 fseek(fp,0L,0); fread(bm,2,1,fp); fseek(fp,0L,0); fread(buf_head, 54, 1, fp); fwrite(buf_head, 1, 54, outfp); fseek(fp,28L,0); fread(&ind,2,1,fp); if(bm[0]!='B'||bm[1]!='M'||ind!=24){ printf("\n非24位BMP图片\n"); return 1; } fseek(fp, 18L, 0); fread(picwidth, 4, 1, fp); fread(picheight, 4, 1, fp); fseek(fp,34L,0);//图像数据区的大小 fread(&biSizeImage,4,1,fp); fseek(fp, 54L, 0); printf("图片尺寸%d*%d ",*picwidth,*picheight); // fread(buf_total, 1, 54+biSizeImage, fp); return 0; };之后,结合fread、fseek、fwrite函数进行文件流的读写即可,下面给出一个RGB直接转灰度图[方法比较粗暴]的例子:
fseek(fp, 54L, 0); for (i=0;i<picheight;i++) for (j = 0; j < picwidth; j++){ fread(&b, 1, 1, fp); fread(&g, 1, 1, fp); fread(&r, 1, 1, fp); //为防止rgb溢出,将其值赋给int型的r1,b1,g1进行之后的公式运算 r1 = r; b1 = b; g1 = g; //注意:这之后的步骤可根据需要自行修改 fwrite(&b1, 1, 1, outfp2); fwrite(&b1, 1, 1, outfp2); fwrite(&b1, 1, 1, outfp2); }
二、RGB转YUV 再转回RGB
YUV数据格式可以参考这篇文章:http://blog.csdn.net/beyond_cn/article/details/12998247
我的目标是RGB转YUV 再转回RGB,这个步骤的重点是解决转换过程中的溢出问题。为了简单,我直接用公式法;我选用的公式是
y= 0.2990*r1+0.5869*g1+0.1140*b1;
u= -0.1687*r1-0.3313*g1+0.5000*b1 +128;
v= 0.5000*r1-0.4187*g1-0.0813*b1 + 128;
中间再处理一下数据不在【0,255】之间的情况即可。
这个是含偏移量的公式。经验证可以正确转换出我想看到的效果。其他的公式总是会出bug
当然,这种方法没什么优化,都是浮点数运算。优化的话,可以参考这个:http://blog.csdn.net/chen825919148/article/details/7921475
附一张我用的测试图:【获得24位BMP图片的方式也很简单,直接用windows自带的画图工具,另存一下即可】
另外,我还学到了一点 #Pragma
Pack(n)与内存分配 的知识。
写完之后才发现,这个过程并没有那么复杂……但我还是花费了大量时间,两点原因:1.自己还是不喜欢动脑,没先搞清楚BMP的格式,就急着写代码;2.网上的资料良莠不齐,浪费了不少时间。都是泪……
对了,最后还有一点值得提一下:BMP是微软家的格式,window系统里的window.h头文件里有BMP文件结构的定义,可以直接用。我因为用的是Mac系统所以不得不重新定义
相关文章推荐
- 数据压缩实验实验2—图像文件的读写和转换(bmp转yuv)
- bmp提取rgb888转换成yuv格式中的yv12再从yv12转换为rgb888写成bmp格式文件的工程,测试通过
- [置顶] 实验二 图像文件的读写和转换(BMP转YUV)
- 数据压缩实验二 图像文件的读写和转换(bmp转yuv)
- 实验二 图像文件的读写和转换(BMP转YUV)
- 使用ffmpeg进行图像格式转换以及图像缩放/sws_scale/linux/c++/c/rgb-yuv420
- java中对图象文件的处理(读写以及转换)
- RGB和YUV、YCbCr 以及格式的转换总结
- yuv数据格式介绍与rgb的转换,图像文件的封装
- YUY2(YUV) 与 RGB 格式图片的相互转换 以及 基于YUY2(YUV)的blending
- 数据压缩原理与应用 图像文件的读写和转换(BMP2YUV)实验报告
- YUY2(YUV) 与 RGB 格式图片的相互转换 以及 基于YUY2(YUV)的blending
- java中对图象文件的处理(读写以及转换)
- YUY2(YUV) 与 RGB 格式图片的相互转换 以及 基于YUY2(YUV)的blending
- YUY2(YUV) 与 RGB 格式图片的相互转换 以及 基于YUY2(YUV)的blending
- YUY2(YUV) 与 RGB 格式图片的相互转换 以及 基于YUY2(YUV)的blending
- 使用ffmpeg进行图像格式转换以及图像缩放/sws_scale/linux/c++/c/rgb-yuv420
- 24位BMP图像RGB与YUV转换
- C++类型转换以及文件读写的总结
- YUY2(YUV) 与 RGB 格式图片的相互转换 以及 基于YUY2(YUV)的blending