数据压缩实验二 图像文件的读写和转换(bmp转yuv)

一、实验原理

图像存储时一般由两部分组成:图像说明部分和图 像数据部分
图像说明部分:图像的格式、深度、高度、宽度、调色板、 压缩方法等
图像数据部分:描述图像每个像素的数据

1.BMP图像文件格式

位图文件(Bitmap-File,BMP)格式是Windows采 用的图像文件存储格式,在Windows环境下运行的 所有图像处理软件都支持这种格式。BMP位图文件 默认的文件扩展名是bmp或者dib。

BMP文件大体上分为四个部分:

位图文件头BITMAPFILEHEADER
位图信息头BITMAPINFOHEADER
调色板Palette
实际的位图数据ImageData

对于一种文件的格式,C语言中往往以结构体的方式描述,因此注意工程中的结构体是十分重要的。
(1)位图头文件数据结构

typedef struct tagBITMAPFILEHEADER 
{
    WORD bfType; /* 说明文件的类型 */  
    DWORD bfSize; /* 说明文件的大小,用字节为单位 注意字节序*/  
    WORD bfReserved1; /* 保留,设置为0 */  
    WORD bfReserved2; /* 保留,设置为0 */  
    DWORD bfOffBits; /* 说明从BITMAPFILEHEADER结构开始到实际的图像数据之间的字节偏移量 */  
} BITMAPFILEHEADER;

(2)位图信息数据结构


typedef struct tagBITMAPINFOHEADER
{
    DWORD biSize; /* 说明结构体所需字节数 */
    LONG biWidth; /* 以像素为单位说明图像的宽度 */
    LONG biHeight; /* 以像素为单位说明图像的高度 */
    WORD biPlanes; /* 说明位面数,必须为1 */
    WORD biBitCount; /* 说明位数/像素,1、2、4、8、24 */
    DWORD biCompression; /* 说明图像是否压缩及压缩类型BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS */
    DWORD biSizeImage; /* 以字节为单位说明图像大小,必须是4的整数倍*/
    LONG biXPelsPerMeter; /*目标设备的水平分辨率,像素/米 */
    LONG biYPelsPerMeter; /*目标设备的垂直分辨率,像素/米 */
    DWORD biClrUsed; /* 说明图像实际用到的颜色数,如果为0,则颜色数为2的biBitCount次方 */
    DWORD biClrImportant; /*说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要。*/
} BITMAPINFOHEADER;

(3)调色板
调色板实际上是一个数组,它所包含的元素与位图 所具有的颜色数相同,决定于biClrUsed和biBitCount字 段。数组中每个元素的类型是一个RGBQUAD结构。真 彩色无调色板部分。

typedef struct tagRGBQUAD
{
    BYTE rgbBlue; /*指定蓝色分量*/
    BYTE rgbGreen; /*指定绿色分量*/
    BYTE rgbRed; /*指定红色分量*/
    BYTE rgbReserved; /*保留,指定为0*/
} RGBQUAD;

(4)图像数据字节阵列:即位图数据
紧跟在调色板之后的是图像数据字节阵列。对于用到调 色板的位图,图象数据就是该象素颜色在调色板中的索引值 (逻辑色)。对于真彩色图,图象数据就是实际的R、G、B 值。

2.需要注意的地方

(1)DWORD 对齐
图像的每一扫描行由表示图像像素的连续的字节组成,每一行的字节数取决于图像的颜色数目和用像素表示的图像宽
度。规定每一扫描行的字节数必需是4的整倍数,也就是DWORD对齐的。写入位图文件数据时,如果图像每行像素字节总数[宽 X biBiCount % 8 != 0 ],系统会自动在每行最后填充若干0值使满足整数字节,接着,如果[每行像素字节数 % 4 != 0 ],系统会自动在每行最后填充若干字节0值使满足DWORD对齐。所以我们对位图加载处理时要注意判断每行数据是否有0值填充,若有0值填充则从位图中读取数据的过程中要注意指针偏移量和即时跳转。

(2)自下而上扫描
扫描行是由底向上存储的,这就是说,阵列中的第一个字节表示位图左下角的像素,而最后一个字节表示位图右上角的像素。(只针对于倒向DIB,如果是正向DIB,则扫描行是由顶向下存储)

(3)字节序
计算机系统存储数据采用的字节序有两种:小尾字节序(Little Endian)和大尾字节序(Big Endian)。以Intel处理器为代表大多数采用小端字节序,”低位在前高位在后“既地址低位存储值的低位,地址高位存储值的高位;以Motorola处理器为代表大多数使用大端字节序,”高位在前低位在后“即地址低位存储值的高位,地址高位存储值的低位。BMP文件中仅除了文件头中文件类型WORD bfType为大端字节序,剩余结构体内的定义均是小端字节序。

(4)掩码组
调色板信息中指示了RGB比特位的掩码组信息。因为图像深度可选为1、4、8、16、24、32bit,所以不同深度的RGB比特位自然不同。
以bmp位图中使用16bit为例,位运算的图示:
这里写图片描述
若读入的BMP位图的biBiCount为8bit或更小,类似的需要位的移位、与操作。
再以2bit图像举例,其数据块中的第一个字节,对应着第一个像素的索引值为:b’xx zz zz zz,其中只有头两位包含该像素的索引信息,而后六位为其他像素的索引信息。这时候需要与b’11 00 00 00=0xC0相与,再进行6位右移,得到b’00 00 00 xx=index,这便是其对应的索引值,代入pRGB[index]获得其对应的RGB分量值。
当处理像素是第二个像素是,其对应的索引值应为该字节中的第五第六位,即b’zz xx zz zz,这时候掩码值也相应跟着位移,遂引入turn–掩码位移变量,turn可用作循环判断用,当turn为零时——说明该字节中所有像素信息已读取完,可以结束循环,进行下一个字节的读取。
同时,应注意到右移的位数也发生了变换,引入shiftcnt变量,用于不同像素点需位移的长度。每进行一次像素数据读取后,shiftcnt++,因为下一个像素(不是该字节最后一个像素时)需要位移的位数减少了shift*biBitCount个。

二、实验流程

(1)初始化:打开文件,定义变量建立缓冲区
(2)解析BMP文件,抽取或生成RGB数据写入缓冲区
(3)调用RGB2YUV函数进行数据转换
(4)写入YUV文件,关闭文件,释放缓冲区
这里写图片描述

三、实验具体算法代码

1.BMP2YUV.h
#ifndef BMP2YUV_H_
#define BMP2YUV_H_

//define mask struct
typedef struct bit32Mask
{
    unsigned int rgbRed;
    unsigned int rgbGreen;
    unsigned int rgbBlue;   
    unsigned int reserved;
}Mas32;
typedef struct bit16Mask
{
    unsigned int rgbRed;
    unsigned int rgbGreen;
    unsigned int rgbBlue;
}Mas16;

int BMP2RGB32bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf, void *mask);
int BMP2RGB24bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf);
int BMP2RGB16bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf,void *mask);
int BMP2RGBNOT24bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf, void *pRGB);
int RGB2YUV(int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip);
void InitLookupTable();
void adjust(unsigned char *b, unsigned char *g, unsigned char *r, unsigned char *y, unsigned char *u, unsigned char  *v);
#endif
2.main.c

#include <stdio.h>
#include <stdlib.h>
#include <windows.h> 
#include <math.h> 
#include "bmp2yuv.h"

#define u_int8_t    unsigned __int8
#define u_int       unsigned __int32
#define u_int32_t   unsigned __int32

int main(int argc,char **argv)
{
    int count;
    BITMAPFILEHEADER File_header;
    BITMAPINFOHEADER Info_header;
    RGBQUAD *pRGB = NULL;
    FILE* bmp = NULL;
    FILE* yuvFile = NULL;   
    Mas16 *mask16 = NULL;
    Mas32 *mask32 = NULL;

    u_int8_t* yBuf = NULL;
    u_int8_t* uBuf = NULL;
    u_int8_t* vBuf = NULL;
    u_int8_t* rgbBuf = NULL;
    u_int8_t* bmpBuf = NULL;
    u_int8_t* mask = NULL;
    u_int frameWidth;       /* --width=<uint> */
    u_int frameHeight;
    u_int bitcount;
    u_int py;
    u_int m;
    u_int8_t i;
    int sum = 0;

    char bmpf[][50] = { "park.bmp", "tree.bmp", "girlstwo.bmp", "02.bmp", "bea.bmp", "street.bmp"</
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值