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添付ファイルに変換