数据压缩实验2
2017-04-23 23:11
204 查看
基本原理
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,之后为位图数据。
相关文章推荐
- 数据压缩实验一实验报告
- 数据压缩实验一:yuv转rgb
- 数据压缩实验三:用c语言实现Huffman编码和压缩效率分析
- 数据压缩原理 实验四 DPCM压缩系统的实现和分析
- 数据压缩实验5-JEPG解码
- 数据压缩实验4-DPCM编码
- 李春葆数据结构上机实验指导书中矩阵压缩存储的一处错误
- 数据压缩原理实验2_实验报告
- 数据压缩实验二:bmp2yuv
- 数据压缩原理 实验三 Huffman编解码算法实现与压缩效率分析
- 数据压缩原理实验1_彩色空间转换实验YUVtoRGB
- 数据压缩原理与应用 图像文件的读写和转换(BMP2YUV)实验报告
- 数据压缩原理实验1_实验报告
- 数据压缩实验二:BMP2YUV文件转换
- 数据压缩实验二 图像文件的读写和转换(bmp转yuv)
- 数据压缩实验一——彩色空间转换
- 数据压缩实验1
- 数据压缩原理实验2_BMP2YUV文件转换
- 数据压缩实验四:DPCM编码
- 数据压缩第二次实验报告——用C语言实现bmp to yuv的图片格式转化