* be found in the AUTHORS file in the root of the source tree.
*/
+#include <limits.h>
+
#include "denoising.h"
#include "vp8/common/reconinter.h"
return FILTER_BLOCK;
}
+void vp8_denoiser_set_parameters(VP8_DENOISER *denoiser, int mode) {
+ assert(mode > 0); // Denoiser is allocated only if mode > 0.
+ if (mode == 1) {
+ denoiser->denoiser_mode = kDenoiserOnYOnly;
+ } else if (mode == 2) {
+ denoiser->denoiser_mode = kDenoiserOnYUV;
+ } else if (mode == 3) {
+ denoiser->denoiser_mode = kDenoiserOnYUVAggressive;
+ } else {
+ denoiser->denoiser_mode = kDenoiserOnAdaptive;
+ }
+ if (denoiser->denoiser_mode != kDenoiserOnYUVAggressive) {
+ denoiser->denoise_pars.scale_sse_thresh = 1;
+ denoiser->denoise_pars.scale_motion_thresh = 8;
+ denoiser->denoise_pars.scale_increase_filter = 0;
+ denoiser->denoise_pars.denoise_mv_bias = 95;
+ denoiser->denoise_pars.pickmode_mv_bias = 100;
+ denoiser->denoise_pars.qp_thresh = 0;
+ denoiser->denoise_pars.consec_zerolast = UINT_MAX;
+ } else {
+ denoiser->denoise_pars.scale_sse_thresh = 2;
+ denoiser->denoise_pars.scale_motion_thresh = 16;
+ denoiser->denoise_pars.scale_increase_filter = 1;
+ denoiser->denoise_pars.denoise_mv_bias = 60;
+ denoiser->denoise_pars.pickmode_mv_bias = 60;
+ denoiser->denoise_pars.qp_thresh = 100;
+ denoiser->denoise_pars.consec_zerolast = 10;
+ }
+}
+
int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height,
- int num_mb_rows, int num_mb_cols)
+ int num_mb_rows, int num_mb_cols, int mode)
{
int i;
assert(denoiser);
vpx_memset(denoiser->yv12_mc_running_avg.buffer_alloc, 0,
denoiser->yv12_mc_running_avg.frame_size);
+ if (vp8_yv12_alloc_frame_buffer(&denoiser->yv12_last_source, width,
+ height, VP8BORDERINPIXELS) < 0) {
+ vp8_denoiser_free(denoiser);
+ return 1;
+ }
+ vpx_memset(denoiser->yv12_last_source.buffer_alloc, 0,
+ denoiser->yv12_last_source.frame_size);
+
denoiser->denoise_state = vpx_calloc((num_mb_rows * num_mb_cols), 1);
vpx_memset(denoiser->denoise_state, 0, (num_mb_rows * num_mb_cols));
-
+ vp8_denoiser_set_parameters(denoiser, mode);
+ denoiser->nmse_source_diff = 0;
+ denoiser->nmse_source_diff_count = 0;
+ // TODO(marpan): Adjust thresholds, including effect on resolution.
+ denoiser->threshold_aggressive_mode = 40;
+ if (width * height > 640 * 480)
+ denoiser->threshold_aggressive_mode = 180;
return 0;
}
+
void vp8_denoiser_free(VP8_DENOISER *denoiser)
{
int i;
vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg[i]);
}
vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_mc_running_avg);
+ vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_last_source);
vpx_free(denoiser->denoise_state);
}
loop_filter_info_n *lfi_n,
int mb_row,
int mb_col,
- int block_index,
- int uv_denoise)
+ int block_index)
+
{
int mv_row;
int mv_col;
+ unsigned int motion_threshold;
unsigned int motion_magnitude2;
unsigned int sse_thresh;
int sse_diff_thresh = 0;
MV_REFERENCE_FRAME zero_frame = x->best_zeromv_reference_frame;
enum vp8_denoiser_decision decision = FILTER_BLOCK;
- enum vp8_denoiser_decision decision_u = FILTER_BLOCK;
- enum vp8_denoiser_decision decision_v = FILTER_BLOCK;
+ enum vp8_denoiser_decision decision_u = COPY_BLOCK;
+ enum vp8_denoiser_decision decision_v = COPY_BLOCK;
if (zero_frame)
{
MB_MODE_INFO *mbmi = &filter_xd->mode_info_context->mbmi;
int sse_diff = 0;
// Bias on zero motion vector sse.
- int zero_bias = 95;
+ const int zero_bias = denoiser->denoise_pars.denoise_mv_bias;
zero_mv_sse = (unsigned int)((int64_t)zero_mv_sse * zero_bias / 100);
sse_diff = zero_mv_sse - best_sse;
mv_row = x->best_sse_mv.as_mv.row;
mv_col = x->best_sse_mv.as_mv.col;
motion_magnitude2 = mv_row * mv_row + mv_col * mv_col;
- sse_thresh = SSE_THRESHOLD;
- if (x->increase_denoising) sse_thresh = SSE_THRESHOLD_HIGH;
+ motion_threshold = denoiser->denoise_pars.scale_motion_thresh *
+ NOISE_MOTION_THRESHOLD;
- if (best_sse > sse_thresh || motion_magnitude2
- > 8 * NOISE_MOTION_THRESHOLD)
- {
- decision = COPY_BLOCK;
- }
+ if (motion_magnitude2 <
+ denoiser->denoise_pars.scale_increase_filter * NOISE_MOTION_THRESHOLD)
+ x->increase_denoising = 1;
+
+ sse_thresh = denoiser->denoise_pars.scale_sse_thresh * SSE_THRESHOLD;
+ if (x->increase_denoising)
+ sse_thresh = denoiser->denoise_pars.scale_sse_thresh * SSE_THRESHOLD_HIGH;
+
+ if (best_sse > sse_thresh || motion_magnitude2 > motion_threshold)
+ decision = COPY_BLOCK;
if (decision == FILTER_BLOCK)
{
denoiser->denoise_state[block_index] = motion_magnitude2 > 0 ?
kFilterNonZeroMV : kFilterZeroMV;
// Only denoise UV for zero motion, and if y channel was denoised.
- if (uv_denoise &&
+ if (denoiser->denoiser_mode != kDenoiserOnYOnly &&
motion_magnitude2 == 0 &&
decision == FILTER_BLOCK) {
unsigned char *mc_running_avg_u =
denoiser->yv12_running_avg[INTRA_FRAME].y_stride);
denoiser->denoise_state[block_index] = kNoFilter;
}
- if (uv_denoise) {
+ if (denoiser->denoiser_mode != kDenoiserOnYOnly) {
if (decision_u == COPY_BLOCK) {
vp8_copy_mem8x8(
x->block[16].src + *x->block[16].base_src, x->block[16].src_stride,