【数据压缩】Exp02.BMP2YUV

实验原理:

    本次实验的目的是实现将不同像素深度的bmp图像文件转为yuv格式,并生成一个帧数大于200yuv序列,因此在实验之前应该先对bmp文件的数据组织格式有一定的了解。

   BMP文件是Windows操作系统中的标准图像文件格式,可以分成两类:设备相关位图(DDB)和设备无关位图(DIB)。它采用位映射存储格式,除了图像深度可选以外,在绝大多数应用中不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选 lbit4bit8bit16bit 24bitBMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。

典型的 BMP图像文件由四部分组成:

1)位图头文件数据结构(BITMAPFILEHEADER),它包含 BMP 图像文件的类型、显示内容等信息;

2)位图信息数据结构(BITMAPINFOHEADER),它包含有 BMP 图像的宽、高、压缩方法,以及定义颜色等信息;

3)调色板(Palette),这个部分是可选的,1bit\4bit\8bit位图需要调色板,16bit\24bit不需要调色板;

4)位图数据(ImageData),这部分的内容根据 BMP 位图使用的位数不同而不同,在 24位图中直接使用 RGB16位位图用两个字节来存储一个像素点的RGB值,有555(高位为0)和565G6bit表示)两种存储格式,而其他的小于 24 位的使用调色板中颜色索引值。

实验步骤:

第一步:生成八张图像深度为24位的.bmp图片文件,实现将单张.bmp文件转化为yuv文件,添加了如下的代码:



分别定义了两个结构体为 file_header file_header ,用来存储 .bmp 文件中表征自身信息的数据,例如图像的水平像素数和垂直像素数等。在调试过程中可以看到两结构体中的数据:


再用二进制的方式打开输入的.bmp文件:


可以看到,二进制文件中的数据是与结构体中的数据一一对应的,选中的数据即为两个结构体中的数据,此后即为真正的图像像素数据。因此证明将单张24位位图转为yuv文件是正确的,效果图如下:



第二步:实现将五张不同的24位位图转化为一个200帧以上的yuv序列,每张图像显示的帧数可自行在命令行参数中进行设置。首先命令行参数设置如下:


利用循环结构,读取每个输入文件以及其显示的帧数,循环读取文件并将其转为yuv数据写入yuv文件中:


最终得到的yuv序列为:


第三步:实现将同一张像素深度不同的bmp格式的图片转为yuv文件。对于不同像素深度的图片,其数据存储方式有不同。1bit4bit8bit16bit24bit是几种常见的像素深度。对于1bit\4bit\8bit的图像有调色板,其ImageData中存储的是对应像素的索引值,通过该索引值到调色板中得到其对应的rgb值,而16bit\24bit的则无调色板,其ImageData中直接存储的是素数的rgb值。因此想要将不同像素深度的图像均能转化为yuv格式,构造了两个函数:makePalette()(用来获取文件数据中的调色板数据,若没有调色板则不做处理);makeRGBdata()(用来将文件中的ImageData部分的数据转为RGB数据),关键代码如下:



640x480的图像01_1bit.bmp01_4bit.bmp01_8bit.bmp01_24bit.bmp图像分别测试,发现都能正确生成对应的图片,效果图如下:


第四步:实现将ImageData中有存储时添加的填充数据的图像进行转换。由于bmp文件规定每一扫描行的字节数必须是 4 的整倍数,也就是DWORD对齐的。所以当我们在将一张图片另存为bmp格式时,为了保证每一扫描行都是4字节的整数倍,若选择图片的水平像素数不满足这个要求,则电脑会自动添加填充数据使得每一行的字节数是4的倍数,例如对一张565x565的图像存为像素深度为1bit的bmp文件,每个字节可以存储8个像素的索引值,因此该扫描行的像素值不能被8整除,再存储时需要先填充3bit使其能够构成整字节,每行填充3bit后则每扫描行的数据需要71个字节,由于71不是4的倍数所以在存储时还需要在每行的数据后加入1个字节的填充数据使得满足每行字节数为4 的倍数这个要求。因此,为了使所有像素数的图像均能正常转换,需要在生成rgb数据时判断哪些为真正有用的数据,哪些是填充的数据,从而只对有用数据进行处理读取对应rgb值,跳过存储时添加的填充数据。因此修改makeRGBdata()函数,下面为修改后的代码:

由于测试时挑选了一张565x565的图像,因此rgb2yuv.cpp中的代码也需要进行相应的修改,否则由于宽高不能被2整除将会直接跳出不能正确生成yuv文件,因此将图像的最后一行和最后一列去掉再对其进行处理。这一步是我之前没有想到的,因此反复检查makeRGBdata中的代码而忽略了这儿,经过修改后程序终于能跑通了,生成的yuv文件变成564x564的。


实验结果:

将上述步骤的代码进行整合,实现将不同像素深度的不同图像进行转换,生成一个yuv序列,输入的图像均为565x423。最终的效果图如下:


结论:

       这次的实验是实现将一个数据组织形式不是很复杂的媒体文件进行转化,但是由于对数据的存储方式有较多细节的考虑,例如不同像素深度的图像是否有调色板,如何将文件中存储的数据转为rgb数据,如何再将ImageData中的数据转化为rgb数据时跳过填充数据等,实现这次的实验还是花费了不少时间。通过这次的实验,我了解到了如果想要自己写出的程序能够处理各种不同情况,真的需要把方方面面都考虑到,这样才能提高程序的完备性。

       在实验的过程中我也发现了一些自己需要提高的点,例如自己在编程时比较喜欢照着自己的思路从头往下写,但是这是一个不太好的习惯,对于一些较复杂的功能应该考虑将这个功能用一个函数封装起来,然后在主函数中对其进行调用,这样主函数中的代码就不会那么冗长且杂乱了,在看起来更简洁易读的同时也提高了代码的可移植性。除此之外,在开辟缓存的时候一定要注意开辟空间的大小,再对开辟的缓存操作结束后记得关闭缓存,再对文件进行读写操作时也一定要注意范围,不然很容易造成文件指针的越界。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值