/*
|
* Copyright (c) 2015 The WebRTC 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.
|
*/
|
|
#include <stdlib.h>
|
|
#include "webrtc/modules/video_processing/util/denoiser_filter_c.h"
|
|
namespace webrtc {
|
|
void DenoiserFilterC::CopyMem16x16(const uint8_t* src,
|
int src_stride,
|
uint8_t* dst,
|
int dst_stride) {
|
for (int i = 0; i < 16; i++) {
|
memcpy(dst, src, 16);
|
src += src_stride;
|
dst += dst_stride;
|
}
|
}
|
|
void DenoiserFilterC::CopyMem8x8(const uint8_t* src,
|
int src_stride,
|
uint8_t* dst,
|
int dst_stride) {
|
for (int i = 0; i < 8; i++) {
|
memcpy(dst, src, 8);
|
src += src_stride;
|
dst += dst_stride;
|
}
|
}
|
|
uint32_t DenoiserFilterC::Variance16x8(const uint8_t* a,
|
int a_stride,
|
const uint8_t* b,
|
int b_stride,
|
uint32_t* sse) {
|
int sum = 0;
|
*sse = 0;
|
a_stride <<= 1;
|
b_stride <<= 1;
|
|
for (int i = 0; i < 8; i++) {
|
for (int j = 0; j < 16; j++) {
|
const int diff = a[j] - b[j];
|
sum += diff;
|
*sse += diff * diff;
|
}
|
|
a += a_stride;
|
b += b_stride;
|
}
|
return *sse - ((static_cast<int64_t>(sum) * sum) >> 7);
|
}
|
|
DenoiserDecision DenoiserFilterC::MbDenoise(uint8_t* mc_running_avg_y,
|
int mc_avg_y_stride,
|
uint8_t* running_avg_y,
|
int avg_y_stride,
|
const uint8_t* sig,
|
int sig_stride,
|
uint8_t motion_magnitude,
|
int increase_denoising) {
|
int sum_diff_thresh = 0;
|
int sum_diff = 0;
|
int adj_val[3] = {3, 4, 6};
|
int shift_inc1 = 0;
|
int shift_inc2 = 1;
|
int col_sum[16] = {0};
|
if (motion_magnitude <= kMotionMagnitudeThreshold) {
|
if (increase_denoising) {
|
shift_inc1 = 1;
|
shift_inc2 = 2;
|
}
|
adj_val[0] += shift_inc2;
|
adj_val[1] += shift_inc2;
|
adj_val[2] += shift_inc2;
|
}
|
|
for (int r = 0; r < 16; ++r) {
|
for (int c = 0; c < 16; ++c) {
|
int diff = 0;
|
int adjustment = 0;
|
int absdiff = 0;
|
|
diff = mc_running_avg_y[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_y[c] = mc_running_avg_y[c];
|
col_sum[c] += diff;
|
} else {
|
if (absdiff >= 4 + shift_inc1 && 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_y[c] = 255;
|
else
|
running_avg_y[c] = sig[c] + adjustment;
|
|
col_sum[c] += adjustment;
|
} else {
|
if ((sig[c] - adjustment) < 0)
|
running_avg_y[c] = 0;
|
else
|
running_avg_y[c] = sig[c] - adjustment;
|
|
col_sum[c] -= adjustment;
|
}
|
}
|
}
|
|
// Update pointers for next iteration.
|
sig += sig_stride;
|
mc_running_avg_y += mc_avg_y_stride;
|
running_avg_y += avg_y_stride;
|
}
|
|
for (int c = 0; c < 16; ++c) {
|
if (col_sum[c] >= 128) {
|
col_sum[c] = 127;
|
}
|
sum_diff += col_sum[c];
|
}
|
|
sum_diff_thresh = kSumDiffThreshold;
|
if (increase_denoising)
|
sum_diff_thresh = kSumDiffThresholdHigh;
|
if (abs(sum_diff) > sum_diff_thresh) {
|
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 (int r = 0; r < 16; ++r) {
|
for (int 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;
|
col_sum[c] -= adjustment;
|
} 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;
|
col_sum[c] += adjustment;
|
}
|
}
|
sig += sig_stride;
|
mc_running_avg_y += mc_avg_y_stride;
|
running_avg_y += avg_y_stride;
|
}
|
|
sum_diff = 0;
|
for (int c = 0; c < 16; ++c) {
|
if (col_sum[c] >= 128) {
|
col_sum[c] = 127;
|
}
|
sum_diff += col_sum[c];
|
}
|
|
if (abs(sum_diff) > sum_diff_thresh)
|
return COPY_BLOCK;
|
} else {
|
return COPY_BLOCK;
|
}
|
}
|
|
return FILTER_BLOCK;
|
}
|
|
} // namespace webrtc
|