应用libjpeg提取jpeg质量因子



基本思路:利用开源库实现对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;

}


相关阅读:

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

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




 



 

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值