《数据压缩》实验报告二·BMP2YUV实验

实验原理

 ·BMP文件格式

位图文件头BITMAPFILEHEADER

位图信息头BITMAPINFOHEADER

调色板Palette

实际的位图数据ImageData



·位图文件头BITMAPFILEHEADER结构体


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


·位图信息头BITMAPINFOHEADER结构体


  
  
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;




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

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

·位图数据


位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:

当biBitCount=1时,8个像素占1个字节;

当biBitCount=4时,2个像素占1个字节;

当biBitCount=8时,1个像素占1个字节;

当biBitCount=24时,1个像素占3个字节,按顺序分别为B,G,R;

Windows规定一个扫描行所占的字节数必须是

4的倍数(即以long为单位),不足的以0填充,

biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;


下图为24位bmp图像的二进制数据(截取)




实验流程

1.程序初始化(打开两个文件、定义变量和缓冲区等)

2.读取BMP文件,抽取或生成RGB数据写入缓冲区


        3.调用RGB2YUV的函数实现RGB到YUV数据的转换




4.写YUV文件
        5.程序收尾工作(关闭文件,释放缓冲区)


主要代码

1. main.cpp
本次实验添加头文件#include <windows.h>
初始化变量及对输入输出文件的基本操作与实验一基本相同,这里不再重复。(注意本次实验输入多个图片,需要添加循环)
且本次实验使用
	yuvFile = fopen(yuvFileName, "ab");
ab方式为向二进制文件尾部增加数据,不存在则新建,存在则追加


读入bmp图像的数据

if(fread(&File_header,sizeof(File_header),1,bmpFile) != 1)
    {
		printf("read file header error!");
		exit(0);
    }
   if (File_header.bfType != 0x4D42)
   {
		printf("Not bmp file!");
		exit(0);
   }
   else
    {	printf("this is a %d\n",File_header.bfType);}
   if(fread(&Info_header,sizeof(BITMAPINFOHEADER),1,bmpFile) != 1)
	{	printf("read info header error!");
		exit(0);}

获取生成yuv的长与宽

    frameWidth=Info_header.biWidth;
	frameHeight=Info_header.biHeight;

开空间

    rgbBuf = (unsigned char*)malloc(frameWidth * frameHeight * 3*sizeof(unsigned char));
	yBuf = (unsigned char*)malloc(frameWidth * frameHeight*sizeof(unsigned char));
	uBuf = (unsigned char*)malloc((frameWidth * frameHeight*sizeof(unsigned char)) / 4);
	vBuf = (unsigned char*)malloc((frameWidth * frameHeight*sizeof(unsigned char)) / 4);


接着把bmp数据写入bmp2rgb2yuv.cpp中的函数

BMP2YUV(File_header,Info_header, bmpFile,rgbBuf); 

之后转成yuv(防止溢出的方法与实验一相同)

RGB2YUV(frameWidth, frameHeight, rgbBuf, yBuf, uBuf, vBuf, flip)

同一图片循环10次写入yuv文件

for(fp=0;fp<10;fp++)
	{
		fwrite(yBuf, 1, frameWidth * frameHeight, yuvFile);
		fwrite(uBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
		fwrite(vBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
		printf("\r...%d", ++videoFramesWritten);
		}

最后清理空间

    fclose(yuvFile);
	fclose(bmpFile);
	free(rgbBuf);
	free(yBuf);
	free(uBuf);
	free(vBuf);


2.bmp2rgb2yuv.cpp


主要函数void BMP2YUV(BITMAPFILEHEADER & file_h, BITMAPINFOHEADER & info_h, FILE * pFile, unsigned char * rgbDataOut)  

定义变量

unsigned long Loop; 
    unsigned int width,height,w,h; 
    unsigned char mask, *Data;  

获得长与宽(保证是4的整数倍)

if ((info_h.biWidth % 4) == 0)  
        w = info_h.biWidth;  
    else  
        w = (info_h.biWidth*info_h.biBitCount + 31) / 32 * 4;  
    if ((info_h.biHeight % 2) == 0)  
        h = info_h.biHeight;  
    else  
        h = info_h.biHeight + 1;  
  
    width = w / 8 * info_h.biBitCount;  
    height = h;  

开辟空间并写入图像数据

Data = (unsigned char *)malloc(height*width); 
    fread(Data, 1,height*width,pFile); 


再根据图像的位数不同进行数据处理
	if(info_h.biBitCount==24)
	   {	   memcpy(rgbDataOut, Data, height*width);  
                   free(Data);     
	   }
       else if(info_h.biBitCount==16)
	   {           for (Loop = 0;Loop < height * width;Loop +=2)
			   {
                      *rgbDataOut = (Data[Loop]&0x1F)<<3;
                      *(rgbDataOut + 1) = ((Data[Loop]&0xE0)>>2) + ((Data[Loop+1]&0x03)<<6);
                      *(rgbDataOut + 2) = (Data[Loop+1]&0x7C)<<1;
                      rgbDataOut +=3;
			   } 			 		
	   }
	
	   else{  RGBQUAD *pRGB = (RGBQUAD *)malloc(sizeof(RGBQUAD)*(unsigned int)pow(2,info_h.biBitCount));	
                  if(!MakePalette(pFile,file_h,info_h,pRGB))
             	  printf("No palette!");
                  for (Loop = 0; Loop<height*width; Loop++)  
		{  
                            switch (info_h.biBitCount)  
			{  
                                 case 1:  
                                 mask = 0x80;  
                                 break;  
                                 case 2:  
                                 mask = 0xC0;  
                                 break;  
                                 case 4:  
                                 mask = 0xF0;  
                                 break;  
                                 case 8:  
                                 mask = 0xFF;  
				break;
			}  
                     int shiftCnt = 1;
                       while (mask)
		 {
                              unsigned char index = mask == 0xFF?Data[Loop] : ((Data[Loop] & mask)>>(8 - shiftCnt * info_h.biBitCount));
                             * rgbDataOut = pRGB[index].rgbBlue;
                             * (rgbDataOut+1) = pRGB[index].rgbGreen;
                             * (rgbDataOut+2) = pRGB[index].rgbRed;
                              if(info_h.biBitCount == 8)	mask = 0;
                              else 	mask >>= info_h.biBitCount;
                               rgbDataOut+=3;
                               shiftCnt ++;
		}
   free(pRGB);
	}						
}

调色板函数

bool MakePalette(FILE * pFile,BITMAPFILEHEADER &file_h,BITMAPINFOHEADER & info_h,RGBQUAD *pRGB_out)
{
	if ((file_h.bfOffBits - sizeof(BITMAPFILEHEADER) - info_h.biSize) == sizeof(RGBQUAD)*pow(2,info_h.biBitCount))
	{
		fseek(pFile,sizeof(BITMAPFILEHEADER)+info_h.biSize,0);
		fread(pRGB_out,sizeof(RGBQUAD),(unsigned int)pow(2,info_h.biBitCount),pFile);
		return true;
	}else
		return false;
}

int RGB2YUV (int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip)函数与实验一相同



实验结果

使用的图片预览:
分别是1位 4位 8位 16位 24位图片



生成的yuv如下

24位bmp生成的


16位bmp生成的

8位bmp生成的

4位bmp生成的

1位bmp生成的



放大其中一种图片
24位

16位

8位

4位

1位


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值