media/libvpx/vp8/encoder/denoising.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved.
michael@0 3 *
michael@0 4 * Use of this source code is governed by a BSD-style license
michael@0 5 * that can be found in the LICENSE file in the root of the source
michael@0 6 * tree. An additional intellectual property rights grant can be found
michael@0 7 * in the file PATENTS. All contributing project authors may
michael@0 8 * be found in the AUTHORS file in the root of the source tree.
michael@0 9 */
michael@0 10
michael@0 11 #include "denoising.h"
michael@0 12
michael@0 13 #include "vp8/common/reconinter.h"
michael@0 14 #include "vpx/vpx_integer.h"
michael@0 15 #include "vpx_mem/vpx_mem.h"
michael@0 16 #include "vp8_rtcd.h"
michael@0 17
michael@0 18 static const unsigned int NOISE_MOTION_THRESHOLD = 25 * 25;
michael@0 19 /* SSE_DIFF_THRESHOLD is selected as ~95% confidence assuming
michael@0 20 * var(noise) ~= 100.
michael@0 21 */
michael@0 22 static const unsigned int SSE_DIFF_THRESHOLD = 16 * 16 * 20;
michael@0 23 static const unsigned int SSE_THRESHOLD = 16 * 16 * 40;
michael@0 24
michael@0 25 /*
michael@0 26 * The filter function was modified to reduce the computational complexity.
michael@0 27 * Step 1:
michael@0 28 * Instead of applying tap coefficients for each pixel, we calculated the
michael@0 29 * pixel adjustments vs. pixel diff value ahead of time.
michael@0 30 * adjustment = filtered_value - current_raw
michael@0 31 * = (filter_coefficient * diff + 128) >> 8
michael@0 32 * where
michael@0 33 * filter_coefficient = (255 << 8) / (256 + ((absdiff * 330) >> 3));
michael@0 34 * filter_coefficient += filter_coefficient /
michael@0 35 * (3 + motion_magnitude_adjustment);
michael@0 36 * filter_coefficient is clamped to 0 ~ 255.
michael@0 37 *
michael@0 38 * Step 2:
michael@0 39 * The adjustment vs. diff curve becomes flat very quick when diff increases.
michael@0 40 * This allowed us to use only several levels to approximate the curve without
michael@0 41 * changing the filtering algorithm too much.
michael@0 42 * The adjustments were further corrected by checking the motion magnitude.
michael@0 43 * The levels used are:
michael@0 44 * diff adjustment w/o motion correction adjustment w/ motion correction
michael@0 45 * [-255, -16] -6 -7
michael@0 46 * [-15, -8] -4 -5
michael@0 47 * [-7, -4] -3 -4
michael@0 48 * [-3, 3] diff diff
michael@0 49 * [4, 7] 3 4
michael@0 50 * [8, 15] 4 5
michael@0 51 * [16, 255] 6 7
michael@0 52 */
michael@0 53
michael@0 54 int vp8_denoiser_filter_c(YV12_BUFFER_CONFIG *mc_running_avg,
michael@0 55 YV12_BUFFER_CONFIG *running_avg, MACROBLOCK *signal,
michael@0 56 unsigned int motion_magnitude, int y_offset,
michael@0 57 int uv_offset)
michael@0 58 {
michael@0 59 unsigned char *sig = signal->thismb;
michael@0 60 int sig_stride = 16;
michael@0 61 unsigned char *mc_running_avg_y = mc_running_avg->y_buffer + y_offset;
michael@0 62 int mc_avg_y_stride = mc_running_avg->y_stride;
michael@0 63 unsigned char *running_avg_y = running_avg->y_buffer + y_offset;
michael@0 64 int avg_y_stride = running_avg->y_stride;
michael@0 65 int r, c, i;
michael@0 66 int sum_diff = 0;
michael@0 67 int adj_val[3] = {3, 4, 6};
michael@0 68
michael@0 69 /* If motion_magnitude is small, making the denoiser more aggressive by
michael@0 70 * increasing the adjustment for each level. */
michael@0 71 if (motion_magnitude <= MOTION_MAGNITUDE_THRESHOLD)
michael@0 72 {
michael@0 73 for (i = 0; i < 3; i++)
michael@0 74 adj_val[i] += 1;
michael@0 75 }
michael@0 76
michael@0 77 for (r = 0; r < 16; ++r)
michael@0 78 {
michael@0 79 for (c = 0; c < 16; ++c)
michael@0 80 {
michael@0 81 int diff = 0;
michael@0 82 int adjustment = 0;
michael@0 83 int absdiff = 0;
michael@0 84
michael@0 85 diff = mc_running_avg_y[c] - sig[c];
michael@0 86 absdiff = abs(diff);
michael@0 87
michael@0 88 /* When |diff| < 4, use pixel value from last denoised raw. */
michael@0 89 if (absdiff <= 3)
michael@0 90 {
michael@0 91 running_avg_y[c] = mc_running_avg_y[c];
michael@0 92 sum_diff += diff;
michael@0 93 }
michael@0 94 else
michael@0 95 {
michael@0 96 if (absdiff >= 4 && absdiff <= 7)
michael@0 97 adjustment = adj_val[0];
michael@0 98 else if (absdiff >= 8 && absdiff <= 15)
michael@0 99 adjustment = adj_val[1];
michael@0 100 else
michael@0 101 adjustment = adj_val[2];
michael@0 102
michael@0 103 if (diff > 0)
michael@0 104 {
michael@0 105 if ((sig[c] + adjustment) > 255)
michael@0 106 running_avg_y[c] = 255;
michael@0 107 else
michael@0 108 running_avg_y[c] = sig[c] + adjustment;
michael@0 109
michael@0 110 sum_diff += adjustment;
michael@0 111 }
michael@0 112 else
michael@0 113 {
michael@0 114 if ((sig[c] - adjustment) < 0)
michael@0 115 running_avg_y[c] = 0;
michael@0 116 else
michael@0 117 running_avg_y[c] = sig[c] - adjustment;
michael@0 118
michael@0 119 sum_diff -= adjustment;
michael@0 120 }
michael@0 121 }
michael@0 122 }
michael@0 123
michael@0 124 /* Update pointers for next iteration. */
michael@0 125 sig += sig_stride;
michael@0 126 mc_running_avg_y += mc_avg_y_stride;
michael@0 127 running_avg_y += avg_y_stride;
michael@0 128 }
michael@0 129
michael@0 130 if (abs(sum_diff) > SUM_DIFF_THRESHOLD)
michael@0 131 return COPY_BLOCK;
michael@0 132
michael@0 133 vp8_copy_mem16x16(running_avg->y_buffer + y_offset, avg_y_stride,
michael@0 134 signal->thismb, sig_stride);
michael@0 135 return FILTER_BLOCK;
michael@0 136 }
michael@0 137
michael@0 138 int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height)
michael@0 139 {
michael@0 140 int i;
michael@0 141 assert(denoiser);
michael@0 142
michael@0 143 for (i = 0; i < MAX_REF_FRAMES; i++)
michael@0 144 {
michael@0 145 denoiser->yv12_running_avg[i].flags = 0;
michael@0 146
michael@0 147 if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_running_avg[i]), width,
michael@0 148 height, VP8BORDERINPIXELS)
michael@0 149 < 0)
michael@0 150 {
michael@0 151 vp8_denoiser_free(denoiser);
michael@0 152 return 1;
michael@0 153 }
michael@0 154 vpx_memset(denoiser->yv12_running_avg[i].buffer_alloc, 0,
michael@0 155 denoiser->yv12_running_avg[i].frame_size);
michael@0 156
michael@0 157 }
michael@0 158 denoiser->yv12_mc_running_avg.flags = 0;
michael@0 159
michael@0 160 if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_mc_running_avg), width,
michael@0 161 height, VP8BORDERINPIXELS) < 0)
michael@0 162 {
michael@0 163 vp8_denoiser_free(denoiser);
michael@0 164 return 1;
michael@0 165 }
michael@0 166
michael@0 167 vpx_memset(denoiser->yv12_mc_running_avg.buffer_alloc, 0,
michael@0 168 denoiser->yv12_mc_running_avg.frame_size);
michael@0 169 return 0;
michael@0 170 }
michael@0 171
michael@0 172 void vp8_denoiser_free(VP8_DENOISER *denoiser)
michael@0 173 {
michael@0 174 int i;
michael@0 175 assert(denoiser);
michael@0 176
michael@0 177 for (i = 0; i < MAX_REF_FRAMES ; i++)
michael@0 178 {
michael@0 179 vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg[i]);
michael@0 180 }
michael@0 181 vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_mc_running_avg);
michael@0 182 }
michael@0 183
michael@0 184
michael@0 185 void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser,
michael@0 186 MACROBLOCK *x,
michael@0 187 unsigned int best_sse,
michael@0 188 unsigned int zero_mv_sse,
michael@0 189 int recon_yoffset,
michael@0 190 int recon_uvoffset)
michael@0 191 {
michael@0 192 int mv_row;
michael@0 193 int mv_col;
michael@0 194 unsigned int motion_magnitude2;
michael@0 195
michael@0 196 MV_REFERENCE_FRAME frame = x->best_reference_frame;
michael@0 197 MV_REFERENCE_FRAME zero_frame = x->best_zeromv_reference_frame;
michael@0 198
michael@0 199 enum vp8_denoiser_decision decision = FILTER_BLOCK;
michael@0 200
michael@0 201 if (zero_frame)
michael@0 202 {
michael@0 203 YV12_BUFFER_CONFIG *src = &denoiser->yv12_running_avg[frame];
michael@0 204 YV12_BUFFER_CONFIG *dst = &denoiser->yv12_mc_running_avg;
michael@0 205 YV12_BUFFER_CONFIG saved_pre,saved_dst;
michael@0 206 MB_MODE_INFO saved_mbmi;
michael@0 207 MACROBLOCKD *filter_xd = &x->e_mbd;
michael@0 208 MB_MODE_INFO *mbmi = &filter_xd->mode_info_context->mbmi;
michael@0 209 int sse_diff = zero_mv_sse - best_sse;
michael@0 210
michael@0 211 saved_mbmi = *mbmi;
michael@0 212
michael@0 213 /* Use the best MV for the compensation. */
michael@0 214 mbmi->ref_frame = x->best_reference_frame;
michael@0 215 mbmi->mode = x->best_sse_inter_mode;
michael@0 216 mbmi->mv = x->best_sse_mv;
michael@0 217 mbmi->need_to_clamp_mvs = x->need_to_clamp_best_mvs;
michael@0 218 mv_col = x->best_sse_mv.as_mv.col;
michael@0 219 mv_row = x->best_sse_mv.as_mv.row;
michael@0 220
michael@0 221 if (frame == INTRA_FRAME ||
michael@0 222 ((unsigned int)(mv_row *mv_row + mv_col *mv_col)
michael@0 223 <= NOISE_MOTION_THRESHOLD &&
michael@0 224 sse_diff < (int)SSE_DIFF_THRESHOLD))
michael@0 225 {
michael@0 226 /*
michael@0 227 * Handle intra blocks as referring to last frame with zero motion
michael@0 228 * and let the absolute pixel difference affect the filter factor.
michael@0 229 * Also consider small amount of motion as being random walk due
michael@0 230 * to noise, if it doesn't mean that we get a much bigger error.
michael@0 231 * Note that any changes to the mode info only affects the
michael@0 232 * denoising.
michael@0 233 */
michael@0 234 mbmi->ref_frame =
michael@0 235 x->best_zeromv_reference_frame;
michael@0 236
michael@0 237 src = &denoiser->yv12_running_avg[zero_frame];
michael@0 238
michael@0 239 mbmi->mode = ZEROMV;
michael@0 240 mbmi->mv.as_int = 0;
michael@0 241 x->best_sse_inter_mode = ZEROMV;
michael@0 242 x->best_sse_mv.as_int = 0;
michael@0 243 best_sse = zero_mv_sse;
michael@0 244 }
michael@0 245
michael@0 246 saved_pre = filter_xd->pre;
michael@0 247 saved_dst = filter_xd->dst;
michael@0 248
michael@0 249 /* Compensate the running average. */
michael@0 250 filter_xd->pre.y_buffer = src->y_buffer + recon_yoffset;
michael@0 251 filter_xd->pre.u_buffer = src->u_buffer + recon_uvoffset;
michael@0 252 filter_xd->pre.v_buffer = src->v_buffer + recon_uvoffset;
michael@0 253 /* Write the compensated running average to the destination buffer. */
michael@0 254 filter_xd->dst.y_buffer = dst->y_buffer + recon_yoffset;
michael@0 255 filter_xd->dst.u_buffer = dst->u_buffer + recon_uvoffset;
michael@0 256 filter_xd->dst.v_buffer = dst->v_buffer + recon_uvoffset;
michael@0 257
michael@0 258 if (!x->skip)
michael@0 259 {
michael@0 260 vp8_build_inter_predictors_mb(filter_xd);
michael@0 261 }
michael@0 262 else
michael@0 263 {
michael@0 264 vp8_build_inter16x16_predictors_mb(filter_xd,
michael@0 265 filter_xd->dst.y_buffer,
michael@0 266 filter_xd->dst.u_buffer,
michael@0 267 filter_xd->dst.v_buffer,
michael@0 268 filter_xd->dst.y_stride,
michael@0 269 filter_xd->dst.uv_stride);
michael@0 270 }
michael@0 271 filter_xd->pre = saved_pre;
michael@0 272 filter_xd->dst = saved_dst;
michael@0 273 *mbmi = saved_mbmi;
michael@0 274
michael@0 275 }
michael@0 276
michael@0 277 mv_row = x->best_sse_mv.as_mv.row;
michael@0 278 mv_col = x->best_sse_mv.as_mv.col;
michael@0 279 motion_magnitude2 = mv_row * mv_row + mv_col * mv_col;
michael@0 280 if (best_sse > SSE_THRESHOLD || motion_magnitude2
michael@0 281 > 8 * NOISE_MOTION_THRESHOLD)
michael@0 282 {
michael@0 283 decision = COPY_BLOCK;
michael@0 284 }
michael@0 285
michael@0 286 if (decision == FILTER_BLOCK)
michael@0 287 {
michael@0 288 /* Filter. */
michael@0 289 decision = vp8_denoiser_filter(&denoiser->yv12_mc_running_avg,
michael@0 290 &denoiser->yv12_running_avg[INTRA_FRAME],
michael@0 291 x,
michael@0 292 motion_magnitude2,
michael@0 293 recon_yoffset, recon_uvoffset);
michael@0 294 }
michael@0 295 if (decision == COPY_BLOCK)
michael@0 296 {
michael@0 297 /* No filtering of this block; it differs too much from the predictor,
michael@0 298 * or the motion vector magnitude is considered too big.
michael@0 299 */
michael@0 300 vp8_copy_mem16x16(
michael@0 301 x->thismb, 16,
michael@0 302 denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset,
michael@0 303 denoiser->yv12_running_avg[INTRA_FRAME].y_stride);
michael@0 304 }
michael@0 305 }

mercurial