数据压缩实验2

来源:互联网 发布:网络售彩最新消息官方 编辑:程序博客网 时间:2024/06/05 04:31

基本原理

Bmp文件格式包括四个部分:位图文件头BITMAPFILEHEADER、位图信息头BITMAPINFOHEADER、调色板Palette、实际的位图数据ImageData

位图文件头主要包括:

[cpp] viewplain copy

typedefstruct tagBITMAPFILEHEADER { 

WORDbfType; /* 说明文件的类型 */ 

DWORDbfSize; /* 说明文件的大小,用字节为单位 */ 

WORDbfReserved1; /* 保留,设置为0 */ 

WORDbfReserved2; /* 保留,设置为0 */ 

DWORDbfOffBits; /* 说明从BITMAPFILEHEADER结构开始到实际的图像数据之间的字节偏移量 */ 

}BITMAPFILEHEADER; 

 

位图信息头主要包括:

[cpp] viewplain copy

typedefstruct tagBITMAPINFOHEADER { 

DWORDbiSize; /* 说明结构体所需字节数 */ 

LONGbiWidth; /* 以像素为单位说明图像的宽度 */ 

LONGbiHeight; /* 以像素为单位说明图像的高速 */ 

WORDbiPlanes; /* 说明位面数,必须为1 */ 

WORDbiBitCount; /* 说明位数/像素,1、2、4、8、24 */ 

DWORDbiCompression; /* 说明图像是否压缩及压缩类型BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS */ 

DWORDbiSizeImage; /* 以字节为单位说明图像大小,必须是4的整数倍*/ 

LONGbiXPelsPerMeter; /*目标设备的水平分辨率,像素/米 */ 

LONGbiYPelsPerMeter; /*目标设备的垂直分辨率,像素/米 */ 

DWORDbiClrUsed; /* 说明图像实际用到的颜色数,如果为0,则颜色数为2的biBitCount次方 */ 

DWORDbiClrImportant; /*说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要。*/ 

}BITMAPINFOHEADER; 

 

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

[cpp] viewplain copy

typedefstruct tagRGBQUAD { 

BYTErgbBlue; /*指定蓝色分量*/ 

BYTErgbGreen; /*指定绿色分量*/ 

BYTErgbRed; /*指定红色分量*/ 

BYTErgbReserved; /*保留,指定为0*/ 

}RGBQUAD; 

实验流程

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

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

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

4.       写YUV文件

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

 

 

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

关键代码及其分析

16bit文件操作

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;

}

1~8bit文件操作

 

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 ++;

}

void ReadRGB( BITMAPFILEHEADER &file_h, BITMAPINFOHEADER & info_h, FILE * pFile,unsigned char * rgbDataOut)

 

{

为了使每一行的字节数是四的整数倍

unsigned longLoop, i, j, width, height;

unsigned intx,y;

unsigned charmask, *Index_Data, *Data;

       if((info_h.biWidth % 4) == 0)

x= info_h.biWidth;

else

y= (info_h.biWidth*info_h.biBitCount + 31) / 32 * 4;

if((info_h.biHeight % 2) == 0)

y= info_h.biHeight;

else

              y= info_h.biHeight + 1;

       width= x / 8 * info_h.biBitCount;

       height= y;

       Index_Data= (unsigned char *)malloc(height*width);

Data = (unsignedchar *)malloc(height*width);

fseek(pFile,file_h.bfOffBits, 0);

if(fread(Index_Data, height*width, 1, pFile) != 1)

printf("read file error!");

       exit(0);

       }

 

       倒置

       for(i = 0; i < height; i++)

              for(j = 0; j < width; j++)

              {

                     Data[i*width+ j] = Index_Data[i*width + j];

              }

       if(info_h.biBitCount == 24)

       {

              memcpy(rgbDataOut,Data, height*width);

              free(Index_Data);

              free(Data);

              return;

       }

       RGBQUAD*pRGB = (RGBQUAD *)malloc(sizeof(RGBQUAD)*(unsignedint)pow(2,(float)info_h.biBitCount));                                                 

       if(!MakePalette(pFile, file_h, info_h, pRGB))

              printf("Nopalette!");

16bit

       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;

              }

       }

1~8bit

       for(Loop = 0; Loop<height*width; Loop++)

       {

              switch(info_h.biBitCount)

              {

              case1:

                     mask= 0x80;

                     break;

              case2:

                     mask= 0xC0;

                     break;

              case4:

                     mask= 0xF0;

                     break;

              case8:

                     mask= 0xFF;

              }

              intshiftCnt = 1;

              while(mask)

              {

                     unsignedchar 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(Index_Data);

       free(Data);

       free(pRGB);

}

void main(int argc, char *argv[])

{

       FILE*bmpFile = NULL, *yuvFile = NULL;

       BITMAPFILEHEADERFile_header;

       BITMAPINFOHEADERInfo_header;

       unsignedchar * rgbBuf = NULL;

       unsignedchar * yBuff = NULL;

       unsignedchar * uBuff = NULL;

       unsignedchar * vBuff = NULL;

       intflip = 0;

       intcountframe = 200;

打开文件

       if((bmpFile = fopen(argv[1], "rb")) == NULL)

       {

              printf("bmpfile open failed!");

              exit(0);

       }

       if((bmpFile = fopen(argv[2], "rb")) == NULL)

       {

              printf("bmpfile open failed!");

              exit(0);

       }

       if((bmpFile = fopen(argv[3], "rb")) == NULL)

       {

              printf("bmpfile open failed!");

              exit(0);

       }

       if((bmpFile = fopen(argv[4], "rb")) == NULL)

       {

              printf("bmpfile open failed!");

              exit(0);

       }

       if((bmpFile = fopen(argv[5], "rb")) == NULL)

       {

              printf("bmpfile open failed!");

              exit(0);

       }

 

       if((yuvFile = fopen(argv[6], "ab+")) == NULL)

       {

              printf("yuvfile failed!");

              exit(0);

       }

       if(fread(&File_header, sizeof(BITMAPFILEHEADER), 1, bmpFile) != 1)

       {

              printf("readfile header error!");

              exit(0);

       }

       if(File_header.bfType != 0x4D42)

       {

              printf("Not bmp file!");

              exit(0);

       }

       if(fread(&Info_header, sizeof(BITMAPINFOHEADER), 1, bmpFile) != 1)

       {

              printf("readinfo header error!");

              exit(0);

       }

       intwidth, height;

       if((Info_header.biWidth % 4) == 0)

              width= Info_header.biWidth;

31再除以32后下取整,就保证了计算结果是离这个数最近的而且是比它大的32的倍数,也就保证了是4字节的整数倍。乘以4和行数,得到4字节整数倍的图像大小。

       else

 

              width= (Info_header.biWidth*Info_header.biBitCount + 31) / 32 * 4;

 

       if((Info_header.biHeight % 2) == 0)

              height= Info_header.biHeight;

       else

              height= Info_header.biHeight + 1;

开辟缓冲区

       rgbBuf= (unsigned char *)malloc(height*width * 3);

       memset(rgbBuf,0, height*width * 3);

       yBuff= (unsigned char *)malloc(height*width);

       uBuff= (unsigned char *)malloc((height*width) / 4);

       vBuff= (unsigned char *)malloc((height*width) / 4);

      

 

       inti;

       printf("Thisis a %d bits image!\n", Info_header.biBitCount);

       printf("\nbmpsize: \t%d X %d\n", Info_header.biWidth, Info_header.biHeight);

       ReadRGB(File_header,Info_header, bmpFile, rgbBuf);

              if(RGB2YUV(width, height, rgbBuf, yBuff, uBuff, vBuff, flip))

              {

                     printf("rgb2yuverror");

                     exit(1);

              }

防止色彩溢出

 

              for(i = 0; i < width*height; i++)

              {

                     if(yBuff[i] < 16) yBuff[i] = 16;

                     if(yBuff[i] > 235) yBuff[i] = 235;

              }

              for(i = 0; i < width*height / 4; i++)

              {

                     if(uBuff[i] < 16) uBuff[i] = 16;

                     if(uBuff[i] > 240) uBuff[i] = 240;

                     if(vBuff[i] < 16) vBuff[i] = 16;

                     if(vBuff[i] > 240) vBuff[i] = 240;

              }

输出

              for(int m = 0; m < 40; m++)

              {

                     fwrite(yBuff,1, width * height, yuvFile);

                     fwrite(uBuff,1, (width * height) / 4, yuvFile);

                     fwrite(vBuff,1, (width * height) / 4, yuvFile);

              }

       }

       free(rgbBuf);

       free(yBuff);

       free(uBuff);

       free(vBuff);

       fclose(bmpFile);

       fclose(yuvFile);

 

}

实验结果

图片选择的是720*576的格式,以下是结果视频的截图

以此图为例前十四个字节为位图文件头,之后的四十个字节为位图信息头,1bit调色板占的字节数是4*2^1=8,之后为位图数据。

 

 

 

 

 


0 0