双边滤波C#及Unity3D龟速实现

哈哈哈,我这个真是有点慢的。


先来张刘诗诗微笑,用了4秒才出结果大哭

下面是代码~~~

using System;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// 双边滤波
/// </summary>
public class BilateralFilter<T> where T:TexData,new(){
    TexData[] originalData,curData;
    int width, height;//图像宽高
    double sigma_r, sigma_d;//r,d
    double recip_2r2, recip_2d2;//2sigma平方的倒数
    /// <summary>
    /// 预计算空间域权重数组,未计算exp
    /// </summary>
    double[,] SpatialWightArray;
    int len;//窗口长宽
    int pCent;//窗口中心
    int depth;
    double sumWeight;
    /// <summary>
    /// 双边滤波
    /// </summary>
    /// <param name="texData">实现该接口的类型的数组</param>
    /// <param name="w">图片宽</param>
    /// <param name="h">图片高</param>
    /// <param name="sigma_r">sigma_r</param>
    /// <param name="sigma_d">sigma_d</param>
    /// <param name="r">窗口大小 len = 2*r + 1</param>
    public BilateralFilter(T[] texData,int w,int h,float sigma_r = 0.1f,float sigma_d = 3,int r = 1) {
        this.originalData = texData as TexData[];
        this.width = w;
        this.height = h;
        this.sigma_r = sigma_r;
        this.sigma_d = sigma_d;
        this.recip_2r2 = 1 / (0.5f * sigma_r * sigma_r);
        this.recip_2d2 = 1 / (0.5f * sigma_d * sigma_d);
        this.len = r * 2 + 1;
        pCent = len / 2;
        this.depth = this.len * this.len;
        curData = new TexData[texData.Length];
        Array.Copy(texData, curData, curData.Length);
        getSpatialWightArray();
    }
    /// <summary>
    /// 滤波
    /// </summary>
    public TexData[] Filter() {
        var tcurData = new TexData[width*height];
        Array.Copy(curData, tcurData, tcurData.Length);
        //滑动窗口以滤波
        for (int j = 0; j < height; j++) {
            for (int i = 0; i < width; i++) {
                //计算当前加权窗口
                double[,] window = new double[len, len];//当前权重窗口
                TexData tSum = new T();//窗口数据汇总
                double sumWeight = 0;
                for (int l = 0; l < len; l++) {
                    for (int k = 0; k < len; k++) {
                        var cent = At(i, j);
                        var cur = At(i, j, k, l);
                        double w1 = SpatialWightArray[k, l];
                        double w2 = similarityWeight(cent, cur);
                        window[k,l] = Math.Exp( w1+ w2);
                        sumWeight += window[k, l];
                        tSum = tSum.ADD(cur.MUL((float)window[k,l]));
                    }
                }
                tSum = tSum.DIV((float)sumWeight);
                tcurData[i+j*width] = tSum;
            }
        }

        curData = tcurData;
        return curData;
    }
    /// <summary>
    /// 重新设置参数,传入负值则不改动(未实现)
    /// </summary>
    public void ResizeParams(float sigma_r,float sigma_d,int r) { 

    }
    /// <summary>
    /// 预先计算空间域权重数组
    /// </summary>
    protected void getSpatialWightArray() {
        SpatialWightArray = new double[len,len];
        for (int k = 0; k < len; k++) {
            for (int l = 0; l < len; l++) {
                SpatialWightArray[k, l] = spatialWeight(k, l);
            }
        }
    }
    /// <summary>
    /// 空间域权重,未计算exp
    /// </summary>
    protected double spatialWeight(int k, int l) {
        double i_k_2 = Math.Pow(pCent - k, 2);
        double j_l_2 = Math.Pow(pCent - l, 2);
        return -(i_k_2 + j_l_2)*recip_2d2;
    }
    /// <summary>
    /// 值域权重,未计算exp
    /// </summary>
    protected double similarityWeight(int i, int j, int k, int l) {
        var cent = At(i, j);
        var cur = At(i, j, k, l);
        return similarityWeight(cent,cur); ;
    }
    protected double similarityWeight(TexData cent, TexData cur) {
        float grayij = cent.GetGray();
        float graykl = cur.GetGray();
        return -(Math.Pow(Math.Abs(grayij - graykl), 2)) * recip_2r2;
    }
    private TexData At(int i,int j) {
        return At(i,j,pCent,pCent);
    }
    /// <summary>
    /// 窗口内取值
    /// </summary>
    /// <returns></returns>
    private TexData At(int i, int j, int k, int l) {
        int ti, tj;
        ti = Clamp(Math.Abs(i + (k - pCent)),0,width-1);
        tj = Clamp(Math.Abs(j + (l - pCent)),0,height-1);
        return curData[ti+tj*width];
    }
    double Clamp(double v,double min,double max) {
        if (v < min)
            return min;
        else if (v > max)
            return max;
        else
            return v;
    }
    int Clamp(int v, int min, int max) {
        if (v < min)
            return min;
        else if (v > max)
            return max;
        else
            return v;
    }
}
public interface TexData {
    float R { get; }
    float G { get; }
    float B { get; }
    float A { get; }
    float GetGray();
    TexData ADD(TexData other);
    TexData SUB(TexData other);
    TexData MUL(float scale);
    TexData DIV(float scale);

}
//以下是U3D部分
public class U3DColor : TexData {
    private UnityEngine.Color col;
    public U3DColor() {
        col = new UnityEngine.Color(1, 1, 1, 1);
    }
    public U3DColor(UnityEngine.Color col) {
        this.col = col;
    }
    public float GetGray() {
        return col.grayscale;
    }

    public TexData ADD(TexData other) {
        return new U3DColor(col + new UnityEngine.Color(other.R, other.G, other.B, other.A));
    }

    public TexData SUB(TexData other) {
        return new U3DColor(col - new UnityEngine.Color(other.R, other.G, other.B, other.A));
    }

    public TexData MUL(float scale) {
        return new U3DColor(col * scale);
    }

    public TexData DIV(float scale) {
        return new U3DColor(col / scale);
    }

    public static implicit operator UnityEngine.Color(U3DColor c) {
        return c.col;
    }
    public static implicit operator U3DColor(UnityEngine.Color c) {
        return new U3DColor(c);
    }

    public float R {
        get { return col.r; }
    }

    public float G {
        get { return col.g; }
    }

    public float B {
        get { return col.b; }
    }

    public float A {
        get { return col.a; }
    }
    public override string ToString() {
        return col.ToString();
    }
}

然后是一个在U3D的调用测试

using UnityEngine;
using System.Collections;

public class Test_BilateralFilter : MonoBehaviour {

    public Texture2D inTex, outTex,combine;
    public float sigma_r, sigma_d;
	// Use this for initialization
	void Start () {
        Color[] inCol = inTex.GetPixels();
        U3DColor[] u3dInCol = new U3DColor[inCol.Length];
        for (int i = 0; i < inCol.Length; i++)
            u3dInCol[i] = inCol[i];
        BilateralFilter<U3DColor> bf = new BilateralFilter<U3DColor>(u3dInCol, inTex.width, inTex.height, sigma_r, sigma_d,1);
        float t = Time.realtimeSinceStartup;
        TexData[] data = bf.Filter();
        Color[] outCol = new Color[inCol.Length];
        for (int i = 0; i < inCol.Length; i++)
            outCol[i] = data[i] as U3DColor;

        outTex = new Texture2D(inTex.width,inTex.height);
        outTex.SetPixels(outCol);
        outTex.Apply();
        Debug.LogFormat("用时:{0}", Time.realtimeSinceStartup - t);
        combine = new Texture2D(2, 2);
        combine.PackTextures(new Texture2D[] { inTex, outTex },0);
	}
}

面板拖了一张图:



运行~,就生成outTex和Combine的图片了~~~~~可惜太慢

再来张大窗口的:


稍有改动测试参数,如下:


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值