Review URL: https://webrtc-codereview.appspot.com/922004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2983 4adac7df-926f-26a2-2b94-8c16560cd09d
181 lines
5.0 KiB
C++
181 lines
5.0 KiB
C++
/*
|
|
* Copyright (c) 2012 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 <cstring>
|
|
|
|
namespace webrtc {
|
|
|
|
enum { kSubsamplingTime = 0 }; // Down-sampling in time (unit: number of frames)
|
|
enum { kSubsamplingWidth = 0 }; // Sub-sampling in width (unit: power of 2)
|
|
enum { kSubsamplingHeight = 0 }; // 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(I420VideoFrame* frame)
|
|
{
|
|
assert(frame);
|
|
WebRtc_Word32 thevar;
|
|
int k;
|
|
int jsub, ksub;
|
|
WebRtc_Word32 diff0;
|
|
WebRtc_UWord32 tmpMoment1;
|
|
WebRtc_UWord32 tmpMoment2;
|
|
WebRtc_UWord32 tmp;
|
|
WebRtc_Word32 numPixelsChanged = 0;
|
|
|
|
if (frame->IsZeroSize())
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id,
|
|
"zero size frame");
|
|
return VPM_GENERAL_ERROR;
|
|
}
|
|
|
|
int width = frame->width();
|
|
int height = frame->height();
|
|
|
|
/* 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 */
|
|
uint8_t* buffer = frame->buffer(kYPlane);
|
|
for (int i = 0; i < height; i++)
|
|
{ // Collect over height
|
|
k = i * width;
|
|
ksub = ((i >> kSubsamplingHeight) << kSubsamplingHeight) * width;
|
|
for (int 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)buffer[k + j])) << 8);
|
|
tmpMoment1 >>= 8; // Q8
|
|
_moment1[k + j] = tmpMoment1;
|
|
|
|
tmpMoment2 = _moment2[ksub + jsub];
|
|
if ((ksub == k) && (jsub == j) && (_denoiseFrameCnt == 0))
|
|
{
|
|
tmp = ((WebRtc_UWord32)buffer[k + j] *
|
|
(WebRtc_UWord32)buffer[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)buffer[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
|
|
buffer[k + j] = (WebRtc_UWord8)(_moment1[k + j] >> 8);
|
|
numPixelsChanged++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Update frame counter */
|
|
_denoiseFrameCnt++;
|
|
if (_denoiseFrameCnt > kSubsamplingTime)
|
|
{
|
|
_denoiseFrameCnt = 0;
|
|
}
|
|
|
|
return numPixelsChanged;
|
|
}
|
|
|
|
} //namespace
|