libjpegを適用してjpeg質量因子を抽出する




基本構想:オープンソースライブラリを利用してjpegの解凍を実現し、直接量子化テーブルを抽出し、標準量子化テーブルと抽出量子化テーブル作成アルゴリズムに基づいて品質因子の計算を実現する.
ステップ1: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!
"); 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);


ステップ2:標準量子化テーブルと抽出した量子化テーブルから質量因子を求める
注:質量因子は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に対応する2種類の量子化テーブルを作成し、1次元配列に格納します(左から右、上から下、明るさ、色度の順に格納します).質量係数の量子化テーブルと質量係数の関係はjcparam.cのjpeg_をプリフェッチしてください.setquality()と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:上記で得られた2次元配列を遍歴して得られた量子化テーブルと整合し、質量因子を得る
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
"); 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
",final+1); printf(" :%d
",count); printf("
"); getchar(); #endif #ifdef DEBUG__ if(final!=-2) { printf("quantization table of luminance:the quality is %d
",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("
"); } printf("quantization table of chrominance ,the quality is %d:
",final+1);// CI for (int i = 0; i <64; ++i) { printf("% 4d ", AllQualTabls[final][64+i]); if ((i + 1) % 8 == 0) printf("
"); } printf("
"); getchar(); } else { printf("


"); getchar(); } #endif return final+1; }

関連情報:
C BMPからJPGへの変換を実現
 [セットトップ]C実装jpgをBMP添付ファイルに変換