哈哈哈,我这个真是有点慢的。
先来张刘诗诗,用了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的图片了~~~~~可惜太慢
再来张大窗口的:
稍有改动测试参数,如下: