Auto select noise synthesis level for all intra Add code to estimate the noise level in a still image and choose a noise synthesis level. The auto selection of the noise synthesis level will only occur where --allintra is set on the command line and --denoise-noise-level > 0. Also on the command line: if --enable-dnl-denoising=1 then the source image will also be filtered. If --enable-dnl-denoising=0 then the source image will not be filtered. Filtering of the source image is much more likely to cause some loss fine detail if a strong filter level is chosen and is not recommended. Adjustment from previous patch increases filtering on some images where subjective evaluation said it was too low and reduced it on some high complexity images where it was too high (by lowering the edge threshold). Change-Id: I90c99c3c12ddb8f5155f0ad7d87c35767ffccb38
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c index 53cab3c..743d3d9 100644 --- a/av1/encoder/encode_strategy.c +++ b/av1/encoder/encode_strategy.c
@@ -983,7 +983,8 @@ !is_lossless_requested(&oxcf->rc_cfg); if (allow_kf_filtering) { const double y_noise_level = av1_estimate_noise_from_single_plane( - frame_input->source, 0, cm->seq_params->bit_depth); + frame_input->source, 0, cm->seq_params->bit_depth, + NOISE_ESTIMATION_EDGE_THRESHOLD); apply_filtering = y_noise_level > 0; } else { apply_filtering = 0;
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index d9116ad..f7ef320 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -78,7 +78,6 @@ #include "av1/encoder/speed_features.h" #include "av1/encoder/superres_scale.h" #include "av1/encoder/thirdpass.h" -#include "av1/encoder/temporal_filter.h" #include "av1/encoder/tpl_model.h" #include "av1/encoder/reconinter_enc.h" #include "av1/encoder/var_based_part.h" @@ -3745,11 +3744,32 @@ // even if denoise_noise_level is > 0, we don't need need to denoise on pass // 1 of 2 if enable_dnl_denoising is disabled since the 2nd pass will be // encoding the original (non-denoised) frame - if (cpi->oxcf.noise_level > 0 && - !(cpi->oxcf.pass == AOM_RC_FIRST_PASS && !cpi->oxcf.enable_dnl_denoising)) + if (cpi->oxcf.noise_level > 0 && !(cpi->oxcf.pass == AOM_RC_FIRST_PASS && + !cpi->oxcf.enable_dnl_denoising)) { +#if !CONFIG_REALTIME_ONLY + // Choose a synthetic noise level for still images for enhanced perceptual + // quality based on an estimated noise level in the source, but only if + // the noise level is set on the command line to > 0. + if (cpi->oxcf.mode == ALLINTRA) { + // No noise synthesis if source is very clean. + // Uses a low edge threshold to focus on smooth areas. + // Increase output noise setting a little compared to measured value. + cpi->oxcf.noise_level = + (float)(av1_estimate_noise_from_single_plane( + sd, 0, cm->seq_params->bit_depth, 16) - + 0.1); + cpi->oxcf.noise_level = (float)AOMMAX(0.0, cpi->oxcf.noise_level); + if (cpi->oxcf.noise_level > 0.0) { + cpi->oxcf.noise_level += (float)0.5; + } + cpi->oxcf.noise_level = (float)AOMMIN(5.0, cpi->oxcf.noise_level); + } +#endif + if (apply_denoise_2d(cpi, sd, cpi->oxcf.noise_block_size, cpi->oxcf.noise_level, time_stamp, end_time) < 0) res = -1; + } #endif // CONFIG_DENOISE if (av1_lookahead_push(cpi->ppi->lookahead, sd, time_stamp, end_time, @@ -3925,7 +3945,7 @@ } } -void print_internal_stats(AV1_PRIMARY *const ppi) { +void print_internal_stats(AV1_PRIMARY *ppi) { if (!ppi->cpi) return; AV1_COMP *const cpi = ppi->cpi;
diff --git a/av1/encoder/temporal_filter.c b/av1/encoder/temporal_filter.c index c33b64b..9a796d1 100644 --- a/av1/encoder/temporal_filter.c +++ b/av1/encoder/temporal_filter.c
@@ -976,7 +976,8 @@ double *noise_levels = tf_ctx->noise_levels; for (int plane = 0; plane < num_planes; ++plane) { noise_levels[plane] = av1_estimate_noise_from_single_plane( - to_filter_frame, plane, cpi->common.seq_params->bit_depth); + to_filter_frame, plane, cpi->common.seq_params->bit_depth, + NOISE_ESTIMATION_EDGE_THRESHOLD); } // Get quantization factor. const int q = av1_get_q(cpi); @@ -1086,7 +1087,8 @@ double av1_estimate_noise_from_single_plane(const YV12_BUFFER_CONFIG *frame, const int plane, - const int bit_depth) { + const int bit_depth, + const int edge_thresh) { const int is_y_plane = (plane == 0); const int height = frame->crop_heights[is_y_plane ? 0 : 1]; const int width = frame->crop_widths[is_y_plane ? 0 : 1]; @@ -1115,7 +1117,7 @@ 2 * (mat[0][1] - mat[2][1]); const int Ga = ROUND_POWER_OF_TWO(abs(Gx) + abs(Gy), bit_depth - 8); // Accumulate Laplacian. - if (Ga < NOISE_ESTIMATION_EDGE_THRESHOLD) { // Only count smooth pixels. + if (Ga < edge_thresh) { // Only count smooth pixels. const int v = 4 * mat[1][1] - 2 * (mat[0][1] + mat[2][1] + mat[1][0] + mat[1][2]) + (mat[0][0] + mat[0][2] + mat[2][0] + mat[2][2]);
diff --git a/av1/encoder/temporal_filter.h b/av1/encoder/temporal_filter.h index 1498b4a..f6ae27f 100644 --- a/av1/encoder/temporal_filter.h +++ b/av1/encoder/temporal_filter.h
@@ -272,7 +272,8 @@ // The estimated noise, or -1.0 if there are too few smooth pixels. double av1_estimate_noise_from_single_plane(const YV12_BUFFER_CONFIG *frame, const int plane, - const int bit_depth); + const int bit_depth, + const int edge_thresh); /*!\endcond */ /*!\brief Does temporal filter for a given macroblock row.