Unity 3D : 高斯核

應用 :

同樣是高斯核,但維度不同,就可以做出很多變化,產生很多玩法 :

一維高斯核 : 統計分析
二維高斯核 : 將圖片做高斯模糊
三維高斯核 : 點光源

下圖為 3D 高斯核做的點光源範例 :

Unity 3D : 高斯核


說明 :

公式會用到兩個常數 ( μ 與 σ ),這兩個值可以自訂義。

μ ( mu ) : 分布的位置 ( 一般為中心點 )
σ ( sigma ) : 標準差,分布的幅度

由下圖可以看到 σ ( sigma ) 越小幅度越大 :

Unity 3D : 高斯核

σ ( sigma ) 也稱作標準差,由下圖可以表示 :

標準差 ± 1 = 34.1 * 2 = 68.2%
標準差 ± 2 = (34.1+13.6) * 2 = 95.4%
標準差 ± 3 = (34.1+13.6+2.1) * 2 = 99.6%

Unity 3D : 高斯核


一維高斯核公式 :

f(x)=12πσe(μx)22σ2f(x)=\dfrac{1}{\sqrt{2\pi\sigma}}e-\dfrac{(\mu-x)^2}{2\sigma^2}

同等 :

f(x)=exp{(μx)22σ2}2πσf(x)=\dfrac{exp\{-\dfrac{(\mu-x)^2}{2\sigma^2}\}}{\sqrt{2\pi\sigma}}


二維高斯核公式 :

f(x)=12πσ2e(μx)2+(μy)22σ2f(x)=\dfrac{1}{\sqrt{2\pi\sigma^2}}e-\dfrac{(\mu-x)^2+(\mu-y)^2}{2\sigma^2}

同等 :

f(x)=exp{(μx)2+(μy)22σ2}2πσ2f(x)=\dfrac{exp\{-\dfrac{(\mu-x)^2+(\mu-y)^2}{2\sigma^2}\}}{\sqrt{2\pi\sigma^2}}


三維高斯核公式 :

f(x)=12πσ3e(μx)2+(μy)2+(μz)22σ2f(x)=\dfrac{1}{\sqrt{2\pi\sigma^3}}e-\dfrac{(\mu-x)^2+(\mu-y)^2+(\mu-z)^2}{2\sigma^2}

同等 :

f(x)=exp{(μx)2+(μy)2+(μz)22σ2}2πσ3f(x)=\dfrac{exp\{-\dfrac{(\mu-x)^2+(\mu-y)^2+(\mu-z)^2}{2\sigma^2}\}}{\sqrt{2\pi\sigma^3}}


程式碼 :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        float[] data = GaussTable_1D(5, 1.5f);

        float sum = 0;

        string txt = "";

        for (int x = 0; x < data.Length; x++)
        {
            txt += data[x].ToString("0.00") + ", ";

            sum += data[x];
        }

        print("1D : \n\n" + txt + "\n");

        print("1D Sum : " + sum);


        // --------------------------------------

        float[,] data2 = GaussTable_2D(5, 1.5f);

        sum = 0;

        txt = "";

        for (int y = 0; y < data2.GetLength(1); y++)
        {
            for (int x = 0; x < data2.GetLength(0); x++)
            {
                txt += data2[x, y].ToString("0.00") + ", ";
                sum += data2[x, y];
            }
            txt += "\n";
        }

        print("2D : \n\n" + txt);

        print("2D Sum : " + sum);


        // --------------------------------------

        float[,,] data3 = GaussTable_3D(5, 1.5f);

        sum = 0;

        txt = "";

        for (int z = 0; z < data3.GetLength(2); z++)
        {
            for (int y = 0; y < data3.GetLength(1); y++)
            {
                for (int x = 0; x < data3.GetLength(0); x++)
                {
                    txt += data3[x, y, z].ToString("0.000") + ", ";
                    sum += data3[x, y, z];
                }
                txt += "\n";
            }

            txt += "\n";
            txt += "\n";
        }

        print("3D : \n\n" + txt);

        print("3D Sum : " + sum);        
    }

    float[] GaussTable_1D(int size, float sigma)
    {
        float[] result = new float[size];
        float u = (size - 1) / 2f; // 中心點座標
        float sum = 0;

        for (int x = 0; x < size; x++)
        {
            result[x] = Mathf.Exp(-(u - x) * (u - x)) / (2 * (sigma * sigma) / (Mathf.Sqrt(2 * Mathf.PI * sigma)));
            sum += result[x];
        }

        for (int x = 0; x < size; x++)
        {
            result[x] /= sum;
        }

        return result;
    }


    float[,] GaussTable_2D(int size, float sigma)
    {
        float[,] result = new float[size, size];
        float u = (size - 1) / 2f; // 中心點座標
        float sum = 0;

        for (int y = 0; y < size; y++)
        {
            for (int x = 0; x < size; x++)
            {
                float temp1 = (u - x) * (u - x) + (u - y) * (u - y);
                float temp2 = 2 * sigma * sigma;
                float temp3 = Mathf.Sqrt(2 * Mathf.PI * sigma * sigma);
                float temp4 = Mathf.Exp(-temp1 / temp2) / temp3;

                result[x, y] = temp4;
                sum += temp4;
            }
        }

        for (int y = 0; y < size; y++)
        {
            for (int x = 0; x < size; x++)
            {
                result[x, y] /= sum;
            }
        }

        return result;
    }


    float[,,] GaussTable_3D(int size, float sigma)
    {
        float[,,] result = new float[size, size, size];
        float u = (size - 1) / 2f; // 中心點座標
        float sum = 0;

        for (int z = 0; z < size; z++)
        {
            for (int y = 0; y < size; y++)
            {
                for (int x = 0; x < size; x++)
                {
                    float temp1 = (u - x) * (u - x) + (u - y) * (u - y) + (u - z) * (u - z);
                    float temp2 = 2 * sigma * sigma;
                    float temp3 = Mathf.Sqrt(2 * Mathf.PI * sigma * sigma * sigma);
                    float temp4 = Mathf.Exp(-temp1 / temp2) / temp3;

                    result[x, y, z] = temp4;
                    sum += temp4;
                }
            }
        }

        for (int z = 0; z < size; z++)
        {
            for (int y = 0; y < size; y++)
            {
                for (int x = 0; x < size; x++)
                {
                    result[x, y, z] /= sum;
                }
            }
        }

        return result;
    }

}

輸出結果 :

1D :
Unity 3D : 高斯核

2D :
Unity 3D : 高斯核

3D :
Unity 3D : 高斯核


參考 :

资源 | 一文学会统计学中的显著性概念 : http://www.ijiandao.com/2b/baijia/173862.html