blob: f7cc32ad6b797b8d955fb9ee4b6f68337408ec71 [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
11#include "denoising.h"
12#include "trace.h"
13
14#include <cstring>
15
16namespace webrtc {
17
18enum { kSubsamplingTime = 0 }; // Down-sampling in time (unit: number of frames)
stefan@webrtc.org7dfa8832012-02-08 08:27:31 +000019enum { kSubsamplingWidth = 0 }; // Sub-sampling in width (unit: power of 2)
20enum { kSubsamplingHeight = 0 }; // Sub-sampling in height (unit: power of 2)
niklase@google.com470e71d2011-07-07 08:21:25 +000021enum { kDenoiseFiltParam = 179 }; // (Q8) De-noising filter parameter
22enum { kDenoiseFiltParamRec = 77 }; // (Q8) 1 - filter parameter
23enum { kDenoiseThreshold = 19200 }; // (Q8) De-noising threshold level
24
25VPMDenoising::VPMDenoising() :
26 _id(0),
27 _moment1(NULL),
28 _moment2(NULL)
29{
30 Reset();
31}
32
33VPMDenoising::~VPMDenoising()
34{
35 if (_moment1)
36 {
37 delete [] _moment1;
38 _moment1 = NULL;
39 }
40
41 if (_moment2)
42 {
43 delete [] _moment2;
44 _moment2 = NULL;
45 }
46}
47
48WebRtc_Word32
49VPMDenoising::ChangeUniqueId(const WebRtc_Word32 id)
50{
51 _id = id;
52 return VPM_OK;
53}
54
55void
56VPMDenoising::Reset()
57{
58 _frameSize = 0;
59 _denoiseFrameCnt = 0;
60
61 if (_moment1)
62 {
63 delete [] _moment1;
64 _moment1 = NULL;
65 }
66
67 if (_moment2)
68 {
69 delete [] _moment2;
70 _moment2 = NULL;
71 }
72}
73
74WebRtc_Word32
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000075VPMDenoising::ProcessFrame(I420VideoFrame* frame)
niklase@google.com470e71d2011-07-07 08:21:25 +000076{
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +000077 assert(frame);
niklase@google.com470e71d2011-07-07 08:21:25 +000078 WebRtc_Word32 thevar;
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +000079 int k;
80 int jsub, ksub;
niklase@google.com470e71d2011-07-07 08:21:25 +000081 WebRtc_Word32 diff0;
82 WebRtc_UWord32 tmpMoment1;
83 WebRtc_UWord32 tmpMoment2;
84 WebRtc_UWord32 tmp;
85 WebRtc_Word32 numPixelsChanged = 0;
86
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000087 if (frame->IsZeroSize())
niklase@google.com470e71d2011-07-07 08:21:25 +000088 {
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +000089 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000090 "zero size frame");
niklase@google.com470e71d2011-07-07 08:21:25 +000091 return VPM_GENERAL_ERROR;
92 }
93
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000094 int width = frame->width();
95 int height = frame->height();
niklase@google.com470e71d2011-07-07 08:21:25 +000096
97 /* Size of luminance component */
98 const WebRtc_UWord32 ysize = height * width;
99
100 /* Initialization */
101 if (ysize != _frameSize)
102 {
103 delete [] _moment1;
104 _moment1 = NULL;
105
106 delete [] _moment2;
107 _moment2 = NULL;
108 }
109 _frameSize = ysize;
110
111 if (!_moment1)
112 {
113 _moment1 = new WebRtc_UWord32[ysize];
114 memset(_moment1, 0, sizeof(WebRtc_UWord32)*ysize);
115 }
116
117 if (!_moment2)
118 {
119 _moment2 = new WebRtc_UWord32[ysize];
120 memset(_moment2, 0, sizeof(WebRtc_UWord32)*ysize);
121 }
122
123 /* Apply de-noising on each pixel, but update variance sub-sampled */
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000124 uint8_t* buffer = frame->buffer(kYPlane);
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000125 for (int i = 0; i < height; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000126 { // Collect over height
127 k = i * width;
128 ksub = ((i >> kSubsamplingHeight) << kSubsamplingHeight) * width;
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000129 for (int j = 0; j < width; j++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000130 { // Collect over width
131 jsub = ((j >> kSubsamplingWidth) << kSubsamplingWidth);
132 /* Update mean value for every pixel and every frame */
133 tmpMoment1 = _moment1[k + j];
134 tmpMoment1 *= kDenoiseFiltParam; // Q16
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000135 tmpMoment1 += ((kDenoiseFiltParamRec *
136 ((WebRtc_UWord32)buffer[k + j])) << 8);
niklase@google.com470e71d2011-07-07 08:21:25 +0000137 tmpMoment1 >>= 8; // Q8
138 _moment1[k + j] = tmpMoment1;
139
140 tmpMoment2 = _moment2[ksub + jsub];
141 if ((ksub == k) && (jsub == j) && (_denoiseFrameCnt == 0))
142 {
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000143 tmp = ((WebRtc_UWord32)buffer[k + j] *
144 (WebRtc_UWord32)buffer[k + j]);
niklase@google.com470e71d2011-07-07 08:21:25 +0000145 tmpMoment2 *= kDenoiseFiltParam; // Q16
146 tmpMoment2 += ((kDenoiseFiltParamRec * tmp)<<8);
147 tmpMoment2 >>= 8; // Q8
148 }
149 _moment2[k + j] = tmpMoment2;
150 /* Current event = deviation from mean value */
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000151 diff0 = ((WebRtc_Word32)buffer[k + j] << 8) - _moment1[k + j];
niklase@google.com470e71d2011-07-07 08:21:25 +0000152 /* Recent events = variance (variations over time) */
153 thevar = _moment2[k + j];
154 thevar -= ((_moment1[k + j] * _moment1[k + j]) >> 8);
155 /***************************************************************************
156 * De-noising criteria, i.e., when should we replace a pixel by its mean
157 *
158 * 1) recent events are minor
159 * 2) current events are minor
160 ***************************************************************************/
161 if ((thevar < kDenoiseThreshold)
162 && ((diff0 * diff0 >> 8) < kDenoiseThreshold))
163 { // Replace with mean
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000164 buffer[k + j] = (WebRtc_UWord8)(_moment1[k + j] >> 8);
niklase@google.com470e71d2011-07-07 08:21:25 +0000165 numPixelsChanged++;
166 }
167 }
168 }
169
170 /* Update frame counter */
171 _denoiseFrameCnt++;
172 if (_denoiseFrameCnt > kSubsamplingTime)
173 {
174 _denoiseFrameCnt = 0;
175 }
176
177 return numPixelsChanged;
178}
179
180} //namespace