سلام.
به خاطر تعطیلات نوروز دوستان کمتر میان تو سایت.
همانطور که خودتون در بالا تصویری را قرار دادید فرمول مربوط به گوسین دو بعدی هستش که در آن سیگما میزان پراکنش توزیع را نشان میده و میزان هموار سازی بیشتر به اندازه کرنل و میزان سیگما بستگی داره .در فرمول بالا x و y به ترتیب پهنا و ارتفاع کرنل را مشخص می کند البته الزاماً فیلتر نبایستی مربعی باشد می تواند به صورت مستطیل افقی و عمودی نیز باشد که در ایت شرایط حالت خاصی از فیلتر گابور می باشد.
گوشین در واقع فیلتر پایین گذر و خطی هستش و برای کاهش نویز در تصویر مورد استفاده قرار می گیره و همانطوری که خودتون کرنلش را برای 5*5 قرار دادید در واقع کرنل مورد نظر را با تصویر اصلی کانولوشن نمایید. جهت افزایش سرعت در عملیات کانولوشن می تونید بجای استفاده از کرنل دو بعدی از دو کرنل یک بعدی گوسین استفاده کنید که یکبار تصویر را در جهت افقی با کرنل یک بعدی کانولوشن نمایید و سپس در جهت عمودی با کرنل یک بعدی کانولوشن نمایید.
کد فیلتر گوسین به c++ :
#include<iostream>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
// reflected indexing for border processing
int reflect(int M, int x)
{
if(x < 0)
{
return -x - 1;
}
if(x >= M)
{
return 2*M - x - 1;
}
return x;
}
int main()
{
Mat src, dst, temp;
float sum, x1, y1;
/// Load an image
src = imread("salt.jpg", CV_LOAD_IMAGE_GRAYSCALE);
if( !src.data )
{ return -1; }
// coefficients of 1D gaussian kernel with sigma = 1
double coeffs[] = {0.0545, 0.2442, 0.4026, 0.2442, 0.0545};
dst = src.clone();
temp = src.clone();
// along y - direction
for(int y = 0; y < src.rows; y++){
for(int x = 0; x < src.cols; x++){
sum = 0.0;
for(int i = -2; i <= 2; i++){
y1 = reflect(src.rows, y - i);
sum = sum + coeffs[i + 2]*src.at<uchar>(y1, x);
}
temp.at<uchar>(y,x) = sum;
}
}
// along x - direction
for(int y = 0; y < src.rows; y++){
for(int x = 0; x < src.cols; x++){
sum = 0.0;
for(int i = -2; i <= 2; i++){
x1 = reflect(src.cols, x - i);
sum = sum + coeffs[i + 2]*temp.at<uchar>(y, x1);
}
dst.at<uchar>(y,x) = sum;
}
}
namedWindow("final");
imshow("final", dst);
namedWindow("initial");
imshow("initial", src);
waitKey();
return 0;
}
کد فیلتر گوسین به زبان C# :
public static double[,] Calculate(int lenght, double weight)
{
double[,] Kernel = new double[lenght, lenght];
double sumTotal = 0;
int kernelRadius = lenght / 2;
double distance = 0;
double calculatedEuler = 1.0 /
(2.0 * Math.PI * Math.Pow(weight, 2));
for (int filterY = -kernelRadius;
filterY <= kernelRadius; filterY++)
{
for (int filterX = -kernelRadius;
filterX <= kernelRadius; filterX++)
{
distance = ((filterX * filterX) +
(filterY * filterY)) /
(2 * (weight * weight));
Kernel[filterY + kernelRadius,
filterX + kernelRadius] =
calculatedEuler * Math.Exp(-distance);
sumTotal += Kernel[filterY + kernelRadius,
filterX + kernelRadius];
}
}
for (int y = 0; y < lenght; y++)
{
for (int x = 0; x < lenght; x++)
{
Kernel[y, x] = Kernel[y, x] *
(1.0 / sumTotal);
}
}
return Kernel;
}
public static Bitmap ConvolutionFilter(this Bitmap sourceBitmap,
double[,] filterMatrix,
double factor = 1,
int bias = 0)
{
BitmapData sourceData = sourceBitmap.LockBits(new Rectangle(0, 0,
sourceBitmap.Width, sourceBitmap.Height),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
byte[] pixelBuffer = new byte[sourceData.Stride * sourceData.Height];
byte[] resultBuffer = new byte[sourceData.Stride * sourceData.Height];
Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
sourceBitmap.UnlockBits(sourceData);
double blue = 0.0;
double green = 0.0;
double red = 0.0;
int filterWidth = filterMatrix.GetLength(1);
int filterHeight = filterMatrix.GetLength(0);
int filterOffset = (filterWidth-1) / 2;
int calcOffset = 0;
int byteOffset = 0;
for (int offsetY = filterOffset; offsetY <
sourceBitmap.Height - filterOffset; offsetY++)
{
for (int offsetX = filterOffset; offsetX <
sourceBitmap.Width - filterOffset; offsetX++)
{
blue = 0;
green = 0;
red = 0;
byteOffset = offsetY *
sourceData.Stride +
offsetX * 4;
for (int filterY = -filterOffset;
filterY <= filterOffset; filterY++)
{
for (int filterX = -filterOffset;
filterX <= filterOffset; filterX++)
{
calcOffset = byteOffset +
(filterX * 4) +
(filterY * sourceData.Stride);
blue += (double)(pixelBuffer[calcOffset]) *
filterMatrix[filterY + filterOffset,
filterX + filterOffset];
green += (double)(pixelBuffer[calcOffset + 1]) *
filterMatrix[filterY + filterOffset,
filterX + filterOffset];
red += (double)(pixelBuffer[calcOffset + 2]) *
filterMatrix[filterY + filterOffset,
filterX + filterOffset];
}
}
blue = factor * blue + bias;
green = factor * green + bias;
red = factor * red + bias;
blue = (blue > 255 ? 255 : (blue < 0 ? 0 : blue));
green = (green > 255 ? 255 : (green < 0 ? 0 : green));
red = (red > 255 ? 255 : (red < 0 ? 0 : red));
resultBuffer[byteOffset] = (byte)(blue);
resultBuffer[byteOffset + 1] = (byte)(green);
resultBuffer[byteOffset + 2] = (byte)(red);
resultBuffer[byteOffset + 3] = 255;
}
}
Bitmap resultBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height);
BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0,
resultBitmap.Width, resultBitmap.Height),
ImageLockMode.WriteOnly,
PixelFormat.Format32bppArgb);
Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
resultBitmap.UnlockBits(resultData);
return resultBitmap;
}
برنامه کامل به زبان c# را هم می تونید از اینجا دانلود کنید.