【问题标题】:Image remains unchanged after convolution卷积后图像保持不变
【发布时间】:2014-01-16 01:59:14
【问题描述】:

我正在尝试基于来自AForge 框架的源执行高斯模糊计算。目前,虽然我的计算有问题,因为我从进程中获取了与我输入的相同的像素数据。(我认为需要做一些事情来计算除数)

这个过程分为两部分:

  1. 基于使用设定大小创建的内核创建高斯滤波器。

  2. 根据像素数组(rgba 结构)处理过滤器,以返回转换后的像素,这些像素稍后会转换为位图。

我创建的原始内核转换为基于整数的内核的方法已经针对其他程序进行了测试,并且在其实现中是正确的。

任何帮助将不胜感激。在过去的 12 个小时里,我一直在努力解决这个问题。

创建过滤器的方法

/// <summary>
/// Create a 2 dimensional Gaussian kernel using the Gaussian G(x y)  
/// function for blurring images.
/// </summary>
/// <param name="kernelSize">Kernel Size</param>
/// <returns>A Gaussian Kernel with the given size.</returns>
public double[,] CreateGuassianBlurFilter(int kernelSize)
{
    // Create kernel
    double[,] kernel = this.CreateGaussianKernel2D(kernelSize);
    double min = kernel[0, 0];

    // Convert to integer blurring kernel. First of all the integer kernel
    // is calculated from Kernel2D
    // by dividing all elements by the element with the smallest value.
    double[,] intKernel = new double[kernelSize, kernelSize];
    int divider = 0;

    for (int i = 0; i < kernelSize; i++)
    {
        for (int j = 0; j < kernelSize; j++)
        {
            double v = kernel[i, j] / min;

            if (v > ushort.MaxValue)
            {
                v = ushort.MaxValue;
            }

            intKernel[i, j] = (int)v;

            // Collect the divider
            divider += (int)intKernel[i, j];
        }
    }

    // Update filter
    this.Divider = divider;
    return intKernel;
}

以及执行卷积的方法:

/// <summary>
/// Processes the given kernel to produce an array of pixels representing a 
/// bitmap.
/// </summary>
/// <param name="pixels">The raw pixels of the image to blur</param>
/// <param name="kernel">
/// The Gaussian kernel to use when performing the method</param>
/// <returns>An array of pixels representing the bitmap.</returns>
public Pixel[,] ProcessKernel(Pixel[,] pixels, double[,] kernel)
{
    int width = pixels.GetLength(0);
    int height = pixels.GetLength(1);
    int kernelLength = kernel.GetLength(0);
    int radius = kernelLength >> 1;
    int kernelSize = kernelLength * kernelLength;
    Pixel[,] result = new Pixel[width, height];

    // For each line
    for (int y = 0; y < height; y++)
    {
        // For each pixel
        for (int x = 0; x < width; x++)
        {
            // The number of kernel elements taken into account
            int processedKernelSize;

            // Colour sums
            double blue;
            double alpha;
            double divider;
            double green;
            double red = green = blue = alpha = divider = 
                         processedKernelSize = 0;

            // For each kernel row
            for (int i = 0; i < kernelLength; i++)
            {
                int ir = i - radius;
                int position = y + ir;

                // Skip the current row
                if (position < 0)
                {
                    continue;
                }

                // Outwith the current bounds so break.
                if (position >= height)
                {
                    break;
                }

                // For each kernel column
                for (int j = 0; j < kernelLength; j++)
                {
                    int jr = j - radius;
                    position = x + jr;

                    // Skip the column
                    if (position < 0)
                    {
                        continue;
                    }

                    if (position < width)
                    {
                        double k = kernel[i, j];
                        Pixel pixel = pixels[x, y];

                        divider += k;

                        red += k * pixel.R;
                        green += k * pixel.G;
                        blue += k * pixel.B;
                        alpha += k * pixel.A;

                        processedKernelSize++;
                    }
                }
            }

            // Check to see if all kernel elements were processed
            if (processedKernelSize == kernelSize)
            {
                // All kernel elements are processed; we are not on the edge.
                divider = this.Divider;
            }
            else
            {
                // We are on an edge; do we need to use dynamic divider or not?
                if (!this.UseDynamicDividerForEdges)
                {
                    // Apply the set divider.
                    divider = this.Divider;
                }
            }

            // Check and apply the divider
            if ((long)divider != 0)
            {
                red /= divider;
                green /= divider;
                blue /= divider;
                alpha /= divider;
            }

            // Add any applicable threshold.
            red += this.Threshold;
            green += this.Threshold;
            blue += this.Threshold;
            alpha += this.Threshold;

            result[x, y].R = (byte)((red > 255) 
                           ? 255 : ((red < 0) ? 0 : red));               
            result[x, y].G = (byte)((green > 255) 
                           ? 255 : ((green < 0) ? 0 : green));
            result[x, y].B = (byte)((blue > 255) 
                           ? 255 : ((blue < 0) ? 0 : blue));
            result[x, y].A = (byte)((alpha > 255) 
                           ? 255 : ((alpha < 0) ? 0 : alpha));
        }
    }

    return result;
}

【问题讨论】:

    标签: c# image-processing gdi+ gaussian convolution


    【解决方案1】:

    问题在于选择要乘以内核值的正确像素。我没有选择适当的偏移量,而是选择了相同的像素。

    修正方法如下。

    /// <summary>
    /// Processes the given kernel to produce an array of pixels representing a 
    /// bitmap.
    /// </summary>
    /// <param name="pixels">The raw pixels of the image to blur</param>
    /// <param name="kernel">
    /// The Gaussian kernel to use when performing the method</param>
    /// <returns>An array of pixels representing the bitmap.</returns>
    public Pixel[,] ProcessKernel(Pixel[,] pixels, double[,] kernel)
    {
        int width = pixels.GetLength(0);
        int height = pixels.GetLength(1);
        int kernelLength = kernel.GetLength(0);
        int radius = kernelLength >> 1;
        int kernelSize = kernelLength * kernelLength;
        Pixel[,] result = new Pixel[width, height];
    
        // For each line
        for (int y = 0; y < height; y++)
        {
            // For each pixel
            for (int x = 0; x < width; x++)
            {
                // The number of kernel elements taken into account
                int processedKernelSize;
    
                // Colour sums
                double blue;
                double alpha;
                double divider;
                double green;
                double red = green = blue = alpha = divider = 
                             processedKernelSize = 0;
    
                // For each kernel row
                for (int i = 0; i < kernelLength; i++)
                {
                    int ir = i - radius;
                    int iposition = y + ir;
    
                    // Skip the current row
                    if (iposition < 0)
                    {
                        continue;
                    }
    
                    // Outwith the current bounds so break.
                    if (iposition >= height)
                    {
                        break;
                    }
    
                    // For each kernel column
                    for (int j = 0; j < kernelLength; j++)
                    {
                        int jr = j - radius;
                        int jposition = x + jr;
    
                        // Skip the column
                        if (jposition < 0)
                        {
                            continue;
                        }
    
                        if (jposition < width)
                        {
                            double k = kernel[i, j];
                            Pixel pixel = pixels[jposition, iposition];
    
                            divider += k;
    
                            red += k * pixel.R;
                            green += k * pixel.G;
                            blue += k * pixel.B;
                            alpha += k * pixel.A;
    
                            processedKernelSize++;
                        }
                    }
                }
    
                // Check to see if all kernel elements were processed
                if (processedKernelSize == kernelSize)
                {
                    // All kernel elements are processed; we are not on the edge.
                    divider = this.Divider;
                }
                else
                {
                    // We are on an edge; do we need to use dynamic divider or not?
                    if (!this.UseDynamicDividerForEdges)
                    {
                        // Apply the set divider.
                        divider = this.Divider;
                    }
                }
    
                // Check and apply the divider
                if ((long)divider != 0)
                {
                    red /= divider;
                    green /= divider;
                    blue /= divider;
                    alpha /= divider;
                }
    
                // Add any applicable threshold.
                red += this.Threshold;
                green += this.Threshold;
                blue += this.Threshold;
                alpha += this.Threshold;
    
                result[x, y].R = (byte)((red > 255) 
                               ? 255 : ((red < 0) ? 0 : red));               
                result[x, y].G = (byte)((green > 255) 
                               ? 255 : ((green < 0) ? 0 : green));
                result[x, y].B = (byte)((blue > 255) 
                               ? 255 : ((blue < 0) ? 0 : blue));
                result[x, y].A = (byte)((alpha > 255) 
                               ? 255 : ((alpha < 0) ? 0 : alpha));
            }
        }
    
        return result;
    }
    

    【讨论】:

      【解决方案2】:

      找出它发生原因的唯一快速方法是to set breakpoints 并跟踪值的变化。这可以帮助您有效地捕获带有错误的代码。您可能会忘记某些计算或方法可能会返回未修改的副本而不是修改后的结果,或者修改后的计算可能会降低精度,无论如何,这不是委托的问题给别人。

      【讨论】:

      • 我实际上已经追溯到我获取像素数据Pixel pixel = pixels[x, y]; x 和 y 值应该偏移但我不知道偏移量应该是多少。数学不是我的强项
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-27
      相关资源
      最近更新 更多