应用libjpeg提取jpeg质量因子
http://blog.csdn.net/lzhq28/article/details/7775222
版权声明:本文为博主原创文章,未经博主允许不得转载。
- data = new BYTE [cinfo.image_width*cinfo.image_height*cinfo.num_components];
基本思路:利用开源库实现对jpeg的解压缩以直接提取量化表,根据标准量化表和所提取量化表编写算法实现质量因子的求算。
步骤一:使用libjpeg库实现对jpeg的解压缩并提取量化表
参照:http://www.vckbase.com/index.php/wv/1488.html
步骤如下:
1、声明并初始化解压缩对象,同时制定错误信息管理器
- struct jpeg_decompress_struct cinfo;
- struct jpeg_error_mgr jerr;
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_decompress(&cinfo);
2、打开jpg图像文件,并指定为解压缩对象的源文件
- FILE *f = fopen(strSourceFileName,"rb");
- if (f==NULL)
- {
- printf("Open file error!\n");
- return;
- }
- jpeg_stdio_src(&cinfo, f);
3、读取图像信息
- jpeg_read_header(&cinfo, TRUE);
4、根据图像信息申请一个图像缓冲区
- data = new BYTE [cinfo.image_width*cinfo.image_height*cinfo.num_components];
5、开始解压缩
- jpeg_start_decompress(&cinfo);
- JSAMPROW row_pointer[1];
- while (cinfo.output_scanline < cinfo.output_height)
- {
- row_pointer[0] = &data[(cinfo.output_height - cinfo.output_scanline-1)*cinfo.image_width*cinfo.num_components];
- jpeg_read_scanlines(&cinfo,row_pointer ,
- 1);
- }
- jpeg_finish_decompress(&cinfo);
6:获取解压缩后的量化表
- GetQualityTabl(&cinfo,QualTabl,1);//获取解压缩后的量化表
7:释放资源
- jpeg_destroy_decompress(&cinfo);
- fclose(f);
步骤二:根据标准量化表和所提取的量化表求出质量因子
注解:由于质量因子为1到100的整数,所以可以采用遍历的方式查出质量因子
1:在libjpeg库中jcparam.c中复制标准量化表
亮度量化表:
- static const unsigned int std_luminance_quant_tbl[64] = {
- 16, 11, 10, 16, 24, 40, 51, 61,
- 12, 12, 14, 19, 26, 58, 60, 55,
- 14, 13, 16, 24, 40, 57, 69, 56,
- 14, 17, 22, 29, 51, 87, 80, 62,
- 18, 22, 37, 56, 68, 109, 103, 77,
- 24, 35, 55, 64, 81, 104, 113, 92,
- 49, 64, 78, 87, 103, 121, 120, 101,
- 72, 92, 95, 98, 112, 100, 103, 99
- };
色度量化表:
- static const unsigned int std_chrominance_quant_tbl[64] = {
- 17, 18, 24, 47, 99, 99, 99, 99,
- 18, 21, 26, 66, 99, 99, 99, 99,
- 24, 26, 56, 99, 99, 99, 99, 99,
- 47, 66, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99
- };
2:创建从质量因子从1到100所对应的两种量化表,并将其存入一维数组中(按从左到右,从上到下,先亮度后色度的顺序进行存储),其中对质量因子的量化表和质量因子的关系请预读jcparam.c中的jpeg_set_quality()和jpeg_add_quant_table()函数。
- for(int quality=1;quality<=100;quality++)
- {
- if(quality<=0)
- quality = 1;
- if(quality > 100)
- quality = 100;
- if(quality<50)
- scale_factor=5000 / quality;
- else
- scale_factor= 200 - quality*2;
- for(int j=0;j<2;j++)
- {
- for(int i=0;i<64;i++)
- {
- if(j==0)
- {
- temp=((long) std_luminance_quant_tbl[i]*scale_factor+ 50L)/100L;
- if (temp <= 0L) temp = 1L;
- if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */
- if(temp>255)
- temp = 255L;
- AllQualTabls[quality-1][i]=(UINT16) temp;
- }
- if(j==1)
- {
- temp=((long) std_chrominance_quant_tbl[i]*scale_factor+ 50L)/100L;
- if (temp <= 0L) temp = 1L;
- if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */
- if(temp>255)
- temp = 255L;
- AllQualTabls[quality-1][64+i]=(UINT16) temp;
- }
- }
- }
- }
3:遍历上述所得二维数组与所得量化表进行匹配,得到质量因子
- for(int tmp=99;tmp>=0;tmp--)//逆序寻找,因为一般质量因子都大于50
- {
- for(int j=0;j<128;j++)
- {
- if( (QualTabl[j]==AllQualTabls[tmp][j])&&(j==127))
- {
- //Q_Factor=tmp;
- count++;//满足条件的质量因子的数量加1
- if(tmp>final)//选择最大满足条件的最大的质量因子
- final=tmp;
- }
- else if(QualTabl[j]!=AllQualTabls[tmp][j])
- break;//发现不相等的项将跳出该循环进入下一个循环(质量因子不同)。
- }
- }
源程序:
1:解压缩JPEG图片
- unsigned char * DeJpeg(char * JpegName,int QualTabl[128],int AllQualTabls[100][128],int *Factor)//解压jpeg格式图片并显示相应的量化表,并已指针参数形式传递Factor的值,并返回RGB(unsigned char)数据的指针
- {
- FILE *openJpeg;
- unsigned char *data; //存放解压后的数据
- unsigned char *jpgbuf; //存放解压后一行图像数据
- int row_stride; //定义每行的字节数
- struct jpeg_decompress_struct cinfo;
- struct jpeg_error_mgr jerr;
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_decompress(&cinfo);//声明并初始化解压缩对象
- openJpeg=fopen(JpegName,"rb");//二进制模式读取jpeg文件
- if(openJpeg==NULL) //二进制模式读取
- {
- printf("error: cannot open the file\n");
- return NULL;
- }//打开jpeg图片
- jpeg_stdio_src(&cinfo, openJpeg);//指定解压对象的源文件
- jpeg_read_header(&cinfo, TRUE);//读取文件信息,将图像的缺省的信息填充到cinfo结构中比便程序使用
- jpeg_start_decompress(&cinfo);//开始接压缩
- data=(unsigned char *)malloc(cinfo.output_width* cinfo.output_components*cinfo.output_width);//动态分配数据存储内存
- memset(data,0,cinfo.output_width*cinfo.output_width*cinfo.output_components);//设置图像数据初值为0
- jpgbuf = (unsigned char *) malloc(cinfo.output_width *cinfo.output_components);//动态分配缓存内存
- memset(jpgbuf,0,cinfo.output_width*cinfo.output_components);//为缓存内存设置初值
- row_stride = cinfo.output_width * cinfo.output_components; //计算每行所需的空间,字节为单位
- while (cinfo.output_scanline < cinfo.output_height)
- {
- int line=cinfo.output_scanline;//当前行数
- (void) jpeg_read_scanlines(&cinfo, &jpgbuf, 1);//执行该操作读取第line行数据,cinfo.output_scanline将加一,指向下一个要扫描的行
- for(int i=0;i< cinfo.output_width;i++)//循环将存储在jpgbuf缓存区的数据放入data中
- {
- data[line*row_stride+i*cinfo.output_components+0]=jpgbuf[i*3];
- data[line*row_stride+i*cinfo.output_components+1]=jpgbuf[i*3+1];
- data[line*row_stride+i*cinfo.output_components+2]=jpgbuf[i*3+2];
- #ifdef DEBUG__
- //printf("(%d,%d,%d),(%d,%d)",jpgbuf[i*3],jpgbuf[i*3+1],jpgbuf[i*3+2],line,i);//打印图像数据
- #endif
- }
- }
- GetQualityTabl(&cinfo,QualTabl,1);//获取解压缩后的量化表
- *Factor=GetFactor(QualTabl,AllQualTabls,Q_FACTOR);//获取质量因子
- jpeg_finish_decompress(&cinfo);//完成解压过程
- jpeg_destroy_decompress(&cinfo);//释放cinfo
- free(jpgbuf);//释放缓存
- fclose(openJpeg);
- return data;
- }
2:遍历寻找质量因子
- int GetFactor(int QualTabl[128],int AllQualTabls[100][128],int testFactor)//通过将得到的向量表(以一维维数组存储)和实验中所有情况的数组进行匹配(????是否存在与多个数组相匹配情况)
- {
- /* These are the sample quantization tables given in JPEG spec section K.1.
- * The spec says that the values given produce "good" quality, and
- * when divided by 2, "very good" quality.
- */
- static const unsigned int std_luminance_quant_tbl[64] = {
- 16, 11, 10, 16, 24, 40, 51, 61,
- 12, 12, 14, 19, 26, 58, 60, 55,
- 14, 13, 16, 24, 40, 57, 69, 56,
- 14, 17, 22, 29, 51, 87, 80, 62,
- 18, 22, 37, 56, 68, 109, 103, 77,
- 24, 35, 55, 64, 81, 104, 113, 92,
- 49, 64, 78, 87, 103, 121, 120, 101,
- 72, 92, 95, 98, 112, 100, 103, 99
- };
- static const unsigned int std_chrominance_quant_tbl[64] = {
- 17, 18, 24, 47, 99, 99, 99, 99,
- 18, 21, 26, 66, 99, 99, 99, 99,
- 24, 26, 56, 99, 99, 99, 99, 99,
- 47, 66, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99
- };
- long temp;//存储临时的质量因子
- int scale_factor=0;//默认值为0,品质因子最高
- //int Q_Factor=-1;//寻找到的质量因子,默认值为-1,表示没找到
- int count=0;//记录量化表相同的质量因子的个数
- int final=-2;//如果有多个质量因子满足条件,将选择最大的那个。-1表示没找到
- for(int quality=1;quality<=100;quality++)
- {
- if(quality<=0)
- quality = 1;
- if(quality > 100)
- quality = 100;
- if(quality<50)
- scale_factor=5000 / quality;
- else
- scale_factor= 200 - quality*2;
- for(int j=0;j<2;j++)
- {
- for(int i=0;i<64;i++)
- {
- if(j==0)
- {
- temp=((long) std_luminance_quant_tbl[i]*scale_factor+ 50L)/100L;
- if (temp <= 0L) temp = 1L;
- if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */
- if(temp>255)
- temp = 255L;
- AllQualTabls[quality-1][i]=(UINT16) temp;
- }
- if(j==1)
- {
- temp=((long) std_chrominance_quant_tbl[i]*scale_factor+ 50L)/100L;
- if (temp <= 0L) temp = 1L;
- if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */
- if(temp>255)
- temp = 255L;
- AllQualTabls[quality-1][64+i]=(UINT16) temp;
- }
- }
- }
- }
- //int testNum=testFactor-1;
- for(int tmp=99;tmp>=0;tmp--)//逆序寻找,因为一般质量因子都大于50
- {
- for(int j=0;j<128;j++)
- {
- if( (QualTabl[j]==AllQualTabls[tmp][j])&&(j==127))
- {
- //Q_Factor=tmp;
- count++;//满足条件的质量因子的数量加1
- if(tmp>final)//选择最大满足条件的最大的质量因子
- final=tmp;
- }
- else if(QualTabl[j]!=AllQualTabls[tmp][j])
- break;//发现不相等的项将跳出该循环进入下一个循环(质量因子不同)。
- }
- }
- #ifdef DEBUG__
- printf("比较得出质量因子为:%d\n",final+1);
- printf("与之量化表相等所对应的质量因子的个数:%d\n",count);
- printf("任意键继续\n");
- getchar();
- #endif
- #ifdef DEBUG__
- if(final!=-2)
- {
- printf("quantization table of luminance:the quality is %d \n",final+1);//输出CI通道的量化表
- if(testFactor<=0)
- testFactor=1;
- if(testFactor>100)
- testFactor=100;//保障质量因子在1-100之间
- for (int i = 0; i <64; ++i)
- {
- printf("% 4d ", AllQualTabls[final][i]);
- if ((i + 1) % 8 == 0)
- printf("\n");
- }
- printf("quantization table of chrominance ,the quality is %d: \n",final+1);//输出CI通道的量化表
- for (int i = 0; i <64; ++i)
- {
- printf("% 4d ", AllQualTabls[final][64+i]);
- if ((i + 1) % 8 == 0)
- printf("\n");
- }
- printf("任意键继续\n");
- getchar();
- }
- else
- {
- printf("没有找到匹配的向量表\n\n 任意键继续\n");
- getchar();
- }
- #endif
- return final+1;
- }
相关阅读:
OpenCV(Open Source Computer Vision Library)是一个强大的开源计算机视觉库,里面包含了许多非常有用的图像处理算法,由于在学习中需要提取JPEG图像文件的压缩信息,比如压缩的量化表、量化的DCT系数矩阵等。一开始我使用的是最新的libjpeg(IJG9)和opencv,在使用时发现两者会有冲突,原因是opencv的一些读入图像的函数会调用libjpeg,调用的libjpeg(libjpeg6.2)被集成在opencv中,而加载libjpeg9.2时会和libjpeg6.2冲突,故运行程序时经常弹出libjpeg版本错误的信息 。
为解决这个问题,我调用opencv中的libjpeg来读取jpeg的压缩信息,下面粘上代码:
- #include <opencv2/core/core.hpp>
- #include <opencv2/highgui/highgui.hpp>
- #include <opencv2/opencv.hpp>
- #include <stdio.h>
- #include <iostream>
- #include <stdlib.h>
- #include <iostream>
- #include <setjmp.h>
- #include <jerror.h>
- #include <jpeglib.h>
- using namespace std;
- using namespace cv;
- int DeJpeg(string JpegName,int q_table[64])//解压jpeg格式图片并显示相应的量化表,并已指针参数形式传递Factor的值,并返回RGB(unsigned char)数据的指针
- {
- FILE *openJpeg;
- struct jpeg_decompress_struct cinfo;
- struct jpeg_error_mgr jerr;
- JQUANT_TBL *quant_ptr;
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_decompress(&cinfo);//声明并初始化解压缩对象
- openJpeg=fopen(JpegName.c_str(),"rb");//二进制模式读取jpeg文件
- if(openJpeg==NULL) //二进制模式读取
- {
- printf("error: cannot open the file\n");
- return NULL;
- }//打开jpeg图片
- jpeg_stdio_src(&cinfo, openJpeg);//指定解压对象的源文件
- jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF);
- jpeg_read_header(&cinfo, TRUE);//读取文件信息,将图像的缺省的信息填充到cinfo结构中比便程序使用
- //jpeg_destroy_decompress(&cinfo);//释放cinfo
- //------------------------------------------------------
- //int q_table[64];
- if (cinfo.quant_tbl_ptrs[0] != NULL) {
- quant_ptr = cinfo.quant_tbl_ptrs[0];
- for (unsigned int i = 0; i < DCTSIZE; i++)
- for (unsigned int j = 0; j < DCTSIZE; j++){
- q_table[j*DCTSIZE+i] = (int) quant_ptr->quantval[i*DCTSIZE+j];
- cout<<q_table[j*DCTSIZE+i]<<" ";}
- }
- //int QualTabl[128];
- jpeg_destroy_decompress(&cinfo);
- fclose(openJpeg);
- return 1;
- }
- int main(){
- Mat img = imread("./ucid00001.jpg",0);
- int Q_table[64];
- DeJpeg("./ucid00001.jpg",Q_table);
- for(int i=0;i<DCTSIZE2;i++){
- cout<<Q_table[i]<<" ";
- }
- imshow("Hi",img);
- waitKey(0);
- }
应用libjpeg提取jpeg质量因子的更多相关文章
- Android图片编码机制深度解析(Bitmap,Skia,libJpeg)
问题 工作中遇到了Android中有关图片压缩保存的问题,发现这个问题还挺深,而且网上资料比较有限,因此自己深入研究了一下,算是把这个问题自顶至下全部搞懂了,在此记录. 相关的几个问题如下: 1.An ...
- 在NVIDIA A100 GPU上利用硬件JPEG解码器和NVIDIA nvJPEG库
在NVIDIA A100 GPU上利用硬件JPEG解码器和NVIDIA nvJPEG库 根据调查,普通人产生的1.2万亿张图像可以通过电话或数码相机捕获.这样的图像的存储,尤其是以高分辨率的原始格式, ...
- NVIDIA A100 GPUs上硬件JPEG解码器和NVIDIA nvJPEG库
NVIDIA A100 GPUs上硬件JPEG解码器和NVIDIA nvJPEG库 Leveraging the Hardware JPEG Decoder and NVIDIA nvJPEG Lib ...
- (转)JPEG图片数据结构分析- 附Png数据格式详解.doc
一.简述 JPEG是一个压缩标准,又可分为标准JPEG.渐进式JPEG及JPEG2000三种: ①标准JPEG:以24位颜色存储单个光栅图像,是与平台无关的格式,支持最高级别的压缩,不过,这种压 ...
- jpeg了解
JPEG是一个压缩标准,又可分为标准 JPEG.渐进式JPEG及JPEG2000三种: ①标准JPEG:以24位颜色存储单个光栅图像,是与平台无关的格式,支持最高级 别的压缩,不过,这种压缩是有损耗的 ...
- 图像JPEG格式介绍
1 JPG格式介绍 JPEG (Joint PhotographicExperts GROUP)是由国际标准组织和国际电话电报咨询委员会为静态图像所建立的第一个国际数字图像压缩标准,也是至今一直在使用 ...
- libjpeg用法
libjpeg是一个完全用C语言编写的库,包含了被广泛使用的JPEG解码.JPEG编码和其他的JPEG功能的实现.这个库由独立JPEG工作组维护.最新版本号是6b,于1998年发布.可以参考维基百科关 ...
- 美国usan数据库——PDF提取
QQ:231469242 原创 单个PDF内容提取 # -*- coding: utf-8 -*- """ io.open() is the preferred, hig ...
- JPEG最优压缩参数试验【光影魔术手VS Image Optimizer】
样本数量:100张(1MB-2.6MB)旅游照 样本大小:157MB 156.44 样本尺寸:3M(204 ...
随机推荐
- vue2.0非父子间进行通讯
在vue中,父组件向之组件通讯使用的是props,子组件向父组件通讯使用的是$emit+事件,那非父子间的通讯呢,在官方文档上只有寥寥数笔, 概念很模糊,这个空的vue实例应该放在哪里呢,光放文档并没 ...
- skeleton
响应式模版 伯乐在线:http://hao.jobbole.com/skeleton/ cdn : https://cdn.bootcss.com/skeleton/2.0.4/skeleton.c ...
- 【BZOJ3195】[Jxoi2012]奇怪的道路 状压DP
[BZOJ3195][Jxoi2012]奇怪的道路 Description 小宇从历史书上了解到一个古老的文明.这个文明在各个方面高度发达,交通方面也不例外.考古学家已经知道,这个文明在全盛时期有n座 ...
- 【BZOJ1895】Pku3580 supermemo Splay
[BZOJ1895]Pku3580 supermemo Description 给出一个初始序列fA1;A2;:::Ang,要求你编写程序支持如下操作: 1. ADDxyD:给子序列fAx:::Ayg ...
- LAMP集群项目四 安装apache、php及其插件
rpm -qa httpd* 查看是否有apache rpm -e httpd-2.2.22.2 卸载该文件,如果不让卸载,则加参数:--nodeps 不做软件中的依赖检查 ./configure ...
- 用wamp实现前端和php的交互效果
我们今天来用php来做一下前台与后台的交互效果,首先我们先打开这个软件. 看一下电脑右下角的小图标 当变成之后鼠标左键 打开这个之后点击第二个之后会打开一个网站 点击右面页面的数据库打开新建数据库,填 ...
- Spring AOP和事务的相关陷阱
1.前言 2.嵌套方法拦截失效 2.1 问题场景 2.2 解决方案 2.3 原因分析 2.3.1 原理 2.3.2 源代码分析 3.Spring事务在多线程环境下失效 3.1 问题场景 3.2 解决方 ...
- 前端开发 - JavaScript - 上
1.js引入 <!DOCTYPE html> <html lang="cn"> <head> <meta charset="UT ...
- web前端 微信支付之H5支付
一.什么是微信H5支付? 微信,简直是21世纪的社交产品之最.人们的生活已经离不开它,因为它的触角广泛蔓延像一张巨大无形的网,从而让我们的生活更加便捷高效,这款社交工具我们不做过多评价,但是我们要通过 ...
- MySQL优化(三):优化数据库对象
二.优化数据库对象 1.优化表的数据类型 应用设计的时候需要考虑字段的长度留有一定的冗余,但不推荐很多字段都留有大量的冗余,这样既浪费磁盘空间,也在应用操作时浪费物理内存. 在MySQL中,可以使用函 ...