- 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;
-
- 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;
-
- if(temp>255)
-
- temp = 255L;
-
- AllQualTabls[quality-1][64+i]=(UINT16) temp;
-
- }
-
- }
-
- }
-
- }
3:遍历上述所得二维数组与所得量化表进行匹配,得到质量因子
- for(int tmp=99;tmp>=0;tmp--)
-
- {
-
- for(int j=0;j<128;j++)
-
- {
-
- if( (QualTabl[j]==AllQualTabls[tmp][j])&&(j==127))
-
- {
-
-
-
- count++;
-
- 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)
-
- {
-
-
-
- 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");
-
-
-
- if(openJpeg==NULL)
-
- {
-
- printf("error: cannot open the file\n");
-
- return NULL;
-
- }
-
-
-
- jpeg_stdio_src(&cinfo, openJpeg);
-
- jpeg_read_header(&cinfo, TRUE);
-
- 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);
-
- 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);
-
-
-
- for(int i=0;i< cinfo.output_width;i++)
-
- {
-
- 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__
-
-
-
- #endif
-
- }
-
-
-
- }
-
-
-
- GetQualityTabl(&cinfo,QualTabl,1);
-
-
-
- *Factor=GetFactor(QualTabl,AllQualTabls,Q_FACTOR);
-
-
-
-
-
- jpeg_finish_decompress(&cinfo);
-
-
-
- jpeg_destroy_decompress(&cinfo);
-
-
-
- free(jpgbuf);
-
- fclose(openJpeg);
-
- return data;
-
-
-
- }
2:遍历寻找质量因子
- int GetFactor(int QualTabl[128],int AllQualTabls[100][128],int testFactor)
-
- {
-
-
-
-
-
-
- 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;
-
-
- int count=0;
-
- int final=-2;
-
-
-
-
-
- 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;
-
- 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;
-
- if(temp>255)
-
- temp = 255L;
-
- AllQualTabls[quality-1][64+i]=(UINT16) temp;
-
- }
-
- }
-
- }
-
- }
-
-
-
-
-
-
-
-
- for(int tmp=99;tmp>=0;tmp--)
-
- {
-
- for(int j=0;j<128;j++)
-
- {
-
- if( (QualTabl[j]==AllQualTabls[tmp][j])&&(j==127))
-
- {
-
-
-
- count++;
-
- 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);
-
-
-
- if(testFactor<=0)
-
- testFactor=1;
-
- if(testFactor>100)
-
- testFactor=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);
-
- 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;
-
- }
相关阅读:
C 实现BMP 转换为JPG 附源代码
[置顶] C实现jpg转换为BMP 附源文件
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])
-
- {
-
-
-
- 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");
-
- if(openJpeg==NULL)
- {
- printf("error: cannot open the file\n");
- return NULL;
- }
-
- jpeg_stdio_src(&cinfo, openJpeg);
- jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF);
- jpeg_read_header(&cinfo, TRUE);
-
-
-
-
-
- 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]<<" ";}
- }
-
- 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);
- }