blob: 79c4bcc3d1bc7a8fcea424f58e74a243d3d18fd6 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
stefan@webrtc.org7dfa8832012-02-08 08:27:31 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
pbos@webrtc.org6f3d8fc2013-05-27 14:12:16 +000011#include "webrtc/modules/video_processing/main/source/denoising.h"
12#include "webrtc/system_wrappers/interface/trace.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000013
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000014#include <string.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000015
16namespace webrtc {
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000017// Down-sampling in time (unit: number of frames)
18enum { kSubsamplingTime = 0 };
19// Sub-sampling in width (unit: power of 2.
20enum { kSubsamplingWidth = 0 };
21// Sub-sampling in height (unit: power of 2)
22enum { kSubsamplingHeight = 0 };
23// (Q8) De-noising filter parameter
24enum { kDenoiseFiltParam = 179 };
25// (Q8) 1 - filter parameter
26enum { kDenoiseFiltParamRec = 77 };
27// (Q8) De-noising threshold level
28enum { kDenoiseThreshold = 19200 };
niklase@google.com470e71d2011-07-07 08:21:25 +000029
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000030VPMDenoising::VPMDenoising()
31 : id_(0),
32 moment1_(NULL),
33 moment2_(NULL) {
34 Reset();
niklase@google.com470e71d2011-07-07 08:21:25 +000035}
36
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000037VPMDenoising::~VPMDenoising() {
38 if (moment1_) {
39 delete [] moment1_;
40 moment1_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +000041}
42
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000043 if (moment2_) {
44 delete [] moment2_;
45 moment2_ = NULL;
46 }
niklase@google.com470e71d2011-07-07 08:21:25 +000047}
48
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000049int32_t VPMDenoising::ChangeUniqueId(const int32_t id) {
50 id_ = id;
51 return VPM_OK;
niklase@google.com470e71d2011-07-07 08:21:25 +000052}
53
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000054void VPMDenoising::Reset() {
55 frame_size_ = 0;
56 denoise_frame_cnt_ = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000057
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000058 if (moment1_) {
59 delete [] moment1_;
60 moment1_ = NULL;
61 }
62
63 if (moment2_) {
64 delete [] moment2_;
65 moment2_ = NULL;
66 }
67}
68
69int32_t VPMDenoising::ProcessFrame(I420VideoFrame* frame) {
70 assert(frame);
71 int32_t thevar;
72 int k;
73 int jsub, ksub;
74 int32_t diff0;
75 uint32_t tmp_moment1;
76 uint32_t tmp_moment2;
77 uint32_t tmp;
78 int32_t num_pixels_changed = 0;
79
80 if (frame->IsZeroSize()) {
81 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, id_,
82 "zero size frame");
83 return VPM_GENERAL_ERROR;
84 }
85
86 int width = frame->width();
87 int height = frame->height();
88
89 /* Size of luminance component */
90 const uint32_t y_size = height * width;
91
92 /* Initialization */
93 if (y_size != frame_size_) {
94 delete [] moment1_;
95 moment1_ = NULL;
96
97 delete [] moment2_;
98 moment2_ = NULL;
99 }
100 frame_size_ = y_size;
101
102 if (!moment1_) {
103 moment1_ = new uint32_t[y_size];
104 memset(moment1_, 0, sizeof(uint32_t)*y_size);
105 }
106
107 if (!moment2_) {
108 moment2_ = new uint32_t[y_size];
109 memset(moment2_, 0, sizeof(uint32_t)*y_size);
110 }
111
112 /* Apply de-noising on each pixel, but update variance sub-sampled */
113 uint8_t* buffer = frame->buffer(kYPlane);
114 for (int i = 0; i < height; i++) { // Collect over height
115 k = i * width;
116 ksub = ((i >> kSubsamplingHeight) << kSubsamplingHeight) * width;
117 for (int j = 0; j < width; j++) { // Collect over width
118 jsub = ((j >> kSubsamplingWidth) << kSubsamplingWidth);
119 /* Update mean value for every pixel and every frame */
120 tmp_moment1 = moment1_[k + j];
121 tmp_moment1 *= kDenoiseFiltParam; // Q16
122 tmp_moment1 += ((kDenoiseFiltParamRec * ((uint32_t)buffer[k + j])) << 8);
123 tmp_moment1 >>= 8; // Q8
124 moment1_[k + j] = tmp_moment1;
125
126 tmp_moment2 = moment2_[ksub + jsub];
127 if ((ksub == k) && (jsub == j) && (denoise_frame_cnt_ == 0)) {
128 tmp = ((uint32_t)buffer[k + j] *
129 (uint32_t)buffer[k + j]);
130 tmp_moment2 *= kDenoiseFiltParam; // Q16
131 tmp_moment2 += ((kDenoiseFiltParamRec * tmp) << 8);
132 tmp_moment2 >>= 8; // Q8
133 }
134 moment2_[k + j] = tmp_moment2;
135 /* Current event = deviation from mean value */
136 diff0 = ((int32_t)buffer[k + j] << 8) - moment1_[k + j];
137 /* Recent events = variance (variations over time) */
138 thevar = moment2_[k + j];
139 thevar -= ((moment1_[k + j] * moment1_[k + j]) >> 8);
140 // De-noising criteria, i.e., when should we replace a pixel by its mean.
141 // 1) recent events are minor.
142 // 2) current events are minor.
143 if ((thevar < kDenoiseThreshold)
144 && ((diff0 * diff0 >> 8) < kDenoiseThreshold)) {
145 // Replace with mean.
146 buffer[k + j] = (uint8_t)(moment1_[k + j] >> 8);
147 num_pixels_changed++;
148 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000149 }
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +0000150 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000151
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +0000152 denoise_frame_cnt_++;
153 if (denoise_frame_cnt_ > kSubsamplingTime)
154 denoise_frame_cnt_ = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000155
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +0000156 return num_pixels_changed;
niklase@google.com470e71d2011-07-07 08:21:25 +0000157}
158
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000159} // namespace