OpenGL-高斯模糊原理

OpenGL-高斯模糊原理

正态分布

在这里插入图片描述
上图人类的智商分布比例,大多数人的智商集中在85-115,超高和超低智商的人只占很小的比例,柱状图可用一条曲线拟合,如图中红色曲线所示. 这个钟形曲线就是正态分布曲线. 正态分布曲线体现了宇宙中很多事物的分布规律,比如全国身高的分布,年级考试成绩的分布,气体分子运动速度的分布,抛10个硬币1000次正面向上的次数分布,等等都符合正态分布.

正态分布试验

在这里插入图片描述
正态分布,可描述某事件大量发生时的分布规律,或某事件单独发生的可能性,也就是概率. 事件发生后,可用统计解释,发生前可用概率预测. 图2-2的装置叫做高尔顿钉板,可验证大量重复试验的结果符合正态分布. 小球从顶部落下,会经过很多钉子,每碰到一个钉子,小球弹向左边或右边的概率都是1/2,落在最左边或者最右边的概率非常低,落在中间的概率最高,所以可以用正态分布描述小球落入区间的分布.

正态分布的数学公式

在这里插入图片描述

数学公式:

在这里插入图片描述
曲线表示概率密度变化,x轴数值表示试验结果,函数值是这个结果对应的概率, 比如某人智商是x=130的概率是f(x),或者说人类中智商是x=130的所占的比例是f(x). 曲线积分(曲线和x轴围成的面积)等于1,即所有可能的情况(x的取值值)的概率和(求积分)是1,比如某人的智商是x∈[0-150](全部可能性)的概率是1.

x=μ,对应钟形曲线最高点,μ是x的概率加权平均值,叫期望E(X),期望就是平均值,比如智商统计的曲线中μ=100,那么人类的平均智商就是100. μ=0时,平均值就是0,如图.小明和小红的智商是90和110,平均值是:(90+110)/2=100

σ2的平方是方差,即Var(X)=E[(X-μ)2 ],即所有x与平均值的差,平方,求和,最后平均. 方差表示样本的平均波动大小,比如小明和小红的智商是90和110,平均值是100,方差是[(90-100)2+(110-100)2 ]/2=100,再比如小明和小红的智商是50和150,平均值也是100,但是方差(波动性)要大得多, [(50-100)2+(150-100)2 ]/2=2500

从正态分布到高斯模糊

**均值模糊:**将中心像素和周围像素颜色数值加起来求平均,作为中心像素的模糊结果

**中值模糊:**把中心像素和周围像素的颜色排个顺序,取中间像素的颜色数值作为模糊结果

**高斯模糊:**中间像素和周围像素对模糊的权重(重要性)不一样,且权重遵循正态分布,进行加权平均. 换句话说,高斯模糊就是参与模糊的像素(中间像素和周围像素)的重要性,符合正态分布,所以按照正态分布的规律加权平均就是最后的模糊数值,中间像素权重(百分比)最大,越往边上,权重(百分比)越小,且所有的权重(百分比)的和应该是1,即100%. 正态分布又叫做高斯分布,所以这种模糊又叫高斯模糊. 中间像素的权重最大,对应钟形曲线最高点,左右像素的权重对称相等,所以μ=0 ,曲线关于y轴对称;σ决定了曲线的陡峭程度,σ=1的曲线相对平滑,那么模糊也会相对平滑. 高斯模糊的像素权重分布,采用的正态分布函数如下:
在这里插入图片描述
在这里插入图片描述
正态分布是连续的,纹理采样点是离散问题有限的,对于每个纹素,不可能采样整张图像,按照正态分布加权平均,最后生成该纹素点的模糊值. 出于效率考虑,假设在目标纹素左右,以Δx为间隔,各采样2个点,包括中心的目标纹素共5个点,如图2-5. 那么应该将这5个点,映射在正态分布多大的范围内,来取得权重呢?正态分布的样本空间是[-∞,+∞], 在 图2-5中,当 x∈[μ-2σ,μ+2σ] 时,概率(权重)总和已经达到95%, 接近100%,再靠边缘的样本对最后结果的贡献非常非常小, 所以仅需要在正态分布的[μ-2σ,μ+2σ]区间中计算权重即可.

当分布函数为f(x)=1/√2π e(-x2/2),即μ=0,σ=1时,区间[-2,+2]权重占到95%. 那么5个纹理采样点,映射到正态分布的区间[-2,+2]上,得到正态分布曲线的x值为-2,-1,0,1,2,得到5个纹理采样点对应的5个权重值,或者说这5个纹素对于目标纹素点模糊的贡献比例为:

f(0)=“0.3989”, f(1)=“0.2420”, f(2)=“0.0540”,f(-1)=“0.2420”, f(-2)=“0.0540”,

但这些权重加起来不是1,而是

∑_(i=1)^5▒〖f(i)=0.0540+0.2420+0.3989+0.2420+0.0540=〗 0.9909
在[-2,+2]区间,权重总和不是应该占95%吗,怎么是99%呢?这是因为,这个95%是积分计算的结果,而此处的结果是离散数据计算的.如图2-5-2

在这里插入图片描述
在这里插入图片描述

二维高斯模糊

图像是二维的,那么模糊权重也应该是二维的,所以将正态分布从一维扩展到二维,公式为:
在这里插入图片描述
二维的高斯算子,是x,y两个参数共同决定的, 离远点越近,权重值越大. 如果在目标纹素周围5*5的范围采样,需要把这25个纹素采样点映射到x∈[-2,+2],y∈[-2,+2]的区间内的25个(x,y)坐标,计算得到25个权重,再对25个纹理采样颜色分别乘以权重,得到加权求平均值,即最终的高斯模糊颜色,如图所示.
在这里插入图片描述

在这里插入图片描述

横竖高斯模糊处理

在这里插入图片描述
按上面的知识进行水平模糊后再进行竖直模糊得到下图
在这里插入图片描述

上面知识采用该文章原文

上面知识点总结

1、正态分布原理,对应公式
2、高斯模糊,取任意点上下左右对称点位置像素进行正态分布处理,权重相加约等于1,标准高斯模糊,权重中间像素权重(百分比)最大,越往边上,权重(百分比)越小。
3、高斯模糊分横竖方向两部,按一纬高斯模糊分别进行处理
在这里插入图片描述

GLSL代码部分

具体的说明我已经,在代码进行注解,按的标准高斯模糊,weight是权重,权重值的设定可能是根据特定需求或者视觉效果来调整的。虽然标准情况下权重是随着距离增大而减小的(如正常的高斯分布),但在实际应用中可能会根据具体情况进行微调。正常调整不一样靠中间的值越大,需要自己注意和理解

/**
 * 对texelWidthOffset和texelHeightOffset是1.5f / videoWidth.5f / videoHeight,横向高斯模糊texelWidthOffset,为0,竖直方向高斯模糊texelWidthOffset为0
 *singleStepOffset对应乘1-5分别,为了取像素点vTexCoord(x,y)横向时候取左右5个像素点,竖直时候取上下5个像素点
 */

static const char* gauss_vertex_shader ="attribute vec4 position;\n"
                                        "attribute vec2 texCoord;\n"
                                        "\n"
                                        "uniform float texelWidthOffset;\n"
                                        "uniform float texelHeightOffset;\n"
                                        "\n"
                                        "varying vec2 vTexCoord;\n"
                                        "varying vec2 blurCoordinates[11];\n"
                                        "\n"
                                        "void main()\n"
                                        "{\n"
                                        "    gl_Position = position;\n"
                                        "    vTexCoord = texCoord.xy;\n"
                                        "\n"
                                        "    vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);\n"
                                        "    blurCoordinates[0] = texCoord.xy;\n"
                                        "    blurCoordinates[1] = texCoord.xy + singleStepOffset * 1.0;\n"
                                        "    blurCoordinates[2] = texCoord.xy - singleStepOffset * 1.0;\n"
                                        "    blurCoordinates[3] = texCoord.xy + singleStepOffset * 2.0;\n"
                                        "    blurCoordinates[4] = texCoord.xy - singleStepOffset * 2.0;\n"
                                        "    blurCoordinates[5] = texCoord.xy + singleStepOffset * 3.0;\n"
                                        "    blurCoordinates[6] = texCoord.xy - singleStepOffset * 3.0;\n"
                                        "    blurCoordinates[7] = texCoord.xy + singleStepOffset * 4.0;\n"
                                        "    blurCoordinates[8] = texCoord.xy - singleStepOffset * 4.0;\n"
                                        "    blurCoordinates[9] = texCoord.xy + singleStepOffset * 5.0;\n"
                                        "    blurCoordinates[10] = texCoord.xy - singleStepOffset * 5.0;\n"
                                        " }";
/**
 * blurCoordinates对应像素点,进行 sum += texture2D(texture, blurCoordinates[0]) * weight;
 * weight是权重,权重之和要约等于1,
 *
 */
static const char* gauss_fragment_shader ="precision highp float;\n"
                                          "uniform sampler2D texture;\n"
                                          "\n"
                                          "uniform float texelWidthOffset;\n"
                                          "uniform float texelHeightOffset;\n"
                                          "\n"
                                          "varying vec2 vTexCoord;\n"
                                          "\n"
                                          "varying highp vec2 blurCoordinates[11];\n"
                                          "\n"
                                          "void main()\n"
                                          "{\n"
                                          "    vec4 tex = texture2D(texture, vTexCoord);\n"
                                          "    vec4 sum = vec4(0.0);\n"
                                          "    sum += texture2D(texture, blurCoordinates[0]) * 0.180590;\n"
                                          "    sum += texture2D(texture, blurCoordinates[1]) * 0.146265;\n"
                                          "    sum += texture2D(texture, blurCoordinates[2]) * 0.146265;\n"
                                          "    sum += texture2D(texture, blurCoordinates[3]) * 0.136940;\n"
                                          "    sum += texture2D(texture, blurCoordinates[4]) * 0.136940;\n"
                                          "    sum += texture2D(texture, blurCoordinates[5]) * 0.078710;\n"
                                          "    sum += texture2D(texture, blurCoordinates[6]) * 0.078710;\n"
                                          "    sum += texture2D(texture, blurCoordinates[7]) * 0.035367;\n"
                                          "    sum += texture2D(texture, blurCoordinates[8]) * 0.035367;\n"
                                          "    sum += texture2D(texture, blurCoordinates[9]) * 0.012422;\n"
                                          "    sum += texture2D(texture, blurCoordinates[10]) * 0.012422;\n"
                                          "\n"
                                          "    gl_FragColor = sum;\n"
                                          "}\n"
                                          "";

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】static关键字及其修饰的静态成员变量/函数详解

🦄个人主页:修修修也 🎏所属专栏:C ⚙️操作环境:Visual Studio 2022 目录 什么是static? static的引入 静态数据的存储 全局(静态)存储区 static成员概念 static成员特性 ststic成员的应用 利用static实现一个可以计算程序中正在使用的类对象有…

使用 Docker Compose 安装 Harbor

Harbor 是一个企业级开源仓库,用于存储和管理 Docker 镜像。它提供了一系列功能,包括镜像复制、安全扫描和漏洞管理。Harbor 可以通过多种方式安装,其中之一是使用 Docker Compose。 先决条件 在安装 Harbor 之前,您需要满足以下…

golang sync.Map之如何设计一个并发安全的读写分离结构?

在 golang中,想要并发安全的操作map,可以使用sync.Map结构,sync.Map 是一个适合读多写少的数据结构,今天我们来看看它的设计思想,来看看为什么说它适合读多写少的场景。 如下,是golang 中sync.Map的数据结构…

详细分析Js中的Promise.all基本知识(附Demo)

目录 1. 基本知识2. Demo3. 实战 1. 基本知识 Promise.all 是 JavaScript 中的一个方法,它接受一个由 Promise 对象组成的数组作为参数,并在所有 Promise 对象都变为 resolved(已完成)状态时才返回一个新的 Promise 对象&#xf…

KTV点歌系统|基于JSP技术+ Mysql+Java+ B/S结构的KTV点歌系统设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java,ssm,springboot的平台设计与实现项目系统开发资源(可…

MyBatis是纸老虎吗?(四)

在《MyBatis是纸老虎吗?(三)》这篇文章中我们一起梳理了MyBatis配置文件的解析流程,并详细介绍了其中的一些常见节点的解析步骤。通过梳理,我们弄清楚了MyBatis配置文件中的一些常用配置项与Java Bean之间的对应关系&a…

linux网线正常,但没有网络,ifconfig没有ip地址

ubuntu 22.04环境: 今天正在用着好好的,不知道为什么突然没有网络了,网线灯也不亮,ifconfig只有lo回环地址。 因为装的双系统,切换到windows环境发现网络是正常的。 使用-a: 使用各种方式比如下面的命令…

大模型应用开发-虚拟人-AI刘能、AI李宏伟

简介 本案例通过python编程调用智谱的大模型接口,以及很简单的prompt设计,实现了用大语言模型模拟一个人物来和我们对话,前端HTML代码是用大语言模型生成的(原因:我根本不会写前端啊~~),本教程适合所有对大模型应用开发感兴趣的初学者,这是个非常有趣的案例。 读完本…

excel 破解 保护工作簿及保护工作表

excel 破解 保护工作簿及保护工作表 对于这种 保护工作簿及保护工作表 不知道密码时,可以使用以下方法破解 保护工作簿破解 打开受保存的excel 右键点击sheet名称 —> 查看代码 复制以下代码,粘贴到代码区域 Sub 工作簿密码破解() ActiveWorkbook.…

C语言例:(m=a==b)||(n=a==b);求解m,n的值

题目&#xff1a;设int a0,b0,m0,n0;执行语句(mab)||(nab);求解m,n的值。 #include<stdio.h> int main(void) {int a0,b0,m0,n0;(mab)||(nab);printf("m%d\n",m);printf("n%d\n",n);return 0; } 优先级: () 优先 优先 a b -->为真&am…

Python元组:不可变的序列

文章目录 一、元组1.创建元组2.访问元组中的元素3.修改元组4.删除元组 二、运算符1.加法运算符2.乘法运算符3.in运算符4.not in运算符 三、元组内置方法1.len()2.max()3.min()4.tuple()4.1 将列表转换成元组4.2 将字符串转换成元组4.3 将集合转换成元组 三、总结 一、元组 在P…

【5G NB-IoT NTN】3GPP R17 NB-IoT NTN介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

10000字!一文学会SQL数据分析

文章来源于山有木兮 原文链接&#xff1a;https://edu.cda.cn/goods/show/3412?targetId5695&preview0 第1节 SQL简介与基础知识 做数据分析的&#xff0c;为什么要写SQL&#xff1f; 没有数据的情况下&#xff0c;我们分析数据就像是巧妇难为无米之炊。因此&#xff0c…

Netty学习——源码篇3 服务端Bootstrap(一) 备份

1 介绍 在分析客户端的代码中&#xff0c;已经对Bootstrap启动Netty有了一个大致的认识&#xff0c;接下来在分析服务端时&#xff0c;就会相对简单。先看一下服务端简单的启动代码。 public class ChatServer {public void start(int port) throws Exception{NioEventLoopGro…

解锁鸿蒙小程序开发新姿势

如今&#xff0c;鸿蒙开发日益受到广大开发者的关注&#xff0c;而小程序开发也早已成为互联网领域的热门话题。那么&#xff0c;我们不禁要问&#xff1a;是否有可能将这两者融为一体&#xff0c;将小程序开发的便捷与高效带入鸿蒙生态中呢&#xff1f;本文将首先带你回顾小程…

SpringCloud alibaba入门简介

SpringCloud alibaba入门简介 1、简介 SpringCloud alibaba官网&#xff1a;SpringCloudAlibaba | Spring Cloud Alibaba (aliyun.com) Spring官网&#xff1a;Spring Cloud Alibaba GitHub中文文档&#xff1a;spring-cloud-alibaba/README-zh.md at 2022.x alibaba/spri…

数据库基本介绍及编译安装mysql

目录 数据库介绍 数据库类型 数据库管理系统&#xff08;DBMS&#xff09; 数据库系统 DBMS的工作模式 关系型数据库的优缺点 编译安装mysql 数据库介绍 数据&#xff1a;描述事物的的符号纪录称为数据&#xff08;Data&#xff09; 表&#xff1a;以行和列的形式组成…

公众号怎么更换主体

公众号账号迁移的作用是什么&#xff1f;只能变更主体吗&#xff1f;1.可合并多个公众号的粉丝、文章&#xff0c;打造超级大V2.可变更公众号主体&#xff0c;更改公众号名称&#xff0c;变更公众号类型——订阅号、服务号随意切换3.可以增加留言功能4.个人订阅号可迁移到企业名…

零知识玩转AVH(8)—— 门槛任务(3)所遇错误及解决(2)

接前一篇文章&#xff1a;零知识玩转AVH&#xff08;7&#xff09;—— 门槛任务&#xff08;2&#xff09;所遇错误及解决&#xff08;1&#xff09; 上一回说到在尝试完成门槛任务 https://github.com/ArmDeveloperEcosystem/Paddle-examples-for-AVH &#xff08;推荐&#…

阿里G6 树状图使用 Iconfont

官网&#xff1a;使用 Iconfont | G6 效果&#xff1a; 完整代码&#xff1a;index.html: <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width…