实验原理:
1.BMP文件的组成结构
BMP(全称 Bitmap )是Windows操作系统中的标准图像文件格式,可以分成两类:设备相关位图(DDB )和设备无关位图(DIB),使用非常广。它采用位映射存储格式,除了图像深度可选以外,在绝大多数应用中不采用其他任何压缩,因此BMP文件所占用的空间很大。BMP 文件的图像深度可选 1bit、4bit、 8bit 、16bit及24bit ,指存储每个像素所用的位数。BMP 文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。由于BMP 文件格式是 Windows环境中交换与图有关的数据的一种标准,因此在Windows 环境中运行的图形软件都支持BMP图像格式。
典型的BMP图像文件由四部分组成:
(1)位图头文件数据结构,它包含 BMP 图像文件的类型、显示内容等信息;
(2)位图信息数据结构,它包含有 BMP 图像的宽、高、压缩方法,以及定义颜色等信息;
(3)调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的 BMP)就不需要调色板;
(4)位图数据,这部分的内容根据 BMP 位图使用的位数不同而不同,在 24 位图中直接使用 RGB,而其他的小于 24 位的使用调色板中颜色索引值。
实验流程:
1. 程序初始化
2. 读取bmp文件,抽取或生成rgb写入缓冲区
3. 调用rgb2yuv函数实现rgb2yuv数据的转换
4. 写入yuv文件
5. 关闭文件,释放缓冲区
实验代码:
Main.cpp
#include <stdio.h>
#include <Windows.h>
#include <malloc.h>
#include <memory.h>
#include "rgb2yuv.h"
#include "readrgb.h"
#define u_int8_t unsigned __int8
#define u_int unsigned __int32
#define u_int32_t unsigned __int32
BITMAPFILEHEADER File_header;
BITMAPINFOHEADER Info_header;
void main(int argc, char *argv[])
{
FILE*bmpFile = NULL;
FILE*yuvFile = NULL;
FILE*out2huff = NULL;
char*bmpFileName = NULL;
char*yuvFileName = NULL;
//u_intFrames = 40;
char*diffFileName = NULL;
BYTE*rgbData=NULL;
BYTE*y_buf=NULL,
*u_buf=NULL,*v_buf=NULL;
intQbits;
bmpFileName= argv[1];
yuvFileName= argv[2];
//Frames= atoi(argv[3]);
diffFileName= argv[3];
Qbits= atoi(argv[4]);
bmpFile= fopen(bmpFileName, "rb+");
if(bmpFile == NULL)
{
printf("can'tfind the bmp file\n");
}
else{
printf("THEinput bmp file is %s\n", bmpFileName);
}
yuvFile= fopen(yuvFileName, "wb+");
if(yuvFile == NULL)
{
printf("worryoutput file path\n");
}
else
{
printf("theoutput yuv file is %s\n", yuvFileName);
}
// read file & info header
if(fread(&File_header, sizeof(BITMAPFILEHEADER), 1, bmpFile) != 1)
{
printf("readfile header error!\n");
exit(0);
}
if(File_header.bfType != 0x4D42)
{
printf("Notbmp file!\n");
exit(0);
}
else
{
printf("thisis a %c%c\n", 0x42,0x4d);//存在问题
}
if(fread(&Info_header,sizeof(BITMAPINFOHEADER),1,bmpFile)!=1)
{
printf("readinfo header error!");
exit(0);
}
//endread header
rgbData= (unsigned char *)malloc(Info_header.biWidth*Info_header.biHeight * 3);
memset(rgbData,0, Info_header.biWidth*Info_header.biHeight * 3);
y_buf= (unsigned char *)malloc(Info_header.biWidth*Info_header.biHeight );
u_buf= (unsigned char *)malloc(Info_header.biWidth*Info_header.biHeight / 4);
v_buf= (unsigned char *)malloc(Info_header.biWidth*Info_header.biHeight / 4);
printf("Thisis a %d bits image!\n", Info_header.biBitCount);
printf("\nbmpsize: \t%d X %d\n\n", Info_header.biWidth, Info_header.biHeight);
ReadRGB(bmpFile,File_header, Info_header, rgbData);
RGB2YUV(Info_header.biWidth,Info_header.biHeight, rgbData, y_buf, u_buf, v_buf, 0);
/*
对y灰度值进行DPCM处理
*/
int* qn = NULL;
unsignedchar * q = NULL;
unsignedchar * rebuild = NULL;
qn= (int *)malloc(Info_header.biWidth*Info_header.biHeight*sizeof(int));
q= (unsigned char *)malloc(Info_header.biWidth*Info_header.biHeight);
rebuild= (unsigned char *)malloc(Info_header.biWidth*Info_header.biHeight);
intscale = 512 / (1 << Qbits);
for(int i = 0; i < Info_header.biHeight; i++)
{
for(int j = 0; j < Info_header.biWidth; j++)
{
if(j == 0) //第一列灰度值为128
{
qn[i*Info_header.biWidth+ j] = y_buf[i*Info_header.biWidth + j] - 128; //负反馈
}
else{
qn[i*Info_header.biWidth+ j] = y_buf[i*Info_header.biWidth + j] - rebuild[i*Info_header.biWidth + j -1];
}
qn[i*Info_header.biWidth+ j] = qn[i*Info_header.biWidth + j] / scale;//简单量化
if(j == 0){
rebuild[i*Info_header.biWidth+ j] = qn[i*Info_header.biWidth + j] * scale + 128; //重建过程
}
else
{
rebuild[i*Info_header.biWidth+ j] = qn[i*Info_header.biWidth + j] * scale + rebuild[i*Info_header.biWidth +j - 1];
}
q[i*Info_header.biWidth+ j] = qn[i*Info_header.biWidth + j] +128;
}
}
//memset(u_buf,128, Info_header.biWidth*Info_header.biHeight);
// memset(v_buf, 128,Info_header.biWidth*Info_header.biHeight);
fwrite(rebuild,1, Info_header.biWidth*Info_header.biHeight, yuvFile);
//fwrite(u_buf,1, Info_header.biWidth*Info_header.biHeight / 4, yuvFile);
//fwrite(v_buf,1, Info_header.biWidth*Info_header.biHeight / 4, yuvFile);
out2huff= fopen(diffFileName, "wb");
fwrite(q,1, Info_header.biWidth*Info_header.biHeight, out2huff);
if(rgbData) free(rgbData);
if(qn) free(qn);
if(q) free(q);
if(rebuild) free(rebuild);
if(y_buf) free(y_buf);
if(u_buf) free(u_buf);
if(v_buf) free(v_buf);
fclose(out2huff);
fclose(bmpFile);
fclose(yuvFile);
}
bmp2yuv.cpp
#include<stdio.h>
#include<math.h>
#include"BMPtoYUV.h"
#include<Windows.h>
static float RGBYUV02990[256],RGBYUV05870[256], RGBYUV01140[256];
static float RGBYUV01684[256],RGBYUV03316[256];
static float RGBYUV04187[256],RGBYUV00813[256];
bool MakePalette(FILE * pFile,BITMAPFILEHEADER &file_h, BITMAPINFOHEADER & info_h, RGBQUAD*pRGB_out)
{
/*若图像开始位置与INFOHEADER结束处位置,还有pow(2,info_h.biBitCount)个
结构体RGBQUAQ的空间(颜色数为2的biBitCount次方,调色板为数组),
则说明该bmp图像有调色板。*/
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;
}
void ReadRGB(unsigned char * rgbbuf,FILE *bmpfile, BITMAPFILEHEADER &file_h, BITMAPINFOHEADER &info_h)
{
u_int Height = 0, Width = 0;
long Loop = 0;
unsigned char *bmpbuf = NULL;
unsigned char *rgb = NULL;
unsigned char mask = 0;
int deltaw = 0;
rgb = rgbbuf;
if (((info_h.biWidth *info_h.biBitCount / 8) % 4) == 0)
Width = info_h.biWidth*info_h.biBitCount / 8;
else
Width = (info_h.biWidth *info_h.biBitCount + 31) / 32 * 4;
if ((info_h.biHeight % 2) == 0)
Height = info_h.biHeight;
else
Height = info_h.biHeight +1;
deltaw = Width - info_h.biWidth * info_h.biBitCount / 8;
bmpbuf = (unsigned char *)malloc(sizeof(unsignedchar)*Height*Width);
printf("word_width :%d , word_height: %d \n", Width,Height);
RGBQUAD *pRGB = (RGBQUAD *)malloc(sizeof(RGBQUAD) * (unsignedint)pow(2.0, (double)info_h.biBitCount));
if (!MakePalette(bmpfile, file_h, info_h, pRGB))
{
printf("No palette!\n");
}
fread(bmpbuf, 1, Height*Width, bmpfile);
if (info_h.biBitCount == 24)
{
for (Loop = 0; Loop<Height*Width; Loop++)
{
if (deltaw != 0)
{
if (deltaw == 1)
{
if ((Loop + 1) % Width == 0)
continue;
}
else if (deltaw == 2)
{
if ((Loop + 1) % Width == 0|| (Loop + 2) % Width == 0)
continue;
}
else
{
if ((Loop + 1) % Width == 0|| (Loop + 2) % Width == 0 || (Loop + 3) % Width == 0)
continue;
}
}
*rgb = *(bmpbuf + Loop);
rgb++;
}
}
else if (info_h.biBitCount == 16)
{
for (Loop = 0; Loop < Height * Width; Loop += 2)
{
*rgb = (bmpbuf[Loop] & 0x1F)<< 3;
*(rgb + 1) = ((bmpbuf[Loop] &0xE0) >> 2) + ((bmpbuf[Loop + 1] & 0x03) << 6);
*(rgb + 2) = (bmpbuf[Loop + 1]& 0x7C) << 1;
rgb += 3;
}
}
else
{
for (Loop = 0; Loop < Height*Width; Loop++)
{
if (deltaw != 0)
{
if (deltaw == 1)
{
if ((Loop + 1) % Width ==0)
continue;
}
else if (deltaw == 2)
{
if ((Loop + 1) % Width == 0|| (Loop + 2) % Width == 0)
continue;
}
else
{
if ((Loop + 1) % Width == 0|| (Loop + 2) % Width == 0 || (Loop + 3) % Width == 0)
continue;
}
}
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)
{
/*根据从数据中提取出的索引号index,以index为调色板数组下标去查询
数据中每info_h.biBitCount位所代表的颜色。
while 循环的次数:
1bit 图像每字节循环8次
2bit 图像 每字节循环4次
4bit 图像 每字节循环2次
8bit 图像 每字节循环1次。
*/
unsigned char index =
mask == 0xFF ? bmpbuf[Loop]: ((bmpbuf[Loop] & mask) >> (8 - shiftCnt *info_h.biBitCount));
*rgb =pRGB[index].rgbBlue;
*(rgb + 1) =pRGB[index].rgbGreen;
*(rgb + 2) = pRGB[index].rgbRed;
if (info_h.biBitCount == 8)mask = 0;
else mask >>= info_h.biBitCount;
rgb += 3;
shiftCnt++;
}
}
}
if (pRGB != NULL) free(pRGB);
if (bmpbuf != NULL)free(bmpbuf);
}
实验结果:
原bmp图
经转换过的bmp图