BMP转JPG(法二)RGB数据经过YUV交织

转载请标明是引用于

欢迎大家拍砖!

源码下载地址:

编译平台:VS2005

在上一篇文章<<BMP转JPG(法一)VS2005环境下采用makefile编译、使用libjpeg.lib函数库>>

我们介绍了BMP转JPG的第一种方法,现在讲第二种方法。

BMP原图:

JPG结果图:

第一步、获得JPEG编码需要的bmp数据结构并获得数据。

(1)获取BMP文件输出缓冲区信息这部分相对简单,就是从文件流读取BITMAPFILEHEADER信息与BITMAPINFOHEADER信息,,获得8或16整数倍的宽与高;

它是通过GetBMBuffSize函数实现的。

// 获取BMP文件输出缓冲区信息BMBUFINFO JEnc::GetBMBuffSize(FILE* pFile) { BITMAPFILEHEADER bmHead;//文件头信息块BITMAPINFOHEADER bmInfo;//图像描述信息块 BMBUFINFO bmBuffInfo; UINT colSize = 0; UINT rowSize = 0;fseek(pFile,0,SEEK_SET);//将读写指针指向文件头部 fread(&bmHead,sizeof(bmHead),1,pFile); //读取文件头信息块 fread(&bmInfo,sizeof(bmInfo),1,pFile); //读取位图信息块// 计算填充后列数,jpeg编码要求缓冲区的高和宽为8或16的倍数 if (bmInfo.biWidth % 8 == 0) {colSize = bmInfo.biWidth; } else {colSize = bmInfo.biWidth + 8 – (bmInfo.biWidth % 8); }// 计算填充后行数 if (bmInfo.biHeight % 8 == 0) {rowSize = bmInfo.biHeight; } else {rowSize = bmInfo.biHeight + 8 – (bmInfo.biHeight % 8); }bmBuffInfo.BitCount = 24; bmBuffInfo.buffHeight = rowSize;// 缓冲区高 bmBuffInfo.buffWidth = colSize;// 缓冲区宽 bmBuffInfo.imgHeight = bmInfo.biHeight;// 图像高 bmBuffInfo.imgWidth = bmInfo.biWidth;// 图像宽return bmBuffInfo; }

(2)获得图像数据。如下图所示

第二步、将RGB信号转换为YUV信号

从上图读出的有效数据中取出R、G、B Byte,然后根据三个分量交织得到Y、U、V分量。

以下函数中pBuf为输入的RGB有效数据,输出的结果分别存在pYBuff、pUBuff、pVBuff中。

// 转换色彩空间BGR-YUV,111采样 void JEnc::BGR2YUV111(BYTE* pBuf, BYTE* pYBuff, BYTE* pUBuff, BYTE* pVBuff) { DOUBLE tmpY = 0;//临时变量 DOUBLE tmpU = 0; DOUBLE tmpV = 0; BYTE tmpB = 0;BYTE tmpG = 0; BYTE tmpR = 0; UINT i = 0; size_t elemNum = _msize(pBuf) / 3; //缓冲长度for (i = 0; i < elemNum; i++) {tmpB = pBuf[i * 3];tmpG = pBuf[i * 3 + 1];tmpR = pBuf[i * 3 + 2];tmpY = 0.299 * tmpR + 0.587 * tmpG + 0.114 * tmpB;tmpU = -0.1687 * tmpR – 0.3313 * tmpG + 0.5 * tmpB + 128;tmpV = 0.5 * tmpR – 0.4187 * tmpG – 0.0813 * tmpB + 128;//if(tmpY > 255){tmpY = 255;}//输出限制//if(tmpU > 255){tmpU = 255;}//if(tmpV > 255){tmpV = 255;}//if(tmpY < 0){tmpY = 0;}//if(tmpU < 0){tmpU = 0;}//if(tmpV < 0){tmpV = 0;}pYBuff[i] = tmpY;//放入输入缓冲pUBuff[i] = tmpU;pVBuff[i] = tmpV; } }第三步、将YUV信号分别分割为8×8的块 //******************************************************************** // 方法名称:DivBuff // 最后修订日期:2003.5.3 // // 参数说明: // lpBuf:输入缓冲,处理后的数据也存储在这里 // width:缓冲X方向长度 // height:缓冲Y方向长度 // xLen:X方向切割长度 // yLen:Y方向切割长度 //********************************************************************void JEnc::DivBuff(BYTE* pBuf,UINT width,UINT height,UINT xLen,UINT yLen){ UINT xBufs = width / xLen;//X轴方向上切割数量 UINT yBufs = height / yLen;//Y轴方向上切割数量 UINT tmpBufLen = xBufs * xLen * yLen;//计算临时缓冲区长度 BYTE* tmpBuf = new BYTE[tmpBufLen];//创建临时缓冲 UINT i = 0;//临时变量 UINT j = 0; UINT k = 0;UINT n = 0; UINT bufOffset = 0;//切割开始的偏移量for (i = 0; i < yBufs; ++i)//循环Y方向切割数量 {n = 0;//复位临时缓冲区偏移量for (j = 0; j < xBufs; ++j)//循环X方向切割数量{bufOffset = yLen * xLen * i * xBufs + j * xLen;//计算单元信号块的首行偏移量for (k = 0; k < yLen; ++k)//循环块的行数{memcpy(&tmpBuf[n],&pBuf[bufOffset],xLen);//复制一行到临时缓冲n += xLen;//计算临时缓冲区偏移量bufOffset += width;//计算输入缓冲区偏移量}}memcpy(&pBuf[i * tmpBufLen],tmpBuf,tmpBufLen); //复制临时缓冲数据到输入缓冲 }delete[] tmpBuf;//删除临时缓冲} 第四步:寝化YUV量化表 // 第四步:寝化YUV量化表 SetQuantTable(std_Y_QT, YQT, Q);// 设置Y量化表 SetQuantTable(std_UV_QT,UVQT, Q);// 设置UV量化表InitQTForAANDCT();// 初始化AA&N需要的量化表 pVLITAB=VLI_TAB + 2047;// 设置VLI_TAB的别名 BuildVLITable();// 计算VLI表 第五步:写入各段 WriteSOI();WriteAPP0(); WriteDQT(); WriteSOF(); WriteDHT(); WriteSOS();第六步:计算Y/UV信号的交直分量的huffman表

这里使用标准的huffman表,并不是计算得出,缺点是文件略长,但是速度快

BuildSTDHuffTab(STD_DC_Y_NRCODES,STD_DC_Y_VALUES,STD_DC_Y_HT); BuildSTDHuffTab(STD_AC_Y_NRCODES,STD_AC_Y_VALUES,STD_AC_Y_HT); BuildSTDHuffTab(STD_DC_UV_NRCODES,STD_DC_UV_VALUES,STD_DC_UV_HT); BuildSTDHuffTab(STD_AC_UV_NRCODES,STD_AC_UV_VALUES,STD_AC_UV_HT);第七步:处理单元数据 //******************************************************************** // 方法名称:ProcessData // // 方法说明:处理图像数据FDCT-QUANT-HUFFMAN // // 参数说明: // lpYBuf:亮度Y信号输入缓冲 // lpUBuf:色差U信号输入缓冲 // lpVBuf:色差V信号输入缓冲 //******************************************************************** void JEnc::ProcessData(BYTE* lpYBuf,BYTE* lpUBuf,BYTE* lpVBuf) {size_t yBufLen = _msize(lpYBuf);//亮度Y缓冲长度 size_t uBufLen = _msize(lpUBuf);//色差U缓冲长度size_t vBufLen = _msize(lpVBuf);//色差V缓冲长度 FLOAT dctYBuf[DCTBLOCKSIZE];//Y信号FDCT编码临时缓冲 FLOAT dctUBuf[DCTBLOCKSIZE];//U信号FDCT编码临时缓冲FLOAT dctVBuf[DCTBLOCKSIZE];//V信号FDCT编码临时缓冲UINT mcuNum = 0;//存放MCU的数量SHORT yDC = 0;//Y信号的当前块的DC SHORT uDC = 0;//U信号的当前块的DC SHORT vDC = 0;//V信号的当前块的DCBYTE yCounter = 0;//YUV信号各自的写入计数器 BYTE uCounter = 0; BYTE vCounter = 0; UINT i = 0;//临时变量UINT j = 0;UINT k = 0; UINT p = 0; UINT m = 0; UINT n = 0; UINT s = 0;mcuNum = (this->buffHeight * this->buffWidth * 3)/ (DCTBLOCKSIZE * 3);//计算MCU的数量for (p = 0;p < mcuNum; p++)//依次生成MCU并写入 {yCounter = 1;//MCUIndex[SamplingType][0]; //按采样方式初始化各信号计数器uCounter = 1;//MCUIndex[SamplingType][1];vCounter = 1;//MCUIndex[SamplingType][2];for (; i < yBufLen; i += DCTBLOCKSIZE){for (j = 0; j < DCTBLOCKSIZE; j++){dctYBuf[j] = FLOAT(lpYBuf[i + j] – 128);}if (yCounter > 0){–yCounter;ProcessDU(dctYBuf,YQT_DCT,STD_DC_Y_HT,STD_AC_Y_HT,&yDC);}else{break;}}//——————————————————————for (; m < uBufLen; m += DCTBLOCKSIZE){for (n = 0; n < DCTBLOCKSIZE; n++){dctUBuf[n] = FLOAT(lpUBuf[m + n] – 128);}if (uCounter > 0){–uCounter;ProcessDU(dctUBuf,UVQT_DCT,STD_DC_UV_HT,STD_AC_UV_HT,&uDC);}else{break;}}//——————————————————————-for (; s < vBufLen; s += DCTBLOCKSIZE){for (k = 0; k < DCTBLOCKSIZE; k++){dctVBuf[k] = FLOAT(lpVBuf[s + k] – 128);}if (vCounter > 0){–vCounter;ProcessDU(dctVBuf,UVQT_DCT,STD_DC_UV_HT,STD_AC_UV_HT,&vDC);}else{break;}}} }

版权声明:本文为博主原创文章,未经博主允许不得转载。

你爱我吗?已经爱到危险的程度了.危险到什么程度?已经不能一个人生活。

BMP转JPG(法二)RGB数据经过YUV交织

相关文章:

你感兴趣的文章:

标签云: