/* * Copyright (c) 2011 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 "denoising.h" #include "trace.h" #include namespace webrtc { enum { kSubsamplingTime = 0 }; // Down-sampling in time (unit: number of frames) enum { kSubsamplingWidth = 3 }; // Sub-sampling in width (unit: power of 2) enum { kSubsamplingHeight = 2 }; // Sub-sampling in height (unit: power of 2) enum { kDenoiseFiltParam = 179 }; // (Q8) De-noising filter parameter enum { kDenoiseFiltParamRec = 77 }; // (Q8) 1 - filter parameter enum { kDenoiseThreshold = 19200 }; // (Q8) De-noising threshold level VPMDenoising::VPMDenoising() : _id(0), _moment1(NULL), _moment2(NULL) { Reset(); } VPMDenoising::~VPMDenoising() { if (_moment1) { delete [] _moment1; _moment1 = NULL; } if (_moment2) { delete [] _moment2; _moment2 = NULL; } } WebRtc_Word32 VPMDenoising::ChangeUniqueId(const WebRtc_Word32 id) { _id = id; return VPM_OK; } void VPMDenoising::Reset() { _frameSize = 0; _denoiseFrameCnt = 0; if (_moment1) { delete [] _moment1; _moment1 = NULL; } if (_moment2) { delete [] _moment2; _moment2 = NULL; } } WebRtc_Word32 VPMDenoising::ProcessFrame(WebRtc_UWord8* frame, const WebRtc_UWord32 width, const WebRtc_UWord32 height) { WebRtc_Word32 thevar; WebRtc_UWord32 k; WebRtc_UWord32 jsub, ksub; WebRtc_Word32 diff0; WebRtc_UWord32 tmpMoment1; WebRtc_UWord32 tmpMoment2; WebRtc_UWord32 tmp; WebRtc_Word32 numPixelsChanged = 0; if (frame == NULL) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id, "Null frame pointer"); return VPM_GENERAL_ERROR; } if (width == 0 || height == 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id, "Invalid frame size"); return VPM_GENERAL_ERROR; } /* Size of luminance component */ const WebRtc_UWord32 ysize = height * width; /* Initialization */ if (ysize != _frameSize) { delete [] _moment1; _moment1 = NULL; delete [] _moment2; _moment2 = NULL; } _frameSize = ysize; if (!_moment1) { _moment1 = new WebRtc_UWord32[ysize]; memset(_moment1, 0, sizeof(WebRtc_UWord32)*ysize); } if (!_moment2) { _moment2 = new WebRtc_UWord32[ysize]; memset(_moment2, 0, sizeof(WebRtc_UWord32)*ysize); } /* Apply de-noising on each pixel, but update variance sub-sampled */ for (WebRtc_UWord32 i = 0; i < height; i++) { // Collect over height k = i * width; ksub = ((i >> kSubsamplingHeight) << kSubsamplingHeight) * width; for (WebRtc_UWord32 j = 0; j < width; j++) { // Collect over width jsub = ((j >> kSubsamplingWidth) << kSubsamplingWidth); /* Update mean value for every pixel and every frame */ tmpMoment1 = _moment1[k + j]; tmpMoment1 *= kDenoiseFiltParam; // Q16 tmpMoment1 += ((kDenoiseFiltParamRec * ((WebRtc_UWord32)frame[k + j])) << 8); tmpMoment1 >>= 8; // Q8 _moment1[k + j] = tmpMoment1; tmpMoment2 = _moment2[ksub + jsub]; if ((ksub == k) && (jsub == j) && (_denoiseFrameCnt == 0)) { tmp = ((WebRtc_UWord32)frame[k + j] * (WebRtc_UWord32)frame[k + j]); tmpMoment2 *= kDenoiseFiltParam; // Q16 tmpMoment2 += ((kDenoiseFiltParamRec * tmp)<<8); tmpMoment2 >>= 8; // Q8 } _moment2[k + j] = tmpMoment2; /* Current event = deviation from mean value */ diff0 = ((WebRtc_Word32)frame[k + j] << 8) - _moment1[k + j]; /* Recent events = variance (variations over time) */ thevar = _moment2[k + j]; thevar -= ((_moment1[k + j] * _moment1[k + j]) >> 8); /*************************************************************************** * De-noising criteria, i.e., when should we replace a pixel by its mean * * 1) recent events are minor * 2) current events are minor ***************************************************************************/ if ((thevar < kDenoiseThreshold) && ((diff0 * diff0 >> 8) < kDenoiseThreshold)) { // Replace with mean frame[k + j] = (WebRtc_UWord8)(_moment1[k + j] >> 8); numPixelsChanged++; } } } /* Update frame counter */ _denoiseFrameCnt++; if (_denoiseFrameCnt > kSubsamplingTime) { _denoiseFrameCnt = 0; } return numPixelsChanged; } } //namespace