使用C#語言編寫高斯平滑。
一、線性濾波與卷積的基本概念
2D卷積需要4個嵌套循環4-double loop,所以它並不快,除非我們使用很小的卷積核。這裏一般使用3×3或者5×5。而且,對於濾波器,也有一定的規則要求:
1)濾波器的大小應該是奇數,這樣它纔有一箇中心,例如3×3,5×5或者7×7。有中心了,也有了半徑的稱呼,例如5×5大小的核的半徑就是2。
2)濾波器矩陣所有的元素之和應該要等於1,這是爲了保證濾波前後圖像的亮度保持不變。當然了,這不是硬性要求了。
3)如果濾波器矩陣所有元素之和大於1,那麼濾波後的圖像就會比原圖像更亮,反之,如果小於1,那麼得到的圖像就會變暗。如果和爲0,圖像不會變黑,但也會非常暗。
4)對於濾波後的結構,可能會出現負數或者大於255的數值。對這種情況,我們將他們直接截斷到0和255之間即可。對於負數,也可以取絕對值。
二、卷積核
private double[,] GaussianBlur;//聲明私有的高斯模糊卷積核函數
/// <summary>
/// 構造卷積(Convolution)類函數
/// </summary>
public Convolution()
{
//初始化高斯模糊卷積核
int k=273;
GaussianBlur = new double[5, 5]{{(double)1/k,(double)4/k,(double)7/k,(double)4/k,(double)1/k},
{(double)4/k,(double)16/k,(double)26/k,(double)16/k,(double)4/k},
{(double)7/k,(double)26/k,(double)41/k,(double)26/k,(double)7/k},
{(double)4/k,(double)16/k,(double)26/k,(double)16/k,(double)4/k},
{(double)1/k,(double)4/k,(double)7/k,(double)4/k,(double)1/k}};
}
三、對圖像進行卷積平滑
/// <summary>
/// 對圖像進行平滑處理(利用高斯平滑Gaussian Blur)
/// </summary>
/// <param name="bitmap">要處理的位圖</param>
/// <returns>返回平滑處理後的位圖</returns>
public Bitmap Smooth(Bitmap bitmap)
{
int[, ,] InputPicture = new int[3, bitmap.Width, bitmap.Height];//以GRB以及位圖的長寬建立整數輸入的位圖的數組
Color color = new Color();//儲存某一像素的顏色
//循環使得InputPicture數組得到位圖的RGB
for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
color = bitmap.GetPixel(i, j);
InputPicture[0, i, j] = color.R;
InputPicture[1, i, j] = color.G;
InputPicture[2, i, j] = color.B;
}
}
int[, ,] OutputPicture = new int[3, bitmap.Width, bitmap.Height];//以GRB以及位圖的長寬建立整數輸出的位圖的數組
Bitmap smooth = new Bitmap(bitmap.Width, bitmap.Height);//創建新位圖
//循環計算使得OutputPicture數組得到計算後位圖的RGB
for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
int R=0;
int G=0;
int B=0;
//每一個像素計算使用高斯模糊卷積核進行計算
for (int r = 0; r < 5; r++)//循環卷積核的每一行
{
for (int f = 0; f < 5; f++)//循環卷積核的每一列
{
//控制與卷積核相乘的元素
int row = i - 2 + r;
int index = j - 2 + f;
//當超出位圖的大小範圍時,選擇最邊緣的像素值作爲該點的像素值
row = row < 0 ? 0 : row;
index = index < 0 ? 0 : index;
row = row >= bitmap.Width ? bitmap.Width - 1 : row;
index = index >= bitmap.Height ? bitmap.Height - 1 : index;
//輸出得到像素的RGB值
R += (int)(GaussianBlur[r, f] * InputPicture[0, row, index]);
G += (int)(GaussianBlur[r, f] * InputPicture[1, row, index]);
B += (int)(GaussianBlur[r, f] * InputPicture[2, row, index]);
}
}
color = Color.FromArgb(R,G,B);//顏色結構儲存該點RGB
smooth.SetPixel(i, j, color);//位圖存儲該點像素值
}
}
return smooth;
}