1.简介
高斯模糊是图像处理中的常用算法,下图就是对一块区域以外的区域进行模糊处理以凸显这块区域。
高斯模糊很多可能不大了解,但对于另外一个知识点,正态分布 ,相信大多数人都学过。维基百科中文页对高斯模糊有一这样的解释“从数学的角度来看,图像的高斯模糊过程就是图像与正态分布做卷积。由于正态分布又叫作“高斯分布”,所以这项技术就叫作高斯模糊”。
由于之后要介绍的Unity运行时动态编辑地形需要用到,所以今天打算先介绍一下高斯模糊的知识。高斯模糊的处理过程其实就是拿图像周围几个像素点的信息按比例制进行计算,对地形的平滑处理也是一样,拿到周围几个点的高度信息再按比列计算,需要处理的数据不同,但方法相同。在计算某个点均值的时候,我们只需要需其作为原点,其他周围的点按照各自在正态曲线上的位置取权重,最后就可以的到一个加权平均数。
2.高斯函数
正态分布的密度函数叫做高斯函数,高斯函数实际上是一个函数族,上图所展示的是一维高斯函数,其公式是
图像和地形平滑要处理的数据都是一个二维数组,所以我们需要的是一个二维的高斯函数,其公式和大致图像如下(图是我用Unity的地形做的,请忽略旁边的树)
3.高斯核
我们假设中心点的坐标为(0,0),外维一圈的8个点的相对坐标如下(如果需要,可以将半径设的大一些)
二维高斯函数公式中的 σ代表方差,我们设为1.5,u和v分别表示相对坐标中x和y轴上的值。将相对坐标带入二维高斯函数后的到
我们发现 所有权值加起来并不等于1,所以我们要进行最后一步处理,将他们各自的值除以所有权值的和,最后得到的高斯核如下
有了高斯核我们就可以进行加权平均了,下面直接上代码,利用高斯模糊对二维数组的数据进行处理。
/// <summary> /// 对二维数组做高斯模糊 /// </summary> /// <param name="array">要处理的数组</param> /// <param name="dev">方差</param> /// <param name="r">高斯核扩展半径</param> /// <param name="isCircle">改变形状是否是圆</param> public static void GaussianBlur(float[,] array, float dev = 1.5f, int r = 1, bool isCircle = true) { // 构造半径为1的高斯核 int length = r * 2 + 1; float[,] gaussianCore = new float[length, length]; float k = 1 / (2 * Mathf.PI * dev * dev); for (int i = 0; i < length; i++) { for (int j = 0; j < length; j++) { float pow = -((j - r) * (j - r) + (i - r) * (i - r)) / (2 * dev * dev); gaussianCore[i, j] = k * Mathf.Pow(2.71828f, pow); } } // 使高斯核权值和为1 float sum = 0; for (int i = 0; i < length; i++) { for (int j = 0; j < length; j++) { sum += gaussianCore[i, j]; } } for (int i = 0; i < length; i++) { for (int j = 0; j < length; j++) { gaussianCore[i, j] /= sum; } } // 对二维数组进行高斯模糊处理 int circleR = array.GetLength(0) / 2; for (int i = r, length_0 = array.GetLength(0) - r; i < length_0; i++) { for (int j = r, length_1 = array.GetLength(1) - r; j < length_1; j++) { if (isCircle && (i - circleR) * (i - circleR) + (j - circleR) * (j - circleR) > (circleR - r) * (circleR - r)) continue; // 用高斯核处理一个值 float value = 0; for (int u = 0; u < length; u++) { for (int v = 0; v < length; v++) { if ((i + u - r) >= array.GetLength(0) || (i + u - r) < 0 || (j + v - r) >= array.GetLength(1) || (j + v - r) < 0) Debug.LogError("滴嘟滴嘟的报错"); else value += gaussianCore[u, v] * array[i + u - r, j + v - r]; } } array[i, j] = value; } } }