文件位置
● openh264/codec/processing/denoise/denoise.cpp
● openh264/codec/processing/denoise/denoise_filter.cpp
代码流程
- 说明:从代码流程可以看到,实现降噪的核心功能主要就是
BilateralDenoiseLuma
、WaverageDenoiseChroma
两个函数。
原理
- 参数开关控制:(bool) bEnableDenoise
BilateralDenoiseLuma函数
- 功能:实现图像亮度分量的双边滤波降噪
- 过程:
- 将亮度指针pSrcY向前移动m_uiSpaceRadius行,跳过图像边缘的噪声处理区域;
- 外层循环遍历图像的高度,从m_uiSpaceRadius开始,到iHeight - m_uiSpaceRadius,跳过边缘区域;
- 内层循环遍历图像的宽度,从m_uiSpaceRadius开始,每次增加8(为了利用SIMD指令集进行优化),直到iWidth - m_uiSpaceRadius - TAIL_OF_LINE8;
- 对当前8个像素块使用双边滤波器
pfBilateralLumaFilter8
函数(指向具体的BilateralLumaFilter8_c
函数)进行去噪;- for 循环处理剩余的像素,这些像素不能被8整除,因此需要单独处理;
- 调用
Gauss3x3Filter
函数对单个像素使用高斯滤波器进行去噪;- 将指针pSrcY向下移动一行,准备处理下一行的数据;
- 原理图
- 相关源码:
BilateralDenoiseLuma
函数
void CDenoiser::BilateralDenoiseLuma (uint8_t* pSrcY, int32_t iWidth, int32_t iHeight, int32_t iStride) {
int32_t w;
pSrcY = pSrcY + m_uiSpaceRadius * iStride;
for (int32_t h = m_uiSpaceRadius; h < iHeight - m_uiSpaceRadius; h++) {
for (w = m_uiSpaceRadius; w < iWidth - m_uiSpaceRadius - TAIL_OF_LINE8; w += 8) {
m_pfDenoise.pfBilateralLumaFilter8 (pSrcY + w, iStride);
}
for (; w < iWidth - m_uiSpaceRadius; w++) {
Gauss3x3Filter (pSrcY + w, iStride);
}
pSrcY += iStride;
}
}
pfBilateralLumaFilter8
函数(指向具体的BilateralLumaFilter8_c
函数)
void BilateralLumaFilter8_c (uint8_t* pSample, int32_t iStride) {
int32_t nSum = 0, nTotWeight = 0;
int32_t iCenterSample = *pSample;
uint8_t* pCurLine = pSample - iStride - DENOISE_GRAY_RADIUS;
int32_t x, y;
int32_t iCurSample, iCurWeight, iGreyDiff;
uint8_t aSample[8];
for (int32_t i = 0; i < 8; i++) {
nSum = 0;
nTotWeight = 0;
iCenterSample = *pSample;
pCurLine = pSample - iStride - DENOISE_GRAY_RADIUS;
for (y = 0; y < 3; y++) {
for (x = 0; x < 3; x++) {
if (x == 1 && y == 1) continue; // except center point
iCurSample = pCurLine[x];
iCurWeight = WELS_ABS (iCurSample - iCenterSample);
iGreyDiff = 32 - iCurWeight;
if (iGreyDiff < 0) continue;
else iCurWeight = (iGreyDiff * iGreyDiff) >> 5;
nSum += iCurSample * iCurWeight;
nTotWeight += iCurWeight;
}
pCurLine += iStride;
}
nTotWeight = 256 - nTotWeight;
nSum += iCenterSample * nTotWeight;
aSample[i] = nSum >> 8;
pSample++;
}
WelsMemcpy (pSample - 8, aSample, 8);
}
Gauss3x3Filter
函数
/***************************************************************************
edge of y/uv use a 3x3 Gauss filter, radius = 1:
1 2 1
2 4 2
1 2 1
***************************************************************************/
void Gauss3x3Filter (uint8_t* pSrc, int32_t iStride) {
int32_t nSum = 0;
uint8_t* pCurLine1 = pSrc - iStride - 1;
uint8_t* pCurLine2 = pCurLine1 + iStride;
uint8_t* pCurLine3 = pCurLine2 + iStride;
nSum = pCurLine1[0] + (pCurLine1[1] << 1) + pCurLine1[2] +
(pCurLine2[0] << 1) + (pCurLine2[1] << 2) + (pCurLine2[2] << 1) +
pCurLine3[0] + (pCurLine3[1] << 1) + pCurLine3[2];
*pSrc = nSum >> 4;
}
WaverageDenoiseChroma函数
- 功能:实现图像色度分量的降噪功能
- 过程:
- 将指针pSrcUV向前移动UV_WINDOWS_RADIUS行,跳过图像边缘的噪声处理区域;
- 外层循环遍历图像的高度,从UV_WINDOWS_RADIUS开始,到iHeight - UV_WINDOWS_RADIUS,跳过边缘区域;
- 内层循环遍历图像的宽度,从UV_WINDOWS_RADIUS开始,每次增加8(为了利用SIMD指令集进行优化),直到iWidth - UV_WINDOWS_RADIUS - TAIL_OF_LINE8,用于确保在处理行尾时不会超出边界;
- 对当前8个像素块使用加权平均滤波器
pfWaverageChromaFilter8
函数(指向WaverageChromaFilter8_c
函数)进行去噪;- 调用
Gauss3x3Filter
函数处理剩余的像素,这些像素不能被8整除,因此需要单独处理;- 将指针pSrcUV向下移动一行,准备处理下一行的数据。
- 原理图:
- 相关源码:
WaverageDenoiseChroma
函数
void CDenoiser::WaverageDenoiseChroma (uint8_t* pSrcUV, int32_t iWidth, int32_t iHeight, int32_t iStride) {
int32_t w;
pSrcUV = pSrcUV + UV_WINDOWS_RADIUS * iStride;
for (int32_t h = UV_WINDOWS_RADIUS; h < iHeight - UV_WINDOWS_RADIUS; h++) {
for (w = UV_WINDOWS_RADIUS; w < iWidth - UV_WINDOWS_RADIUS - TAIL_OF_LINE8; w += 8) {
m_pfDenoise.pfWaverageChromaFilter8 (pSrcUV + w, iStride);
}
for (; w < iWidth - UV_WINDOWS_RADIUS; w++) {
Gauss3x3Filter (pSrcUV + w, iStride);
}
pSrcUV += iStride;
}
}
WaverageChromaFilter8_c
函数
/***************************************************************************
5x5 filter:
1 1 2 1 1
1 2 4 2 1
2 4 20 4 2
1 2 4 2 1
1 1 2 1 1
***************************************************************************/
#define SUM_LINE1(pSample) (pSample[0] +(pSample[1]) +(pSample[2]<<1) + pSample[3] + pSample[4])
#define SUM_LINE2(pSample) (pSample[0] +(pSample[1]<<1) +(pSample[2]<<2) +(pSample[3]<<1) + pSample[4])
#define SUM_LINE3(pSample) ((pSample[0]<<1) +(pSample[1]<<2) +(pSample[2]*20) +(pSample[3]<<2) +(pSample[4]<<1))
void WaverageChromaFilter8_c (uint8_t* pSample, int32_t iStride) {
int32_t sum;
uint8_t* pStartPixels = pSample - UV_WINDOWS_RADIUS * iStride - UV_WINDOWS_RADIUS;
uint8_t* pCurLine1 = pStartPixels;
uint8_t* pCurLine2 = pCurLine1 + iStride;
uint8_t* pCurLine3 = pCurLine2 + iStride;
uint8_t* pCurLine4 = pCurLine3 + iStride;
uint8_t* pCurLine5 = pCurLine4 + iStride;
uint8_t aSample[8];
for (int32_t i = 0; i < 8; i++) {
sum = SUM_LINE1 ((pCurLine1 + i)) + SUM_LINE2 ((pCurLine2 + i)) + SUM_LINE3 ((pCurLine3 + i))
+ SUM_LINE2 ((pCurLine4 + i)) + SUM_LINE1 ((pCurLine5 + i));
aSample[i] = (sum >> 6);
pSample++;
}
WelsMemcpy (pSample - 8, aSample, 8);
}
Gauss3x3Filter
函数
/***************************************************************************
edge of y/uv use a 3x3 Gauss filter, radius = 1:
1 2 1
2 4 2
1 2 1
***************************************************************************/
void Gauss3x3Filter (uint8_t* pSrc, int32_t iStride) {
int32_t nSum = 0;
uint8_t* pCurLine1 = pSrc - iStride - 1;
uint8_t* pCurLine2 = pCurLine1 + iStride;
uint8_t* pCurLine3 = pCurLine2 + iStride;
nSum = pCurLine1[0] + (pCurLine1[1] << 1) + pCurLine1[2] +
(pCurLine2[0] << 1) + (pCurLine2[1] << 2) + (pCurLine2[2] << 1) +
pCurLine3[0] + (pCurLine3[1] << 1) + pCurLine3[2];
*pSrc = nSum >> 4;
}