Add optimization of quantization matrix

Optimizes quantization matrix by minimizing reconstruction error based
on quantized coefficients.
Feature is controlled by cinfo->trellis_q_opt; disabled by default.
This commit is contained in:
Frank Bossen
2014-04-28 16:28:05 -04:00
parent e5f8575776
commit b03b5797f4
6 changed files with 43 additions and 5 deletions

View File

@@ -363,7 +363,6 @@ compress_trellis_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
c_derived_tbl actbl_data;
c_derived_tbl *actbl = &actbl_data;
compptr = cinfo->cur_comp_info[ci];
jpeg_make_c_derived_tbl(cinfo, FALSE, compptr->ac_tbl_no, &actbl);
@@ -398,7 +397,7 @@ compress_trellis_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
*/
for (block_row = 0; block_row < block_rows; block_row++) {
thisblockrow = buffer[block_row];
quantize_trellis(cinfo, actbl, thisblockrow, buffer_dst[block_row], blocks_across, cinfo->quant_tbl_ptrs[compptr->quant_tbl_no]);
quantize_trellis(cinfo, actbl, thisblockrow, buffer_dst[block_row], blocks_across, cinfo->quant_tbl_ptrs[compptr->quant_tbl_no], cinfo->norm_src[compptr->quant_tbl_no], cinfo->norm_coef[compptr->quant_tbl_no]);
if (ndummy > 0) {
/* Create dummy blocks at the right edge of the image. */
@@ -435,6 +434,7 @@ compress_trellis_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
}
}
}
/* NB: compress_output will increment iMCU_row_num if successful.
* A suspension return will result in redoing all the work above next time.
*/

View File

@@ -576,7 +576,7 @@ static const float jpeg_lambda_weights_csf_luma[64] = {
GLOBAL(void)
quantize_trellis(j_compress_ptr cinfo, c_derived_tbl *actbl, JBLOCKROW coef_blocks, JBLOCKROW src, JDIMENSION num_blocks,
JQUANT_TBL * qtbl)
JQUANT_TBL * qtbl, double *norm_src, double *norm_coef)
{
int i, j, k;
float accumulated_zero_dist[DCTSIZE2];
@@ -821,6 +821,15 @@ quantize_trellis(j_compress_ptr cinfo, c_derived_tbl *actbl, JBLOCKROW coef_bloc
free(block_run_start);
free(requires_eob);
}
if (cinfo->trellis_q_opt) {
for (bi = 0; bi < num_blocks; bi++) {
for (i = 1; i < DCTSIZE2; i++) {
norm_src[i] += src[bi][i] * coef_blocks[bi][i];
norm_coef[i] += 8 * coef_blocks[bi][i] * coef_blocks[bi][i];
}
}
}
}
/*

View File

@@ -50,4 +50,4 @@ EXTERN(void) jpeg_gen_optimal_table
EXTERN(void) quantize_trellis
JPP((j_compress_ptr cinfo, c_derived_tbl *actbl, JBLOCKROW coef_blocks, JBLOCKROW src, JDIMENSION num_blocks,
JQUANT_TBL * qtbl));
JQUANT_TBL * qtbl, double *norm_src, double *norm_coef));

View File

@@ -550,6 +550,16 @@ prepare_for_pass (j_compress_ptr cinfo)
master->pub.call_pass_startup = FALSE;
break;
case trellis_pass:
if (master->pass_number%(cinfo->num_components*(cinfo->use_scans_in_trellis?4:2)) == 1 && cinfo->trellis_q_opt) {
int i, j;
for (i = 0; i < NUM_QUANT_TBLS; i++) {
for (j = 1; j < DCTSIZE2; j++) {
cinfo->norm_src[i][j] = 0.0;
cinfo->norm_coef[i][j] = 0.0;
}
}
}
(*cinfo->entropy->start_pass) (cinfo, TRUE);
(*cinfo->coef->start_pass) (cinfo, JBUF_REQUANT);
master->pub.call_pass_startup = FALSE;
@@ -838,6 +848,20 @@ finish_pass_master (j_compress_ptr cinfo)
break;
case trellis_pass:
master->pass_type = (cinfo->optimize_scans || master->pass_number < master->pass_number_scan_opt_base-1) ? huff_opt_pass : output_pass;
if ((master->pass_number+1)%(cinfo->num_components*(cinfo->use_scans_in_trellis?4:2)) == 0 && cinfo->trellis_q_opt) {
int i, j;
for (i = 0; i < NUM_QUANT_TBLS; i++) {
for (j = 1; j < DCTSIZE2; j++) {
if (cinfo->norm_coef[i][j] != 0.0) {
int q = (int)(cinfo->norm_src[i][j] / cinfo->norm_coef[i][j] + 0.5);
if (q > 254) q = 254;
if (q < 1) q = 1;
}
}
}
}
break;
}

View File

@@ -433,6 +433,7 @@ jpeg_set_defaults (j_compress_ptr cinfo)
cinfo->use_scans_in_trellis = FALSE;
cinfo->trellis_freq_split = 8;
cinfo->trellis_num_loops = 1;
cinfo->trellis_q_opt = FALSE;
}

View File

@@ -384,6 +384,10 @@ struct jpeg_compress_struct {
boolean use_lambda_weight_tbl; /* TRUE=use lambda weighting table */
boolean use_scans_in_trellis; /* TRUE=use scans in trellis optimization */
boolean trellis_passes; /* TRUE=currently doing trellis-related passes */
boolean trellis_q_opt; /* TRUE=optimize quant table in trellis loop */
double norm_src[NUM_QUANT_TBLS][DCTSIZE2];
double norm_coef[NUM_QUANT_TBLS][DCTSIZE2];
int trellis_freq_split; /* splitting point for frequency in trellis quantization */
int trellis_num_loops; /* number of trellis loops */