blob: 4c8dcb439f6f5095ecbc9b4d38447acb460d3735 [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"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <string.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000014
15namespace webrtc {
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000016// Down-sampling in time (unit: number of frames)
17enum { kSubsamplingTime = 0 };
18// Sub-sampling in width (unit: power of 2.
19enum { kSubsamplingWidth = 0 };
20// Sub-sampling in height (unit: power of 2)
21enum { kSubsamplingHeight = 0 };
22// (Q8) De-noising filter parameter
23enum { kDenoiseFiltParam = 179 };
24// (Q8) 1 - filter parameter
25enum { kDenoiseFiltParamRec = 77 };
26// (Q8) De-noising threshold level
27enum { kDenoiseThreshold = 19200 };
niklase@google.com470e71d2011-07-07 08:21:25 +000028
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000029VPMDenoising::VPMDenoising()
30 : id_(0),
31 moment1_(NULL),
32 moment2_(NULL) {
33 Reset();
niklase@google.com470e71d2011-07-07 08:21:25 +000034}
35
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000036VPMDenoising::~VPMDenoising() {
37 if (moment1_) {
38 delete [] moment1_;
39 moment1_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +000040}
41
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000042 if (moment2_) {
43 delete [] moment2_;
44 moment2_ = NULL;
45 }
niklase@google.com470e71d2011-07-07 08:21:25 +000046}
47
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000048int32_t VPMDenoising::ChangeUniqueId(const int32_t id) {
49 id_ = id;
50 return VPM_OK;
niklase@google.com470e71d2011-07-07 08:21:25 +000051}
52
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000053void VPMDenoising::Reset() {
54 frame_size_ = 0;
55 denoise_frame_cnt_ = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000056
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000057 if (moment1_) {
58 delete [] moment1_;
59 moment1_ = NULL;
60 }
61
62 if (moment2_) {
63 delete [] moment2_;
64 moment2_ = NULL;
65 }
66}
67
68int32_t VPMDenoising::ProcessFrame(I420VideoFrame* frame) {
69 assert(frame);
70 int32_t thevar;
71 int k;
72 int jsub, ksub;
73 int32_t diff0;
74 uint32_t tmp_moment1;
75 uint32_t tmp_moment2;
76 uint32_t tmp;
77 int32_t num_pixels_changed = 0;
78
79 if (frame->IsZeroSize()) {
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +000080 return VPM_GENERAL_ERROR;
81 }
82
83 int width = frame->width();
84 int height = frame->height();
85
86 /* Size of luminance component */
87 const uint32_t y_size = height * width;
88
89 /* Initialization */
90 if (y_size != frame_size_) {
91 delete [] moment1_;
92 moment1_ = NULL;
93
94 delete [] moment2_;
95 moment2_ = NULL;
96 }
97 frame_size_ = y_size;
98
99 if (!moment1_) {
100 moment1_ = new uint32_t[y_size];
101 memset(moment1_, 0, sizeof(uint32_t)*y_size);
102 }
103
104 if (!moment2_) {
105 moment2_ = new uint32_t[y_size];
106 memset(moment2_, 0, sizeof(uint32_t)*y_size);
107 }
108
109 /* Apply de-noising on each pixel, but update variance sub-sampled */
110 uint8_t* buffer = frame->buffer(kYPlane);
111 for (int i = 0; i < height; i++) { // Collect over height
112 k = i * width;
113 ksub = ((i >> kSubsamplingHeight) << kSubsamplingHeight) * width;
114 for (int j = 0; j < width; j++) { // Collect over width
115 jsub = ((j >> kSubsamplingWidth) << kSubsamplingWidth);
116 /* Update mean value for every pixel and every frame */
117 tmp_moment1 = moment1_[k + j];
118 tmp_moment1 *= kDenoiseFiltParam; // Q16
119 tmp_moment1 += ((kDenoiseFiltParamRec * ((uint32_t)buffer[k + j])) << 8);
120 tmp_moment1 >>= 8; // Q8
121 moment1_[k + j] = tmp_moment1;
122
123 tmp_moment2 = moment2_[ksub + jsub];
124 if ((ksub == k) && (jsub == j) && (denoise_frame_cnt_ == 0)) {
125 tmp = ((uint32_t)buffer[k + j] *
126 (uint32_t)buffer[k + j]);
127 tmp_moment2 *= kDenoiseFiltParam; // Q16
128 tmp_moment2 += ((kDenoiseFiltParamRec * tmp) << 8);
129 tmp_moment2 >>= 8; // Q8
130 }
131 moment2_[k + j] = tmp_moment2;
132 /* Current event = deviation from mean value */
133 diff0 = ((int32_t)buffer[k + j] << 8) - moment1_[k + j];
134 /* Recent events = variance (variations over time) */
135 thevar = moment2_[k + j];
136 thevar -= ((moment1_[k + j] * moment1_[k + j]) >> 8);
137 // De-noising criteria, i.e., when should we replace a pixel by its mean.
138 // 1) recent events are minor.
139 // 2) current events are minor.
140 if ((thevar < kDenoiseThreshold)
141 && ((diff0 * diff0 >> 8) < kDenoiseThreshold)) {
142 // Replace with mean.
143 buffer[k + j] = (uint8_t)(moment1_[k + j] >> 8);
144 num_pixels_changed++;
145 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000146 }
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +0000147 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000148
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +0000149 denoise_frame_cnt_++;
150 if (denoise_frame_cnt_ > kSubsamplingTime)
151 denoise_frame_cnt_ = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000152
mikhal@webrtc.orgb43d8072013-10-03 16:42:41 +0000153 return num_pixels_changed;
niklase@google.com470e71d2011-07-07 08:21:25 +0000154}
155
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000156} // namespace