denoising.c 28.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/*
 *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

11 12
#include <limits.h>

13 14 15 16 17
#include "denoising.h"

#include "vp8/common/reconinter.h"
#include "vpx/vpx_integer.h"
#include "vpx_mem/vpx_mem.h"
18
#include "vp8_rtcd.h"
19

20
static const unsigned int NOISE_MOTION_THRESHOLD = 25 * 25;
John Koleszar's avatar
John Koleszar committed
21 22 23
/* SSE_DIFF_THRESHOLD is selected as ~95% confidence assuming
 * var(noise) ~= 100.
 */
24 25
static const unsigned int SSE_DIFF_THRESHOLD = 16 * 16 * 20;
static const unsigned int SSE_THRESHOLD = 16 * 16 * 40;
26
static const unsigned int SSE_THRESHOLD_HIGH = 16 * 16 * 60;
27

John Koleszar's avatar
John Koleszar committed
28
/*
29 30 31 32 33 34 35 36 37 38 39
 * The filter function was modified to reduce the computational complexity.
 * Step 1:
 * Instead of applying tap coefficients for each pixel, we calculated the
 * pixel adjustments vs. pixel diff value ahead of time.
 *     adjustment = filtered_value - current_raw
 *                = (filter_coefficient * diff + 128) >> 8
 * where
 *     filter_coefficient = (255 << 8) / (256 + ((absdiff * 330) >> 3));
 *     filter_coefficient += filter_coefficient /
 *                           (3 + motion_magnitude_adjustment);
 *     filter_coefficient is clamped to 0 ~ 255.
John Koleszar's avatar
John Koleszar committed
40
 *
41 42 43 44 45 46 47 48 49 50 51 52 53 54
 * Step 2:
 * The adjustment vs. diff curve becomes flat very quick when diff increases.
 * This allowed us to use only several levels to approximate the curve without
 * changing the filtering algorithm too much.
 * The adjustments were further corrected by checking the motion magnitude.
 * The levels used are:
 * diff       adjustment w/o motion correction   adjustment w/ motion correction
 * [-255, -16]           -6                                   -7
 * [-15, -8]             -4                                   -5
 * [-7, -4]              -3                                   -4
 * [-3, 3]               diff                                 diff
 * [4, 7]                 3                                    4
 * [8, 15]                4                                    5
 * [16, 255]              6                                    7
John Koleszar's avatar
John Koleszar committed
55
 */
56

57 58 59
int vp8_denoiser_filter_c(unsigned char *mc_running_avg_y, int mc_avg_y_stride,
                          unsigned char *running_avg_y, int avg_y_stride,
                          unsigned char *sig, int sig_stride,
60 61
                          unsigned int motion_magnitude,
                          int increase_denoising)
62
{
63 64
    unsigned char *running_avg_y_start = running_avg_y;
    unsigned char *sig_start = sig;
65 66
    int sum_diff_thresh;
    int r, c;
67
    int sum_diff = 0;
68
    int adj_val[3] = {3, 4, 6};
69 70
    int shift_inc1 = 0;
    int shift_inc2 = 1;
71 72 73 74
    int col_sum[16] = {0, 0, 0, 0,
                       0, 0, 0, 0,
                       0, 0, 0, 0,
                       0, 0, 0, 0};
75
    /* If motion_magnitude is small, making the denoiser more aggressive by
76 77
     * increasing the adjustment for each level. Add another increment for
     * blocks that are labeled for increase denoising. */
78
    if (motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD)
79
    {
80 81 82 83 84 85 86
      if (increase_denoising) {
        shift_inc1 = 1;
        shift_inc2 = 2;
      }
      adj_val[0] += shift_inc2;
      adj_val[1] += shift_inc2;
      adj_val[2] += shift_inc2;
87
    }
88

89 90
    for (r = 0; r < 16; ++r)
    {
91 92
        for (c = 0; c < 16; ++c)
        {
93 94 95
            int diff = 0;
            int adjustment = 0;
            int absdiff = 0;
96

97 98
            diff = mc_running_avg_y[c] - sig[c];
            absdiff = abs(diff);
99

100 101 102
            // When |diff| <= |3 + shift_inc1|, use pixel value from
            // last denoised raw.
            if (absdiff <= 3 + shift_inc1)
103
            {
104
                running_avg_y[c] = mc_running_avg_y[c];
105
                col_sum[c] += diff;
106 107 108
            }
            else
            {
109
                if (absdiff >= 4 + shift_inc1 && absdiff <= 7)
110 111 112 113 114 115 116 117 118 119 120 121 122
                    adjustment = adj_val[0];
                else if (absdiff >= 8 && absdiff <= 15)
                    adjustment = adj_val[1];
                else
                    adjustment = adj_val[2];

                if (diff > 0)
                {
                    if ((sig[c] + adjustment) > 255)
                        running_avg_y[c] = 255;
                    else
                        running_avg_y[c] = sig[c] + adjustment;

123
                    col_sum[c] += adjustment;
124 125 126 127 128 129 130 131
                }
                else
                {
                    if ((sig[c] - adjustment) < 0)
                        running_avg_y[c] = 0;
                    else
                        running_avg_y[c] = sig[c] - adjustment;

132
                    col_sum[c] -= adjustment;
133
                }
134 135 136
            }
        }

John Koleszar's avatar
John Koleszar committed
137
        /* Update pointers for next iteration. */
138 139 140
        sig += sig_stride;
        mc_running_avg_y += mc_avg_y_stride;
        running_avg_y += avg_y_stride;
141
    }
142

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
    for (c = 0; c < 16; ++c) {
      // Below we clip the value in the same way which SSE code use.
      // When adopting aggressive denoiser, the adj_val for each pixel
      // could be at most 8 (this is current max adjustment of the map).
      // In SSE code, we calculate the sum of adj_val for
      // the columns, so the sum could be upto 128(16 rows). However,
      // the range of the value is -128 ~ 127 in SSE code, that's why
      // we do this change in C code.
      // We don't do this for UV denoiser, since there are only 8 rows,
      // and max adjustments <= 8, so the sum of the columns will not
      // exceed 64.
      if (col_sum[c] >= 128) {
        col_sum[c] = 127;
      }
      sum_diff += col_sum[c];
    }

160 161
    sum_diff_thresh= SUM_DIFF_THRESHOLD;
    if (increase_denoising) sum_diff_thresh = SUM_DIFF_THRESHOLD_HIGH;
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
    if (abs(sum_diff) > sum_diff_thresh) {
      // Before returning to copy the block (i.e., apply no denoising), check
      // if we can still apply some (weaker) temporal filtering to this block,
      // that would otherwise not be denoised at all. Simplest is to apply
      // an additional adjustment to running_avg_y to bring it closer to sig.
      // The adjustment is capped by a maximum delta, and chosen such that
      // in most cases the resulting sum_diff will be within the
      // accceptable range given by sum_diff_thresh.

      // The delta is set by the excess of absolute pixel diff over threshold.
      int delta = ((abs(sum_diff) - sum_diff_thresh) >> 8) + 1;
      // Only apply the adjustment for max delta up to 3.
      if (delta < 4) {
        sig -= sig_stride * 16;
        mc_running_avg_y -= mc_avg_y_stride * 16;
        running_avg_y -= avg_y_stride * 16;
        for (r = 0; r < 16; ++r) {
          for (c = 0; c < 16; ++c) {
            int diff = mc_running_avg_y[c] - sig[c];
            int adjustment = abs(diff);
            if (adjustment > delta)
              adjustment = delta;
            if (diff > 0) {
              // Bring denoised signal down.
              if (running_avg_y[c] - adjustment < 0)
                running_avg_y[c] = 0;
              else
                running_avg_y[c] = running_avg_y[c] - adjustment;
190
              col_sum[c] -= adjustment;
191 192 193 194 195 196
            } else if (diff < 0) {
              // Bring denoised signal up.
              if (running_avg_y[c] + adjustment > 255)
                running_avg_y[c] = 255;
              else
                running_avg_y[c] = running_avg_y[c] + adjustment;
197
              col_sum[c] += adjustment;
198 199 200 201 202 203 204 205
            }
          }
          // TODO(marpan): Check here if abs(sum_diff) has gone below the
          // threshold sum_diff_thresh, and if so, we can exit the row loop.
          sig += sig_stride;
          mc_running_avg_y += mc_avg_y_stride;
          running_avg_y += avg_y_stride;
        }
206 207 208 209 210 211 212 213 214

        sum_diff = 0;
        for (c = 0; c < 16; ++c) {
          if (col_sum[c] >= 128) {
            col_sum[c] = 127;
          }
          sum_diff += col_sum[c];
        }

215 216 217
        if (abs(sum_diff) > sum_diff_thresh)
          return COPY_BLOCK;
      } else {
218
        return COPY_BLOCK;
219 220
      }
    }
221

222
    vp8_copy_mem16x16(running_avg_y_start, avg_y_stride, sig_start, sig_stride);
223
    return FILTER_BLOCK;
224 225
}

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
int vp8_denoiser_filter_uv_c(unsigned char *mc_running_avg_uv,
                             int mc_avg_uv_stride,
                             unsigned char *running_avg_uv,
                             int avg_uv_stride,
                             unsigned char *sig,
                             int sig_stride,
                             unsigned int motion_magnitude,
                             int increase_denoising) {
    unsigned char *running_avg_uv_start = running_avg_uv;
    unsigned char *sig_start = sig;
    int sum_diff_thresh;
    int r, c;
    int sum_diff = 0;
    int sum_block = 0;
    int adj_val[3] = {3, 4, 6};
    int shift_inc1 = 0;
    int shift_inc2 = 1;
    /* If motion_magnitude is small, making the denoiser more aggressive by
     * increasing the adjustment for each level. Add another increment for
     * blocks that are labeled for increase denoising. */
    if (motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD_UV) {
      if (increase_denoising) {
        shift_inc1 = 1;
        shift_inc2 = 2;
      }
      adj_val[0] += shift_inc2;
      adj_val[1] += shift_inc2;
      adj_val[2] += shift_inc2;
    }

    // Avoid denoising color signal if its close to average level.
    for (r = 0; r < 8; ++r) {
      for (c = 0; c < 8; ++c) {
        sum_block += sig[c];
      }
      sig += sig_stride;
    }
    if (abs(sum_block - (128 * 8 * 8)) < SUM_DIFF_FROM_AVG_THRESH_UV) {
      return COPY_BLOCK;
    }

    sig -= sig_stride * 8;
    for (r = 0; r < 8; ++r) {
      for (c = 0; c < 8; ++c) {
        int diff = 0;
        int adjustment = 0;
        int absdiff = 0;

        diff = mc_running_avg_uv[c] - sig[c];
        absdiff = abs(diff);

        // When |diff| <= |3 + shift_inc1|, use pixel value from
        // last denoised raw.
        if (absdiff <= 3 + shift_inc1) {
          running_avg_uv[c] = mc_running_avg_uv[c];
          sum_diff += diff;
        } else {
          if (absdiff >= 4 && absdiff <= 7)
            adjustment = adj_val[0];
          else if (absdiff >= 8 && absdiff <= 15)
            adjustment = adj_val[1];
          else
            adjustment = adj_val[2];
          if (diff > 0) {
            if ((sig[c] + adjustment) > 255)
              running_avg_uv[c] = 255;
            else
              running_avg_uv[c] = sig[c] + adjustment;
            sum_diff += adjustment;
          } else {
            if ((sig[c] - adjustment) < 0)
              running_avg_uv[c] = 0;
            else
              running_avg_uv[c] = sig[c] - adjustment;
            sum_diff -= adjustment;
          }
        }
      }
      /* Update pointers for next iteration. */
      sig += sig_stride;
      mc_running_avg_uv += mc_avg_uv_stride;
      running_avg_uv += avg_uv_stride;
    }

    sum_diff_thresh= SUM_DIFF_THRESHOLD_UV;
    if (increase_denoising) sum_diff_thresh = SUM_DIFF_THRESHOLD_HIGH_UV;
    if (abs(sum_diff) > sum_diff_thresh) {
      // Before returning to copy the block (i.e., apply no denoising), check
      // if we can still apply some (weaker) temporal filtering to this block,
      // that would otherwise not be denoised at all. Simplest is to apply
      // an additional adjustment to running_avg_y to bring it closer to sig.
      // The adjustment is capped by a maximum delta, and chosen such that
      // in most cases the resulting sum_diff will be within the
      // accceptable range given by sum_diff_thresh.

      // The delta is set by the excess of absolute pixel diff over threshold.
      int delta = ((abs(sum_diff) - sum_diff_thresh) >> 8) + 1;
      // Only apply the adjustment for max delta up to 3.
      if (delta < 4) {
        sig -= sig_stride * 8;
        mc_running_avg_uv -= mc_avg_uv_stride * 8;
        running_avg_uv -= avg_uv_stride * 8;
        for (r = 0; r < 8; ++r) {
          for (c = 0; c < 8; ++c) {
            int diff = mc_running_avg_uv[c] - sig[c];
            int adjustment = abs(diff);
            if (adjustment > delta)
              adjustment = delta;
            if (diff > 0) {
              // Bring denoised signal down.
              if (running_avg_uv[c] - adjustment < 0)
                running_avg_uv[c] = 0;
              else
                running_avg_uv[c] = running_avg_uv[c] - adjustment;
              sum_diff -= adjustment;
            } else if (diff < 0) {
              // Bring denoised signal up.
              if (running_avg_uv[c] + adjustment > 255)
                running_avg_uv[c] = 255;
              else
                running_avg_uv[c] = running_avg_uv[c] + adjustment;
              sum_diff += adjustment;
            }
          }
          // TODO(marpan): Check here if abs(sum_diff) has gone below the
          // threshold sum_diff_thresh, and if so, we can exit the row loop.
          sig += sig_stride;
          mc_running_avg_uv += mc_avg_uv_stride;
          running_avg_uv += avg_uv_stride;
        }
        if (abs(sum_diff) > sum_diff_thresh)
          return COPY_BLOCK;
      } else {
        return COPY_BLOCK;
      }
    }

    vp8_copy_mem8x8(running_avg_uv_start, avg_uv_stride, sig_start,
                    sig_stride);
    return FILTER_BLOCK;
}

368 369 370 371 372 373
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;
374
  } else if (mode == 3) {
375
    denoiser->denoiser_mode = kDenoiserOnYUVAggressive;
376
  } else {
Marco's avatar
Marco committed
377
    denoiser->denoiser_mode = kDenoiserOnYUV;
378 379
  }
  if (denoiser->denoiser_mode != kDenoiserOnYUVAggressive) {
380 381 382 383 384 385 386
    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;
387
    denoiser->denoise_pars.spatial_blur = 0;
388 389 390 391 392
  } 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;
Marco's avatar
Marco committed
393
    denoiser->denoise_pars.pickmode_mv_bias = 75;
Marco's avatar
Marco committed
394
    denoiser->denoise_pars.qp_thresh = 80;
Marco's avatar
Marco committed
395
    denoiser->denoise_pars.consec_zerolast = 15;
Marco's avatar
Marco committed
396
    denoiser->denoise_pars.spatial_blur = 0;
397 398 399
  }
}

400
int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height,
401
                          int num_mb_rows, int num_mb_cols, int mode)
402
{
403
    int i;
404
    assert(denoiser);
405
    denoiser->num_mb_cols = num_mb_cols;
406

407
    for (i = 0; i < MAX_REF_FRAMES; i++)
408
    {
409
        denoiser->yv12_running_avg[i].flags = 0;
410

411 412 413 414 415 416 417 418 419 420 421
        if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_running_avg[i]), width,
                                        height, VP8BORDERINPIXELS)
            < 0)
        {
            vp8_denoiser_free(denoiser);
            return 1;
        }
        vpx_memset(denoiser->yv12_running_avg[i].buffer_alloc, 0,
                   denoiser->yv12_running_avg[i].frame_size);

    }
422 423 424
    denoiser->yv12_mc_running_avg.flags = 0;

    if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_mc_running_avg), width,
425
                                   height, VP8BORDERINPIXELS) < 0)
426 427 428 429 430 431 432
    {
        vp8_denoiser_free(denoiser);
        return 1;
    }

    vpx_memset(denoiser->yv12_mc_running_avg.buffer_alloc, 0,
               denoiser->yv12_mc_running_avg.frame_size);
433

434 435 436 437 438 439 440 441
    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);

442 443
    denoiser->denoise_state = vpx_calloc((num_mb_rows * num_mb_cols), 1);
    vpx_memset(denoiser->denoise_state, 0, (num_mb_rows * num_mb_cols));
444
    vp8_denoiser_set_parameters(denoiser, mode);
445 446
    denoiser->nmse_source_diff = 0;
    denoiser->nmse_source_diff_count = 0;
447 448 449 450 451 452 453 454
    denoiser->qp_avg = 0;
    // QP threshold below which we can go up to aggressive mode.
    denoiser->qp_threshold_up = 80;
    // QP threshold above which we can go back down to normal mode.
    // For now keep this second threshold high, so not used currently.
    denoiser->qp_threshold_down = 128;
    // Bitrate thresholds and noise metric (nmse) thresholds for switching to
    // aggressive mode.
455
    // TODO(marpan): Adjust thresholds, including effect on resolution.
Marco's avatar
Marco committed
456 457
    denoiser->bitrate_threshold = 400000;  // (bits/sec).
    denoiser->threshold_aggressive_mode = 80;
Marco's avatar
Marco committed
458
    if (width * height > 1280 * 720) {
Marco's avatar
Marco committed
459 460
      denoiser->bitrate_threshold = 3000000;
      denoiser->threshold_aggressive_mode = 200;
461
    } else if (width * height > 960 * 540) {
Marco's avatar
Marco committed
462
      denoiser->bitrate_threshold = 1200000;
Marco's avatar
Marco committed
463
      denoiser->threshold_aggressive_mode = 120;
Marco's avatar
Marco committed
464
    } else if (width * height > 640 * 480) {
Marco's avatar
Marco committed
465
      denoiser->bitrate_threshold = 600000;
Marco's avatar
Marco committed
466
      denoiser->threshold_aggressive_mode = 100;
467
    }
468
    return 0;
469 470
}

471

472 473
void vp8_denoiser_free(VP8_DENOISER *denoiser)
{
474
    int i;
475
    assert(denoiser);
476

477
    for (i = 0; i < MAX_REF_FRAMES ; i++)
478 479 480
    {
        vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg[i]);
    }
481
    vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_mc_running_avg);
482
    vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_last_source);
483
    vpx_free(denoiser->denoise_state);
484 485 486 487 488 489 490
}

void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser,
                             MACROBLOCK *x,
                             unsigned int best_sse,
                             unsigned int zero_mv_sse,
                             int recon_yoffset,
491 492 493 494
                             int recon_uvoffset,
                             loop_filter_info_n *lfi_n,
                             int mb_row,
                             int mb_col,
495 496
                             int block_index)

497 498 499
{
    int mv_row;
    int mv_col;
500
    unsigned int motion_threshold;
501
    unsigned int motion_magnitude2;
502
    unsigned int sse_thresh;
503
    int sse_diff_thresh = 0;
504 505 506
    // Spatial loop filter: only applied selectively based on
    // temporal filter state of block relative to top/left neighbors.
    int apply_spatial_loop_filter = 1;
507 508 509
    MV_REFERENCE_FRAME frame = x->best_reference_frame;
    MV_REFERENCE_FRAME zero_frame = x->best_zeromv_reference_frame;

510
    enum vp8_denoiser_decision decision = FILTER_BLOCK;
511 512
    enum vp8_denoiser_decision decision_u = COPY_BLOCK;
    enum vp8_denoiser_decision decision_v = COPY_BLOCK;
513 514

    if (zero_frame)
515 516 517 518 519 520 521
    {
        YV12_BUFFER_CONFIG *src = &denoiser->yv12_running_avg[frame];
        YV12_BUFFER_CONFIG *dst = &denoiser->yv12_mc_running_avg;
        YV12_BUFFER_CONFIG saved_pre,saved_dst;
        MB_MODE_INFO saved_mbmi;
        MACROBLOCKD *filter_xd = &x->e_mbd;
        MB_MODE_INFO *mbmi = &filter_xd->mode_info_context->mbmi;
522 523
        int sse_diff = 0;
        // Bias on zero motion vector sse.
524
        const int zero_bias = denoiser->denoise_pars.denoise_mv_bias;
525 526
        zero_mv_sse = (unsigned int)((int64_t)zero_mv_sse * zero_bias / 100);
        sse_diff = zero_mv_sse - best_sse;
527 528 529

        saved_mbmi = *mbmi;

John Koleszar's avatar
John Koleszar committed
530
        /* Use the best MV for the compensation. */
531 532 533 534 535 536
        mbmi->ref_frame = x->best_reference_frame;
        mbmi->mode = x->best_sse_inter_mode;
        mbmi->mv = x->best_sse_mv;
        mbmi->need_to_clamp_mvs = x->need_to_clamp_best_mvs;
        mv_col = x->best_sse_mv.as_mv.col;
        mv_row = x->best_sse_mv.as_mv.row;
537 538 539 540 541 542 543
        // Bias to zero_mv if small amount of motion.
        // Note sse_diff_thresh is intialized to zero, so this ensures
        // we will always choose zero_mv for denoising if
        // zero_mv_see <= best_sse (i.e., sse_diff <= 0).
        if ((unsigned int)(mv_row * mv_row + mv_col * mv_col)
            <= NOISE_MOTION_THRESHOLD)
            sse_diff_thresh = (int)SSE_DIFF_THRESHOLD;
544

545
        if (frame == INTRA_FRAME ||
546
            sse_diff <= sse_diff_thresh)
547
        {
John Koleszar's avatar
John Koleszar committed
548 549 550 551 552 553 554 555
            /*
             * Handle intra blocks as referring to last frame with zero motion
             * and let the absolute pixel difference affect the filter factor.
             * Also consider small amount of motion as being random walk due
             * to noise, if it doesn't mean that we get a much bigger error.
             * Note that any changes to the mode info only affects the
             * denoising.
             */
Marco's avatar
Marco committed
556
            x->denoise_zeromv = 1;
557 558 559 560 561 562 563 564 565 566 567 568 569 570
            mbmi->ref_frame =
                    x->best_zeromv_reference_frame;

            src = &denoiser->yv12_running_avg[zero_frame];

            mbmi->mode = ZEROMV;
            mbmi->mv.as_int = 0;
            x->best_sse_inter_mode = ZEROMV;
            x->best_sse_mv.as_int = 0;
            best_sse = zero_mv_sse;
        }

        saved_pre = filter_xd->pre;
        saved_dst = filter_xd->dst;
571

John Koleszar's avatar
John Koleszar committed
572
        /* Compensate the running average. */
573 574 575
        filter_xd->pre.y_buffer = src->y_buffer + recon_yoffset;
        filter_xd->pre.u_buffer = src->u_buffer + recon_uvoffset;
        filter_xd->pre.v_buffer = src->v_buffer + recon_uvoffset;
John Koleszar's avatar
John Koleszar committed
576
        /* Write the compensated running average to the destination buffer. */
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
        filter_xd->dst.y_buffer = dst->y_buffer + recon_yoffset;
        filter_xd->dst.u_buffer = dst->u_buffer + recon_uvoffset;
        filter_xd->dst.v_buffer = dst->v_buffer + recon_uvoffset;

        if (!x->skip)
        {
            vp8_build_inter_predictors_mb(filter_xd);
        }
        else
        {
            vp8_build_inter16x16_predictors_mb(filter_xd,
                                               filter_xd->dst.y_buffer,
                                               filter_xd->dst.u_buffer,
                                               filter_xd->dst.v_buffer,
                                               filter_xd->dst.y_stride,
                                               filter_xd->dst.uv_stride);
        }
        filter_xd->pre = saved_pre;
        filter_xd->dst = saved_dst;
        *mbmi = saved_mbmi;

    }

    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;
603 604
    motion_threshold = denoiser->denoise_pars.scale_motion_thresh *
        NOISE_MOTION_THRESHOLD;
605

Marco's avatar
Marco committed
606 607 608 609 610 611
    // If block is considered to be skin area, lower the motion threshold.
    // In current version set threshold = 1, so only denoise very low
    // (i.e., zero) mv on skin.
    if (x->is_skin)
        motion_threshold = 1;

612 613 614 615 616 617 618 619 620 621
    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;
622 623 624

    if (decision == FILTER_BLOCK)
    {
625 626 627 628 629 630 631
        unsigned char *mc_running_avg_y =
            denoiser->yv12_mc_running_avg.y_buffer + recon_yoffset;
        int mc_avg_y_stride = denoiser->yv12_mc_running_avg.y_stride;
        unsigned char *running_avg_y =
            denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset;
        int avg_y_stride = denoiser->yv12_running_avg[INTRA_FRAME].y_stride;

John Koleszar's avatar
John Koleszar committed
632
        /* Filter. */
633
        decision = vp8_denoiser_filter(mc_running_avg_y, mc_avg_y_stride,
634 635 636
                                       running_avg_y, avg_y_stride,
                                       x->thismb, 16, motion_magnitude2,
                                       x->increase_denoising);
637 638
        denoiser->denoise_state[block_index] = motion_magnitude2 > 0 ?
            kFilterNonZeroMV : kFilterZeroMV;
639
        // Only denoise UV for zero motion, and if y channel was denoised.
640
        if (denoiser->denoiser_mode != kDenoiserOnYOnly &&
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
            motion_magnitude2 == 0 &&
            decision == FILTER_BLOCK) {
          unsigned char *mc_running_avg_u =
              denoiser->yv12_mc_running_avg.u_buffer + recon_uvoffset;
          unsigned char *running_avg_u =
              denoiser->yv12_running_avg[INTRA_FRAME].u_buffer + recon_uvoffset;
          unsigned char *mc_running_avg_v =
              denoiser->yv12_mc_running_avg.v_buffer + recon_uvoffset;
          unsigned char *running_avg_v =
              denoiser->yv12_running_avg[INTRA_FRAME].v_buffer + recon_uvoffset;
          int mc_avg_uv_stride = denoiser->yv12_mc_running_avg.uv_stride;
          int avg_uv_stride = denoiser->yv12_running_avg[INTRA_FRAME].uv_stride;
          int signal_stride = x->block[16].src_stride;
          decision_u =
              vp8_denoiser_filter_uv(mc_running_avg_u, mc_avg_uv_stride,
                                      running_avg_u, avg_uv_stride,
                                      x->block[16].src + *x->block[16].base_src,
                                      signal_stride, motion_magnitude2, 0);
          decision_v =
              vp8_denoiser_filter_uv(mc_running_avg_v, mc_avg_uv_stride,
                                      running_avg_v, avg_uv_stride,
                                      x->block[20].src + *x->block[20].base_src,
                                      signal_stride, motion_magnitude2, 0);
        }
665 666
    }
    if (decision == COPY_BLOCK)
667
    {
John Koleszar's avatar
John Koleszar committed
668 669 670
        /* No filtering of this block; it differs too much from the predictor,
         * or the motion vector magnitude is considered too big.
         */
Marco's avatar
Marco committed
671
        x->denoise_zeromv = 0;
672 673
        vp8_copy_mem16x16(
                x->thismb, 16,
674 675
                denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset,
                denoiser->yv12_running_avg[INTRA_FRAME].y_stride);
676 677
        denoiser->denoise_state[block_index] = kNoFilter;
    }
678
    if (denoiser->denoiser_mode != kDenoiserOnYOnly) {
679 680 681 682 683 684 685 686 687 688 689 690 691 692
      if (decision_u == COPY_BLOCK) {
        vp8_copy_mem8x8(
            x->block[16].src + *x->block[16].base_src, x->block[16].src_stride,
            denoiser->yv12_running_avg[INTRA_FRAME].u_buffer + recon_uvoffset,
            denoiser->yv12_running_avg[INTRA_FRAME].uv_stride);
      }
      if (decision_v == COPY_BLOCK) {
        vp8_copy_mem8x8(
            x->block[20].src + *x->block[20].base_src, x->block[16].src_stride,
            denoiser->yv12_running_avg[INTRA_FRAME].v_buffer + recon_uvoffset,
            denoiser->yv12_running_avg[INTRA_FRAME].uv_stride);
      }
    }
    // Option to selectively deblock the denoised signal, for y channel only.
693 694 695 696 697 698 699 700 701
    if (apply_spatial_loop_filter) {
      loop_filter_info lfi;
      int apply_filter_col = 0;
      int apply_filter_row = 0;
      int apply_filter = 0;
      int y_stride = denoiser->yv12_running_avg[INTRA_FRAME].y_stride;
      int uv_stride =denoiser->yv12_running_avg[INTRA_FRAME].uv_stride;

      // Fix filter level to some nominal value for now.
Marco's avatar
Marco committed
702
      int filter_level = 48;
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743

      int hev_index = lfi_n->hev_thr_lut[INTER_FRAME][filter_level];
      lfi.mblim = lfi_n->mblim[filter_level];
      lfi.blim = lfi_n->blim[filter_level];
      lfi.lim = lfi_n->lim[filter_level];
      lfi.hev_thr = lfi_n->hev_thr[hev_index];

      // Apply filter if there is a difference in the denoiser filter state
      // between the current and left/top block, or if non-zero motion vector
      // is used for the motion-compensated filtering.
      if (mb_col > 0) {
        apply_filter_col = !((denoiser->denoise_state[block_index] ==
            denoiser->denoise_state[block_index - 1]) &&
            denoiser->denoise_state[block_index] != kFilterNonZeroMV);
        if (apply_filter_col) {
          // Filter left vertical edge.
          apply_filter = 1;
          vp8_loop_filter_mbv(
              denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset,
              NULL, NULL, y_stride, uv_stride, &lfi);
        }
      }
      if (mb_row > 0) {
        apply_filter_row = !((denoiser->denoise_state[block_index] ==
            denoiser->denoise_state[block_index - denoiser->num_mb_cols]) &&
            denoiser->denoise_state[block_index] != kFilterNonZeroMV);
        if (apply_filter_row) {
          // Filter top horizontal edge.
          apply_filter = 1;
          vp8_loop_filter_mbh(
              denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset,
              NULL, NULL, y_stride, uv_stride, &lfi);
        }
      }
      if (apply_filter) {
        // Update the signal block |x|. Pixel changes are only to top and/or
        // left boundary pixels: can we avoid full block copy here.
        vp8_copy_mem16x16(
            denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset,
            y_stride, x->thismb, 16);
      }
744
    }
745
}