高斯滤波器是一种线性滤波器,能够有效的抑制噪声,平滑图像

1. 正态分布

一维高斯函数的表达式(PDF)为:

image.png

这里只讲解对应的符号及函数的作用,如果大家有兴趣可以研究一下高斯函数的推导过程,即这个函数是怎么来的:国内文献关于正态分布的推导过程

我们先将公式带入到Desmos图形计算器中:

image.png

得到一个标准的正态分布曲线。(u = 0 , simga = 1)

本质上讲正态分布是整个概率论与数理统计的核心
我们观察会发现大部分的数据集中在中间,而越往两边的数据越少,这种连续随机变量概率分布的情况在生活中息息相关:例如班级里同学的身高,学习成绩好坏,以及传感器采集的信号强弱等。

这里我们直观的认为蓝牙信标的信号采集呈正态分布,那么我们接下来就通过一维的高斯函数来解释信号分布的本质:

1.1 关于s(sigma)

概率密度函数可以理解为随机变量x服从于一个数学期望u, 标准方差为pow(s, 2)的高斯分布。

举例班级里的学习平均成绩为80,则80可以理解为数学期望,而从概率学上来说,s即为班级里学习成绩的标准差,它用来形容班级成绩分布的离散程度。

当s越大,则成绩分布越分散,从图形计算器的表达上可以看出,如果s = 2时:

image.png

当s越小,则成绩分布越集中,例如s = 0.2时:

image.png

1.2 正态分布的sigma原则

sigma原则:

数值分布在(μ-s,μ+s)中的概率为0.6826;

image.png

2sigma原则:

数值分布在(μ-2s,μ+2s)中的概率为0.9544;

image.png

3sigma原则:

数值分布在(μ-3s,μ+3s)中的概率为0.9974;
image.png

从上面三个原则我们可以知道,当x取值超过3sigma基本上是千分之5的概率,在实际实验中是基本不可能发生的。本上可以把区间(μ-3s,μ+3s)看作是随机变量X实际可能的取值区间,这称之为正态分布的“3sigma”原则。

国外有一个顶尖的对冲基金叫做two-sigma, 这家公司会采用高斯混合模型来进行金融市场动态的预测建模,有兴趣可了解:Two Sigma:通过机器学习识别市场状态


注:这里要推荐一下Desmos在线图形计算工具,省去很多数学模型的绘制工作,太好用了。

2. 高斯滤波

终于进入正题了,我们现在要通过PDF函数对采集的信标信号进行过滤。在前面几篇文章我们提到了一些基础的滤波方法,例如均值滤波等等。。。

使用高斯函数时要注意的是,此函数应用在滤波降噪时,是作为一个建构模型的函数使用,并不是直接带入对应的信号值来计算。

举例来说我们要平滑某次接收到的信号,强度为80. 为了进行高斯滤波,我们需要采样其前后2次信号强度。这样我们就可以得到一个一维数组:

[ 76, 81, 80, 78, 84]

此时,我们带入高斯函数进行计算:

2.1 以80信号作为目标,我们可以设定出一个一一对应下标数组

[-2, -1, 0, 1, 2]

2.2 前面我们知道sigma越大,对应的波形宽度越宽,那么滤波目标受周围信号权重影响越大。这里我们先将此次信号分布作为一个标准的正态分布,则设置s = 1

2.3 因为滤波目标的权重下标为0,带入到PDF函数中 u = 0

image.png

计算出对应的模糊权重数组:

[0.054, 0.242, 0.399, 0.242, 0.054]

这时我们就得到了在设置好的高斯模型下的各点概率,然而这些点的权重加在一起等于0.991, 我们要进行加权平均还需要进行归一化处理。

计算后可得:

[ 0.0545, 0.244, 0.4, 0.244, 0.0545]

2.4 数值加权累加

final rssi = 0.0545 76 + 0.244 81 + 0.399 80 + 0.244 78 + 0.0545 *84 = 79.664

3. 代码实现

基于flutter代码实现高斯滤波demo

  1. /// 计算高斯filter模板
  2. List<double> getOneGuassionArray(int size, int kerR, double sigma) {
  3. if (size % 2 == 0) {
  4. size -= 1;
  5. }
  6. if (size == 0) {
  7. return [];
  8. }
  9. if (kerR > size - 1) {
  10. return [];
  11. }
  12. double sum = 0;
  13. List<double> arr = List(size);
  14. for (int i = 0; i < size; i++) {
  15. arr[i] = exp(-((i - kerR) * (i - kerR)) / (2 * sigma * sigma)) / (sqrt(2 * PI) * sigma);
  16. sum += arr[i];
  17. }
  18. return arr.map((e) => e / sum).toList();
  19. }
  20. /// 计算sigma
  21. double computedSigma(list) {
  22. double average = getAverage(list);
  23. double sigmaSum = 0;
  24. list.forEach((e) {
  25. sigmaSum += (e - average).abs();
  26. });
  27. double sigma = sigmaSum / list.length;
  28. return sigma;
  29. }
  30. /// 求序列平均值
  31. double getAverage(List list) {
  32. double sum = 0.0;
  33. int n = list.length;
  34. list.forEach((e) {
  35. sum += e;
  36. });
  37. double average = sum / n;
  38. return average;
  39. }
  40. /// 高斯滤波
  41. double sigma = computedSigma(curBeacon['store']);
  42. int size = curBeacon['store'].length;
  43. int tmpSize = (size / 2).toInt();
  44. /// 进行高斯模糊过滤
  45. /// 计算高斯权重模型
  46. int r = (tmpSize / 2).floor();
  47. List models = getOneGuassionArray(tmpSize, r, sigma);
  48. dynamic ret = 0.0;
  49. int index = 0;
  50. List<num> gaussTmp = [];
  51. curBeacon['store'].forEach((element) {
  52. if (index >= r && index <= size - r) {
  53. for (int rIndex = -r; rIndex <= r; rIndex++) {
  54. ret += element * models[rIndex + r];
  55. }
  56. } else {
  57. ret = element;
  58. }
  59. index += 1;
  60. gaussTmp.add(ret);
  61. ret = 0.0;
  62. });

到这里,我们基本上了解了高斯函数与滤波,如有兴趣可以阅读下面几篇文章进行拓展:

  1. 通过shader实现高斯分布
  2. 通过shader实现高斯模糊(二维高斯函数)