فیلتر گوسین و کرنل های آن - هفت خط کد انجمن پرسش و پاسخ برنامه نویسی

فیلتر گوسین و کرنل های آن

+4 امتیاز

تازه سایت خوبتون رو دیدم و یک موضوع تحقیق دارم و اینکه فیلتر گوسین چیه و کاربرد هاش چیه و کرنل های آن چه طوری ساخته میشه

و باید خودم در سی شارپ پیادش کنم لطفا کمکم کنید زبانم هم خوب نیست که از سایتای خارجی بخونم مرسیفیلتر مکانی, پردازش تصویر, آموزش

سوال شده فروردین 7, 1393  بوسیله ی محدثه (امتیاز 121)   9 28 42
ویرایش شده بهمن 1, 1393 بوسیله ی haniye sarbazi
کسی جواب نمیده؟

1 پاسخ

+6 امتیاز
 
بهترین پاسخ

سلام.

به خاطر تعطیلات نوروز دوستان کمتر میان تو سایت.

همانطور که خودتون در بالا تصویری را قرار دادید فرمول مربوط به گوسین دو بعدی هستش که در آن سیگما میزان پراکنش توزیع را نشان میده و میزان هموار سازی بیشتر به اندازه کرنل و میزان سیگما بستگی داره .در فرمول بالا 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# را هم می تونید از اینجا دانلود کنید.

پاسخ داده شده فروردین 9, 1393 بوسیله ی RED (امتیاز 494)   9 30 41
انتخاب شد فروردین 16, 1393 بوسیله ی haniye sarbazi
ممنون از لطفتون
اما مشکل جای دیگس که میخاسم دقیقا همین مقادیر در شکل بالا به دست بیاد
یه کم جستجو کردم و اینجا پیدا کردم که گفته بود بعد از به دست اوردن اعداد اونارو با 0.001 جمع کنید بعد روند کنید و اجام دادم و دقیقا به دست اومد. فقط دلیل اضافه کردن 0.001 رو نفهمیدم البته گفته من سر در نیاوردم این متنشه میشه بگید ترجمش چیه و دلیل اضافه کردن این عدد چی بوده؟


The idea of Gaussian smoothing is to use this 2-D distribution as a `point-spread' function, and this is achieved by convolution. Since the image is stored as a collection of discrete pixels we need to produce a discrete approximation to the Gaussian function before we can perform the convolution. In theory, the Gaussian distribution is non-zero everywhere, which would require an infinitely large convolution kernel, but in practice it is effectively zero more than about three standard deviations from the mean, and so we can truncate the kernel at this point. Figure 3 shows a suitable integer-valued convolution kernel that approximates a Gaussian with a Eqn:eqnsigma of 1.0. It is not obvious how to pick the values of the mask to approximate a Gaussian. One could use the value of the Gaussian at the centre of a pixel in the mask, but this is not accurate because the value of the Gaussian varies non-linearly across the pixel. We integrated the value of the Gaussian over the whole pixel (by summing the Gaussian at 0.001 increments). The integrals are not integers: we rescaled the array so that the corners had the value 1.
جهت سرعت در انجام عملیات کانولوشن سعی می شود که عملیات به صورت عدد صحیح صورت بگیرید
به همین خاطر بایستی کرنل اعشاری را به مقادیر صحیح معادل تبدیل نمائید.چون در کرنل های بزرگ مقادیر در حاشیه کرنل به صفر میل می کند به همین خاطر سعی می شود کل مقادیر در ابتدا با یک عدد خیلی کوچک جمع شود که مقدار هیچ خانه ای صفر نباشد سپس با مقادیر جدید را تغییر مقیاس می دهند که مقادیر حاشیه که به صفر میل می کردند به یک تبدیل شده و بقیه مقادیر هم به تناسب تغییر مقیاس می دهند.
خوب چرا دقیقا مقدار یک هزارم رو جمع کرده؟اگر مقدار دیگه ای جمع کنه ضرایب کلا فرق میکنه.
...