热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

转载请标明是引用于http:blog.csdn.netchenyujing1234欢迎大家拍砖!源码下载地址:http:download.csdn.netdetailchenyuj

转载请标明是引用于 http://blog.csdn.net/chenyujing1234 

欢迎大家拍砖!

 

源码下载地址:http://download.csdn.net/detail/chenyujing1234/4441643

编译平台: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 {
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信号分别分割为8x8的块
 //********************************************************************
// 方法名称: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 {
n = 0;//复位临时缓冲区偏移量
for (j = 0; j {
bufOffset = yLen * xLen * i * xBufs + j * xLen;//计算单元信号块的首行偏移量
for (k = 0; 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信号的当前块的DC
BYTE 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 {
yCounter = 1;//MCUIndex[SamplingType][0]; //按采样方式初始化各信号计数器
uCounter = 1;//MCUIndex[SamplingType][1];
vCounter = 1;//MCUIndex[SamplingType][2];

for (; i {
for (j = 0; 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 {
for (n = 0; 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 {
for (k = 0; 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;
}
}
}
}


 


推荐阅读
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • 在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的步骤和方法
    本文介绍了在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的详细步骤和方法。首先需要下载最新的Java SE Development Kit 9发行版,然后按照给出的Shell命令行方式进行安装。详细的步骤和方法请参考正文内容。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • WebSocket与Socket.io的理解
    WebSocketprotocol是HTML5一种新的协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 树莓派语音控制的配置方法和步骤
    本文介绍了在树莓派上实现语音控制的配置方法和步骤。首先感谢博主Eoman的帮助,文章参考了他的内容。树莓派的配置需要通过sudo raspi-config进行,然后使用Eoman的控制方法,即安装wiringPi库并编写控制引脚的脚本。具体的安装步骤和脚本编写方法在文章中详细介绍。 ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
author-avatar
手机用户2602929765
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有