openh264 降噪功能源码分析

文件位置

openh264/codec/processing/denoise/denoise.cpp
openh264/codec/processing/denoise/denoise_filter.cpp

代码流程

在这里插入图片描述

  • 说明:从代码流程可以看到,实现降噪的核心功能主要就是BilateralDenoiseLumaWaverageDenoiseChroma两个函数。

原理

  • 参数开关控制:(bool) bEnableDenoise

BilateralDenoiseLuma函数

  1. 功能:实现图像亮度分量的双边滤波降噪
  2. 过程
  • 将亮度指针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向下移动一行,准备处理下一行的数据;
  1. 原理图
    在这里插入图片描述
  2. 相关源码
  • 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 pointiCurSample = 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函数

  1. 功能:实现图像色度分量的降噪功能
  2. 过程
  • 将指针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向下移动一行,准备处理下一行的数据。
  1. 原理图
    在这里插入图片描述
  2. 相关源码
  • 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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/24090.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SOA主要协议和规范

Web服务作为实现SOA中服务的最主要手段。首先来了解Web Service相关的标准。它们大多以“WS-”作为名字的前缀&#xff0c;所以统称“WS-*”。Web服务最基本的协议包括UDDI、WSDL和SOAP&#xff0c;通过它们&#xff0c;可以提供直接而又简单的Web Service支持&#xff0c;如图…

代码随想录算法训练营第十五天| 110.平衡二叉树、 257. 二叉树的所有路径、404.左叶子之和

110.平衡二叉树 题目链接&#xff1a;110.平衡二叉树 文档讲讲&#xff1a;代码随想录 状态&#xff1a;还可以 思路&#xff1a;计算左右子树的深度差&#xff0c;递归判断左右子树是否符合平衡条件 题解&#xff1a; public boolean isBalanced(TreeNode root) {if (root n…

覆盖路径规划经典算法 The Boustrophedon Cellular Decomposition 详解

2000年一篇论文 Coverage of Known Spaces: The Boustrophedon Cellular Decomposition 横空出世&#xff0c;解决了很多计算机和机器人领域的覆盖路径问题&#xff0c;今天我来详细解读这个算法。 The Boustrophedon Cellular Decomposition 算法详解 这篇论文标题为"C…

数字模拟EDA研发环境搭建

中小企业数字模拟EDA研发环境部署、集群搭建、网络配置、硬件咨询、数据备份、技术指导、环境生命周期维护等&#xff0c;Cadence、Synopsys、Mentor、Keysight、ANSYS&#xff0c;MATLAB、Xilinx等厂商软件工具安装调试。 EDA研发环境搭建经验交流&#xff0c;请加V

【Neo4j】Windows11使用Neo4j导入CSV数据可视化知识图谱

Windows11使用Neo4j导入CSV数据可视化知识图谱 序1. 安装JDK21&#xff08;1&#xff09;下载&#xff08;2&#xff09;安装&#xff08;3&#xff09;环境配置 2. 安装Neo4j&#xff08;1&#xff09;下载&#xff08;2&#xff09;解压安装&#xff08;3&#xff09;环境配置…

初识C++ · 模板进阶

目录 前言&#xff1a; 1 非类型模板参数 2 按需实例化 3 模板特化 4 模板的分离编译 前言&#xff1a; 前面模板我们会了简单的使用&#xff0c;这里带来模板的进阶&#xff0c;当然&#xff0c;也就那么几个知识点&#xff0c;并不太难。 1 非类型模板参数 先来看这样…

嵌入式移植jpeglib--Linux交叉编译ARM平台

一 、交叉编译jpeg库 1.下载源码tar.gz 2. 源码目录下执行 jpeglib配置文件 ./configure CCarm-none-linux-gnueabihf-gcc LDarm-none-linux-gnueabihf-ld --prefix/work/jpeg_arm_lib --exec-prefix/work/jpeg_arm_lib --enable-shared --enable-static --hostarm-none-linu…

经典文献阅读之--MGS-SLAM(单目稀疏跟踪和高斯映射与深度平滑正则化)

Tip: 如果你在进行深度学习、自动驾驶、模型推理、微调或AI绘画出图等任务&#xff0c;并且需要GPU资源&#xff0c;可以考虑使用UCloud云计算旗下的Compshare的GPU算力云平台。他们提供高性价比的4090 GPU&#xff0c;按时收费每卡2.6元&#xff0c;月卡只需要1.7元每小时&…

CiteScore 2023发布,AI Open斩获45分,位列全球计算机领域前1%

与影响因子&#xff08;IF&#xff09;一样&#xff0c;引用分数&#xff08;CiteScore&#xff09;同样是衡量学术期刊影响力的重要指标之一&#xff0c;且大有赶超前者的势头。 6 月 6 日&#xff0c;CiteScore 2023 正式发布&#xff0c;人工智能领域可自由访问的期刊平台 …

Java 8 中的 Stream API,用于处理集合数据

Java 8 引入了 Stream API&#xff0c;使得处理集合数据变得更加简洁和高效。Stream API 允许开发者以声明式编程风格操作数据集合&#xff0c;而不是使用传统的迭代和条件语句。 一、基本概念 1.1 什么是 Stream Stream 是 Java 8 中的一个新抽象&#xff0c;它允许对集合数…

工厂生产计划难以执行的真正原因及对策

在制造业中&#xff0c;生产计划的执行对于企业的运营至关重要。然而&#xff0c;许多工厂在生产计划执行过程中面临着诸多挑战&#xff0c;尤其是物料齐套率低的问题。本文将探讨工厂生产计划难以执行的真正原因&#xff0c;并提出相应的解决对策。 一、生产计划难以执行的真…

mysql optimizer_switch : 查询优化器优化策略深入解析

码到三十五 &#xff1a; 个人主页 在 MySQL 数据库中&#xff0c;查询优化器是一个至关重要的组件&#xff0c;它负责确定执行 SQL 查询的最有效方法。为了提供DBA和开发者更多的灵活性和控制权&#xff0c;MySQL 引入了 optimizer_switch 系统变量。这个强大的工具允许用户开…

nginx配置WebSocket参数wss连接

目录 一、原文连接 二、 配置参数 三、实践 四、重启nginx 五、连接websocket 一、原文连接 nginx配置websocket支持wss-腾讯云开发者社区-腾讯云 二、 配置参数 map $http_upgrade $connection_upgrade { default upgrade; close; } upstream websocket { se…

【操作系统】进程与线程的区别及总结(非常非常重要,面试必考题,其它文章可以不看,但这篇文章最后的总结你必须要看,满满的全是干货......)

目录 一、 进程1.1 PID(进程标识符)1.2 内存指针1.3 文件描述符表1.4 状态1.5 优先级1.6 记账信息1.7 上下文 二、线程三、总结&#xff1a;进程和线程之间的区别&#xff08;非常非常非常重要&#xff0c;面试必考题&#xff09; 一、 进程 简单来介绍一下什么是进程&#xf…

写入文件内容

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在实例01中&#xff0c;虽然创建并打开一个文件&#xff0c;但是该文件中并没有任何内容&#xff0c;它的大小是0KB。Python的文件对象提供了write()…

【电路笔记】-分贝

分贝 分贝是以 10 为底的对数比,用于表示电路中功率、电压或电流的增加或减少。 1、概述 一般来说,分贝是响度的度量。 在设计或使用放大器和滤波器电路时,计算中使用的一些数字可能非常大或非常小。 例如,如果我们将两个放大器级级联在一起,功率或电压增益分别为 20 和…

os和os.path模块

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 目录也称文件夹&#xff0c;用于分层保存文件。通过目录可以分门别类地存放文件。我们也可以通过目录快速找到想要的文件。在Python中&#xff0c;并…

033.搜索旋转排序数组

题意 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给方法之前&#xff0c;nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了旋转&#xff0c;使数组变为 [nums[k], nums[k1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]&…

古字画3d立体在线数字展览馆更高效便捷

在数字时代的浪潮中&#xff0c;大连图书馆以崭新的面貌跃然屏幕之上——3D全景图书馆。这座承载着城市文化精髓与丰富知识资源的数字图书馆&#xff0c;利用前沿的三维建模技术&#xff0c;为我们呈现了一个全新的知识世界。 随时随地&#xff0c;无论您身处何地&#xff0c;只…

信息学奥赛初赛天天练-22-C++基础关键字、进制转换、结构体与联合体的实用技巧大揭秘

PDF文档公众号回复关键字:20240607 单项选择题&#xff08;共15题&#xff0c;每题2分&#xff0c;共计30分&#xff1a;每题有且仅有一个正确选项&#xff09; 1 在C中&#xff0c;下面哪个关键字用于声明一个变量&#xff0c;其值不能被修改&#xff1f;&#xff08; &#…