应用libjpeg提取jpeg质量因子

http://blog.csdn.net/lzhq28/article/details/7775222

[cpp] view plain copy
 
 print?
  1. 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、声明并初始化解压缩对象,同时制定错误信息管理器

[cpp] view plain copy
 
 print?
  1. struct jpeg_decompress_struct cinfo;  
  2. struct jpeg_error_mgr jerr;  
  3. cinfo.err = jpeg_std_error(&jerr);  
  4. jpeg_create_decompress(&cinfo);  

2、打开jpg图像文件,并指定为解压缩对象的源文件

 

[cpp] view plain copy
 
 print?
  1. FILE *f = fopen(strSourceFileName,"rb");  
  2.   
  3. if (f==NULL)  
[cpp] view plain copy
 
 print?
  1. {  
  2.   
  3.     printf("Open file error! ");  
  4.   
  5.     return;  
[cpp] view plain copy
 
 print?
  1. }  
  2.   
  3. jpeg_stdio_src(&cinfo, f);  

3、读取图像信息

[cpp] view plain copy
 
 print?
  1. jpeg_read_header(&cinfo, TRUE);  

4、根据图像信息申请一个图像缓冲区

[cpp] view plain copy
 
 print?
  1. data = new BYTE [cinfo.image_width*cinfo.image_height*cinfo.num_components];  

5、开始解压缩
 

[cpp] view plain copy
 
 print?
  1. jpeg_start_decompress(&cinfo);  
  2.   
  3. JSAMPROW row_pointer[1];  
  4.   
  5. while (cinfo.output_scanline < cinfo.output_height)  
  6.   
  7. {  
  8.   
  9.     row_pointer[0] = &data[(cinfo.output_height - cinfo.output_scanline-1)*cinfo.image_width*cinfo.num_components];  
  10.   
  11.     jpeg_read_scanlines(&cinfo,row_pointer ,  
  12.   
  13.                            1);  
  14.   
  15. }  
  16.   
  17. jpeg_finish_decompress(&cinfo);  


 

6:获取解压缩后的量化表

[cpp] view plain copy
 
 print?
  1. GetQualityTabl(&cinfo,QualTabl,1);//获取解压缩后的量化表  

7:释放资源

[cpp] view plain copy
 
 print?
  1. jpeg_destroy_decompress(&cinfo);  
  2.   
  3. fclose(f);  

步骤二:根据标准量化表和所提取的量化表求出质量因子

注解:由于质量因子为1到100的整数,所以可以采用遍历的方式查出质量因子

1:在libjpeg库中jcparam.c中复制标准量化表

亮度量化表:  

[cpp] view plain copy
 
 print?
  1. static const unsigned int std_luminance_quant_tbl[64] = {  
  2.   
  3.   16,  11,  10,  16,  24,  40,  51,  61,  
  4.   
  5.   12,  12,  14,  19,  26,  58,  60,  55,  
  6.   
  7.   14,  13,  16,  24,  40,  57,  69,  56,  
  8.   
  9.   14,  17,  22,  29,  51,  87,  80,  62,  
  10.   
  11.   18,  22,  37,  56,  68, 109, 103,  77,  
  12.   
  13.   24,  35,  55,  64,  81, 104, 113,  92,  
  14.   
  15.   49,  64,  78,  87, 103, 121, 120, 101,  
  16.   
  17.   72,  92,  95,  98, 112, 100, 103,  99  
  18.   
  19. };  


色度量化表:

[cpp] view plain copy
 
 print?
  1. static const unsigned int std_chrominance_quant_tbl[64] = {  
  2.   
  3.   17,  18,  24,  47,  99,  99,  99,  99,  
  4.   
  5.   18,  21,  26,  66,  99,  99,  99,  99,  
  6.   
  7.   24,  26,  56,  99,  99,  99,  99,  99,  
  8.   
  9.   47,  66,  99,  99,  99,  99,  99,  99,  
  10.   
  11.   99,  99,  99,  99,  99,  99,  99,  99,  
  12.   
  13.   99,  99,  99,  99,  99,  99,  99,  99,  
  14.   
  15.   99,  99,  99,  99,  99,  99,  99,  99,  
  16.   
  17.   99,  99,  99,  99,  99,  99,  99,  99  
  18.   
  19. };  

2:创建从质量因子从1到100所对应的两种量化表,并将其存入一维数组中(按从左到右,从上到下,先亮度后色度的顺序进行存储),其中对质量因子的量化表和质量因子的关系请预读jcparam.c中的jpeg_set_quality()和jpeg_add_quant_table()函数。

[cpp] view plain copy
 
 print?
  1. for(int quality=1;quality<=100;quality++)  
  2.   
  3. {  
  4.   
  5.         if(quality<=0)  
  6.   
  7.                quality = 1;  
  8.   
  9.         if(quality > 100)  
  10.   
  11.                quality = 100;  
  12.   
  13.         if(quality<50)  
  14.   
  15.                scale_factor=5000 / quality;  
  16.   
  17.         else   
  18.   
  19.                scale_factor= 200 - quality*2;  
  20.   
  21.    
  22.   
  23.         for(int j=0;j<2;j++)  
  24.   
  25.         {  
  26.   
  27.                for(int i=0;i<64;i++)  
  28.   
  29.                {  
  30.   
  31.           
  32.   
  33.                        if(j==0)  
  34.   
  35.                        {  
  36.   
  37.                                temp=((long) std_luminance_quant_tbl[i]*scale_factor+ 50L)/100L;  
  38.   
  39.                                if (temp <= 0L) temp = 1L;  
  40.   
  41.                                if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */  
  42.   
  43.                                if(temp>255)  
  44.   
  45.                                   temp = 255L;  
  46.   
  47.                                AllQualTabls[quality-1][i]=(UINT16) temp;  
  48.   
  49.                        }  
  50.   
  51.                        if(j==1)  
  52.   
  53.                        {  
  54.   
  55.                                temp=((long) std_chrominance_quant_tbl[i]*scale_factor+ 50L)/100L;  
  56.   
  57.                                if (temp <= 0L) temp = 1L;  
  58.   
  59.                                if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */  
  60.   
  61.                                if(temp>255)  
  62.   
  63.                                   temp = 255L;  
  64.   
  65.                                AllQualTabls[quality-1][64+i]=(UINT16) temp;  
  66.   
  67.                        }  
  68.   
  69.                }  
  70.   
  71.         }  
  72.   
  73. }  



3:遍历上述所得二维数组与所得量化表进行匹配,得到质量因子

[cpp] view plain copy
 
 print?
  1. for(int tmp=99;tmp>=0;tmp--)//逆序寻找,因为一般质量因子都大于50  
  2.   
  3. {  
  4.   
  5.         for(int j=0;j<128;j++)  
  6.   
  7.         {  
  8.   
  9.                if( (QualTabl[j]==AllQualTabls[tmp][j])&&(j==127))  
  10.   
  11.                {  
  12.   
  13.                        //Q_Factor=tmp;  
  14.   
  15.                        count++;//满足条件的质量因子的数量加1  
  16.   
  17.                        if(tmp>final)//选择最大满足条件的最大的质量因子  
  18.   
  19.                                final=tmp;  
  20.   
  21.                }  
  22.   
  23.                else if(QualTabl[j]!=AllQualTabls[tmp][j])  
  24.   
  25.                        break;//发现不相等的项将跳出该循环进入下一个循环(质量因子不同)。  
  26.   
  27.    
  28.   
  29.         }  
  30.   
  31. }  


 

源程序:

1:解压缩JPEG图片

[cpp] view plain copy
 
 print?
  1. unsigned char * DeJpeg(char * JpegName,int QualTabl[128],int AllQualTabls[100][128],int *Factor)//解压jpeg格式图片并显示相应的量化表,并已指针参数形式传递Factor的值,并返回RGB(unsigned char)数据的指针  
  2.   
  3. {  
  4.   
  5.    
  6.   
  7.         FILE *openJpeg;  
  8.   
  9.         unsigned char *data;   //存放解压后的数据  
  10.   
  11.         unsigned char *jpgbuf;      //存放解压后一行图像数据  
  12.   
  13.         int row_stride;        //定义每行的字节数  
  14.   
  15.         struct jpeg_decompress_struct cinfo;  
  16.   
  17.     struct jpeg_error_mgr jerr;  
  18.   
  19.         cinfo.err = jpeg_std_error(&jerr);  
  20.   
  21.         jpeg_create_decompress(&cinfo);//声明并初始化解压缩对象  
  22.   
  23.    
  24.   
  25.         openJpeg=fopen(JpegName,"rb");//二进制模式读取jpeg文件  
  26.   
  27.    
  28.   
  29.         if(openJpeg==NULL) //二进制模式读取  
  30.   
  31.         {  
  32.   
  33.                printf("error: cannot open  the file ");  
  34.   
  35.                return NULL;  
  36.   
  37.         }//打开jpeg图片  
  38.   
  39.    
  40.   
  41.         jpeg_stdio_src(&cinfo, openJpeg);//指定解压对象的源文件  
  42.   
  43.         jpeg_read_header(&cinfo, TRUE);//读取文件信息,将图像的缺省的信息填充到cinfo结构中比便程序使用  
  44.   
  45.         jpeg_start_decompress(&cinfo);//开始接压缩  
  46.   
  47.           
  48.   
  49.         data=(unsigned char *)malloc(cinfo.output_width* cinfo.output_components*cinfo.output_width);//动态分配数据存储内存  
  50.   
  51.         memset(data,0,cinfo.output_width*cinfo.output_width*cinfo.output_components);//设置图像数据初值为0  
  52.   
  53.         jpgbuf = (unsigned char *) malloc(cinfo.output_width *cinfo.output_components);//动态分配缓存内存  
  54.   
  55.         memset(jpgbuf,0,cinfo.output_width*cinfo.output_components);//为缓存内存设置初值  
  56.   
  57.    
  58.   
  59.         row_stride = cinfo.output_width * cinfo.output_components; //计算每行所需的空间,字节为单位  
  60.   
  61.         while (cinfo.output_scanline < cinfo.output_height)  
  62.   
  63.         {  
  64.   
  65.                int line=cinfo.output_scanline;//当前行数  
  66.   
  67.    
  68.   
  69.                (void) jpeg_read_scanlines(&cinfo, &jpgbuf, 1);//执行该操作读取第line行数据,cinfo.output_scanline将加一,指向下一个要扫描的行  
  70.   
  71.    
  72.   
  73.                for(int i=0;i< cinfo.output_width;i++)//循环将存储在jpgbuf缓存区的数据放入data中  
  74.   
  75.                        {         
  76.   
  77.                                data[line*row_stride+i*cinfo.output_components+0]=jpgbuf[i*3];  
  78.   
  79.                                data[line*row_stride+i*cinfo.output_components+1]=jpgbuf[i*3+1];  
  80.   
  81.                                data[line*row_stride+i*cinfo.output_components+2]=jpgbuf[i*3+2];  
  82.   
  83. #ifdef DEBUG__  
  84.   
  85.         //printf("(%d,%d,%d),(%d,%d)",jpgbuf[i*3],jpgbuf[i*3+1],jpgbuf[i*3+2],line,i);//打印图像数据  
  86.   
  87. #endif     
  88.   
  89.                         }  
  90.   
  91.    
  92.   
  93.         }  
  94.   
  95.    
  96.   
  97.         GetQualityTabl(&cinfo,QualTabl,1);//获取解压缩后的量化表  
  98.   
  99.    
  100.   
  101.         *Factor=GetFactor(QualTabl,AllQualTabls,Q_FACTOR);//获取质量因子  
  102.   
  103.    
  104.   
  105.    
  106.   
  107.         jpeg_finish_decompress(&cinfo);//完成解压过程  
  108.   
  109.           
  110.   
  111.         jpeg_destroy_decompress(&cinfo);//释放cinfo  
  112.   
  113.    
  114.   
  115.         free(jpgbuf);//释放缓存  
  116.   
  117.         fclose(openJpeg);  
  118.   
  119.         return data;  
  120.   
  121.    
  122.   
  123. }  



2:遍历寻找质量因子

[cpp] view plain copy
 
 print?
  1. int GetFactor(int QualTabl[128],int AllQualTabls[100][128],int testFactor)//通过将得到的向量表(以一维维数组存储)和实验中所有情况的数组进行匹配(????是否存在与多个数组相匹配情况)  
  2.   
  3. {  
  4.   
  5.    
  6.   
  7.           
  8.   
  9. /* These are the sample quantization tables given in JPEG spec section K.1. 
  10.  
  11.  * The spec says that the values given produce "good" quality, and 
  12.  
  13.  * when divided by 2, "very good" quality. 
  14.  
  15.  */  
  16.   
  17. static const unsigned int std_luminance_quant_tbl[64] = {  
  18.   
  19.   16,  11,  10,  16,  24,  40,  51,  61,  
  20.   
  21.   12,  12,  14,  19,  26,  58,  60,  55,  
  22.   
  23.   14,  13,  16,  24,  40,  57,  69,  56,  
  24.   
  25.   14,  17,  22,  29,  51,  87,  80,  62,  
  26.   
  27.   18,  22,  37,  56,  68, 109, 103,  77,  
  28.   
  29.   24,  35,  55,  64,  81, 104, 113,  92,  
  30.   
  31.   49,  64,  78,  87, 103, 121, 120, 101,  
  32.   
  33.   72,  92,  95,  98, 112, 100, 103,  99  
  34.   
  35. };  
  36.   
  37. static const unsigned int std_chrominance_quant_tbl[64] = {  
  38.   
  39.   17,  18,  24,  47,  99,  99,  99,  99,  
  40.   
  41.   18,  21,  26,  66,  99,  99,  99,  99,  
  42.   
  43.   24,  26,  56,  99,  99,  99,  99,  99,  
  44.   
  45.   47,  66,  99,  99,  99,  99,  99,  99,  
  46.   
  47.   99,  99,  99,  99,  99,  99,  99,  99,  
  48.   
  49.   99,  99,  99,  99,  99,  99,  99,  99,  
  50.   
  51.   99,  99,  99,  99,  99,  99,  99,  99,  
  52.   
  53.   99,  99,  99,  99,  99,  99,  99,  99  
  54.   
  55. };  
  56.   
  57. long temp;//存储临时的质量因子  
  58.   
  59. int scale_factor=0;//默认值为0,品质因子最高  
  60.   
  61. //int Q_Factor=-1;//寻找到的质量因子,默认值为-1,表示没找到  
  62.   
  63. int count=0;//记录量化表相同的质量因子的个数  
  64.   
  65. int final=-2;//如果有多个质量因子满足条件,将选择最大的那个。-1表示没找到  
  66.   
  67.    
  68.   
  69.    
  70.   
  71. for(int quality=1;quality<=100;quality++)  
  72.   
  73. {  
  74.   
  75.         if(quality<=0)  
  76.   
  77.                quality = 1;  
  78.   
  79.         if(quality > 100)  
  80.   
  81.                quality = 100;  
  82.   
  83.         if(quality<50)  
  84.   
  85.                scale_factor=5000 / quality;  
  86.   
  87.         else   
  88.   
  89.                scale_factor= 200 - quality*2;  
  90.   
  91.    
  92.   
  93.         for(int j=0;j<2;j++)  
  94.   
  95.         {  
  96.   
  97.                for(int i=0;i<64;i++)  
  98.   
  99.                {  
  100.   
  101.           
  102.   
  103.                        if(j==0)  
  104.   
  105.                        {  
  106.   
  107.                                temp=((long) std_luminance_quant_tbl[i]*scale_factor+ 50L)/100L;  
  108.   
  109.                                if (temp <= 0L) temp = 1L;  
  110.   
  111.                                if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */  
  112.   
  113.                                if(temp>255)  
  114.   
  115.                                   temp = 255L;  
  116.   
  117.                                AllQualTabls[quality-1][i]=(UINT16) temp;  
  118.   
  119.                        }  
  120.   
  121.                        if(j==1)  
  122.   
  123.                        {  
  124.   
  125.                                temp=((long) std_chrominance_quant_tbl[i]*scale_factor+ 50L)/100L;  
  126.   
  127.                                if (temp <= 0L) temp = 1L;  
  128.   
  129.                                if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */  
  130.   
  131.                                if(temp>255)  
  132.   
  133.                                   temp = 255L;  
  134.   
  135.                                AllQualTabls[quality-1][64+i]=(UINT16) temp;  
  136.   
  137.                        }  
  138.   
  139.                }  
  140.   
  141.         }  
  142.   
  143. }  
  144.   
  145. //int testNum=testFactor-1;  
  146.   
  147.    
  148.   
  149.    
  150.   
  151.    
  152.   
  153. for(int tmp=99;tmp>=0;tmp--)//逆序寻找,因为一般质量因子都大于50  
  154.   
  155. {  
  156.   
  157.         for(int j=0;j<128;j++)  
  158.   
  159.         {  
  160.   
  161.                if( (QualTabl[j]==AllQualTabls[tmp][j])&&(j==127))  
  162.   
  163.                {  
  164.   
  165.                        //Q_Factor=tmp;  
  166.   
  167.                        count++;//满足条件的质量因子的数量加1  
  168.   
  169.                        if(tmp>final)//选择最大满足条件的最大的质量因子  
  170.   
  171.                                final=tmp;  
  172.   
  173.                }  
  174.   
  175.                else if(QualTabl[j]!=AllQualTabls[tmp][j])  
  176.   
  177.                        break;//发现不相等的项将跳出该循环进入下一个循环(质量因子不同)。  
  178.   
  179.    
  180.   
  181.         }  
  182.   
  183. }  
  184.   
  185. #ifdef DEBUG__  
  186.   
  187. printf("比较得出质量因子为:%d ",final+1);  
  188.   
  189. printf("与之量化表相等所对应的质量因子的个数:%d ",count);  
  190.   
  191. printf("任意键继续 ");  
  192.   
  193. getchar();  
  194.   
  195. #endif  
  196.   
  197.    
  198.   
  199. #ifdef DEBUG__  
  200.   
  201. if(final!=-2)  
  202.   
  203. {  
  204.   
  205.                printf("quantization table of luminance:the quality is %d  ",final+1);//输出CI通道的量化表  
  206.   
  207.    
  208.   
  209.                if(testFactor<=0)  
  210.   
  211.                        testFactor=1;  
  212.   
  213.                if(testFactor>100)  
  214.   
  215.                        testFactor=100;//保障质量因子在1-100之间  
  216.   
  217.    
  218.   
  219.                for (int i = 0; i <64; ++i)  
  220.   
  221.                {  
  222.   
  223.                        printf("% 4d ",  AllQualTabls[final][i]);  
  224.   
  225.                        if ((i + 1) % 8 == 0)  
  226.   
  227.                        printf(" ");  
  228.   
  229.                }  
  230.   
  231.                printf("quantization table of chrominance ,the quality is %d:  ",final+1);//输出CI通道的量化表  
  232.   
  233.                for (int i = 0; i <64; ++i)  
  234.   
  235.                {  
  236.   
  237.                        printf("% 4d ", AllQualTabls[final][64+i]);  
  238.   
  239.                        if ((i + 1) % 8 == 0)  
  240.   
  241.                        printf(" ");  
  242.   
  243.                }  
  244.   
  245.         printf("任意键继续 ");  
  246.   
  247.         getchar();  
  248.   
  249. }  
  250.   
  251. else   
  252.   
  253. {  
  254.   
  255.         printf("没有找到匹配的向量表  任意键继续 ");  
  256.   
  257.           
  258.   
  259.         getchar();  
  260.   
  261. }  
  262.   
  263. #endif  
  264.   
  265.         return final+1;  
  266.   
  267. }  


相关阅读:

C 实现BMP 转换为JPG 附源代码

 [置顶] C实现jpg转换为BMP 附源文件

 
利用Opencv读取JPEG文件的压缩信息(量化表)
http://blog.csdn.net/williams0/article/details/51143582

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的压缩信息,下面粘上代码:

[cpp] view plain copy
 
  1. #include <opencv2/core/core.hpp>  
  2. #include <opencv2/highgui/highgui.hpp>  
  3. #include <opencv2/opencv.hpp>  
  4. #include <stdio.h>  
  5. #include <iostream>  
  6. #include <stdlib.h>  
  7. #include <iostream>  
  8. #include <setjmp.h>  
  9. #include <jerror.h>  
  10. #include <jpeglib.h>  
  11.   
  12. using namespace std;  
  13. using namespace cv;  
  14.   
  15. int DeJpeg(string JpegName,int q_table[64])//解压jpeg格式图片并显示相应的量化表,并已指针参数形式传递Factor的值,并返回RGB(unsigned char)数据的指针  
  16.   
  17. {  
  18.   
  19.   
  20.   
  21.         FILE *openJpeg;  
  22.   
  23.   
  24.   
  25.         struct  jpeg_decompress_struct cinfo;  
  26.         struct jpeg_error_mgr jerr;  
  27.         JQUANT_TBL *quant_ptr;  
  28.   
  29.         cinfo.err = jpeg_std_error(&jerr);  
  30.   
  31.         jpeg_create_decompress(&cinfo);//声明并初始化解压缩对象  
  32.   
  33.         openJpeg=fopen(JpegName.c_str(),"rb");//二进制模式读取jpeg文件  
  34.   
  35.         if(openJpeg==NULL) //二进制模式读取  
  36.         {  
  37.             printf("error: cannot open  the file ");  
  38.               return NULL;  
  39.         }//打开jpeg图片  
  40.   
  41.         jpeg_stdio_src(&cinfo, openJpeg);//指定解压对象的源文件  
  42.         jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF);  
  43.         jpeg_read_header(&cinfo, TRUE);//读取文件信息,将图像的缺省的信息填充到cinfo结构中比便程序使用  
  44.   
  45.         //jpeg_destroy_decompress(&cinfo);//释放cinfo  
  46.   
  47.         //------------------------------------------------------  
  48.         //int q_table[64];  
  49.         if (cinfo.quant_tbl_ptrs[0] != NULL) {  
  50.             quant_ptr = cinfo.quant_tbl_ptrs[0];  
  51.             for (unsigned int i = 0; i < DCTSIZE; i++)  
  52.               for (unsigned int j = 0; j < DCTSIZE; j++){  
  53.                 q_table[j*DCTSIZE+i] = (int) quant_ptr->quantval[i*DCTSIZE+j];  
  54.                 cout<<q_table[j*DCTSIZE+i]<<" ";}  
  55.         }  
  56.         //int QualTabl[128];  
  57.         jpeg_destroy_decompress(&cinfo);  
  58.   
  59.   
  60.         fclose(openJpeg);  
  61.   
  62.         return 1;  
  63.      
  64.   
  65.   
  66.   
  67. }  
  68. int main(){  
  69.     Mat img = imread("./ucid00001.jpg",0);  
  70.   
  71.     int Q_table[64];  
  72.     DeJpeg("./ucid00001.jpg",Q_table);  
  73.     for(int i=0;i<DCTSIZE2;i++){  
  74.         cout<<Q_table[i]<<" ";  
  75.     }  
  76.      imshow("Hi",img);  
  77.     waitKey(0);  
  78. }  
原文地址:https://www.cnblogs.com/jukan/p/7127700.html