public static byte[,] MedianFilter(byte[,] input, int kernelSize)
        {
            var image = new byte[input.GetLength(0), input.GetLength(1)];

            var startEnd = kernelSize / 2;

            for (var x = startEnd; x < input.GetLength(0) - startEnd; x++)
            {
                for (var y = startEnd; y < input.GetLength(1) - startEnd; y++)
                {
                    var window = new List <byte>();
                    for (byte i = 0; i < kernelSize; i++)
                    {
                        for (byte j = 0; j < kernelSize; j++)
                        {
                            window.Add(input[x - startEnd + i, y - startEnd + j]);
                        }
                    }

                    window.Sort();
                    image[x, y] = window.ElementAt(window.Count / 2);
                }
            }

            return(HelperFunctions.CropImage(image, startEnd));
        }
        /// <summary>
        /// Apply convolution with a given kernel a given amount of times
        /// </summary>
        public static byte[,] Convolve(byte[,] input, float[,] kernel, int times)
        {
            var image    = new byte[input.GetLength(0), input.GetLength(1)];
            var startEnd = kernel.GetLength(0) / 2; // Adjust for all kernel sizes

            for (var x = startEnd; x < input.GetLength(0) - startEnd; x++)
            {
                for (var y = startEnd; y < input.GetLength(1) - startEnd; y++)
                {
                    float total = 0;
                    for (byte i = 0; i < kernel.GetLength(0); i++)
                    {
                        for (byte j = 0; j < kernel.GetLength(1); j++)
                        {
                            total += kernel[i, j] * input[x - startEnd + i, y - startEnd + j];
                        }
                    }
                    image[x, y] = (byte)Math.Round(HelperFunctions.ImageClamp(total));
                }
            }

            if (times > 1)
            {
                image = Convolve(image, kernel, times - 1);
            }

            HelperFunctions.GlobalMask = HelperFunctions.CropImage(HelperFunctions.GlobalMask, startEnd);
            return(HelperFunctions.CropImage(image, startEnd));
        }
示例#3
0
        /// <summary>
        /// The bilateral filter is a weighted average of pixels that, unlike the gaussian blur, takes the variation of brightness into account to
        /// preserve edges as much as possible. It checks not only if two pixels are spatially close to one another, but also if they are close in
        /// terms of brightness. It uses a gaussian kernel for the spatial relation and a one-dimensional range kernel to measure the differences in
        /// brightness of the different pixels.
        /// </summary>
        /// <param name="image">The binary image to be filtered.</param>
        public static byte[,] BilateralFilter2D(byte[,] image)
        {
            // Make a float version of the image to make sure no important information is lost in rounding
            var         workingImage = CastToFloat(image);
            const float sigma        = 80; // Sigma is used to generate the range kernel

            // Create the range kernel
            var rangeKernel = new float[256]; // Used for the brightness-based weighting.

            for (var i = 0; i < rangeKernel.Length; i++)
            {
                double val       = (i * i) / (2 * sigma * sigma);
                var    kernelVal = Math.Exp(-val);
                rangeKernel[i] = (float)kernelVal;
            }

            workingImage = Normalize(workingImage, 0, 1); // Normalize all the values to the [0,1] range

            for (var x = 2; x < image.GetLength(0) - 2; x++)
            {
                for (var y = 2; y < image.GetLength(1) - 2; y++)
                {
                    var   targetPixel = (int)workingImage[x, y]; // The pixel that is to be replaced by a new value
                    float result      = 0;
                    float sum         = 0;                       // The sum of the weighted neighbour values
                    for (var i = -2; i < 2; i++)                 // Cycle through the kernel and compute the coefficients to add to the summation
                    {
                        for (var j = -2; j < 2; j++)
                        {
                            var curPixel = (int)workingImage[x + i, y + j];
                            var weight   = GaussianKernel[i + 2, j + 2] * rangeKernel[Math.Abs(curPixel - targetPixel)];
                            result += curPixel * weight;
                            sum    += weight;
                        }
                    }
                    workingImage[x, y] = result / sum; // Replace the pixel in the output image with the determined value
                }
            }

            return(HelperFunctions.CropImage(CastToByte(workingImage), 2)); // Return the image as an array of ints and without the borders
        }
示例#4
0
        public virtual byte[,] Morph(byte[,] input, UseMask E)
        {
            var image = new byte[input.GetLength(0), input.GetLength(1)];

            for (var x = this.StartEnd; x < input.GetLength(0) - this.StartEnd; x++)
            {
                for (var y = this.StartEnd; y < input.GetLength(1) - this.StartEnd; y++)
                {
                    switch (E)
                    {
                    case UseMask.Binary when HelperFunctions.GlobalMask[x, y] == 255:
                    {
                        var localArea = new List <float>(this.Kernel.GetLength(0) * this.Kernel.GetLength(0));    // storage of local area
                        for (byte i = 0; i < this.Kernel.GetLength(0); i++)
                        {
                            for (byte j = 0; j < this.Kernel.GetLength(1); j++)
                            {
                                if (HelperFunctions.GlobalMask[x - this.StartEnd + i, y - this.StartEnd + j] == 255)
                                {
                                    image[x, y] = Filter(x, y, i, j, localArea, input, 100, E);
                                }
                            }
                        }
                        break;
                    }

                    // don't filter this pixel
                    case UseMask.Binary:
                        image[x, y] = input[x, y];
                        break;

                    case UseMask.Greyscale:
                    {
                        var localArea = new List <float>(this.Kernel.GetLength(0) * this.Kernel.GetLength(0));    // storage of local area
                        for (byte i = 0; i < this.Kernel.GetLength(0); i++)
                        {
                            for (byte j = 0; j < this.Kernel.GetLength(1); j++)
                            {
                                image[x, y] = Filter(x, y, i, j, localArea, input, HelperFunctions.GlobalMask[x, y], E); // use the mask's position as the max or min clamp value for grayscale masks
                            }
                        }
                        break;
                    }

                    default:
                    {
                        var localArea = new List <float>(this.Kernel.GetLength(0) * this.Kernel.GetLength(0));    // storage of local area
                        for (byte i = 0; i < this.Kernel.GetLength(0); i++)
                        {
                            for (byte j = 0; j < this.Kernel.GetLength(1); j++)
                            {
                                image[x, y] = Filter(x, y, i, j, localArea, input, 100, E); // Perform the normal erosion/dilation without a mask (the 100 argument here gets changed in Filter)
                            }
                        }
                        break;
                    }
                    }
                }
            }

            if (this.Times > 1)
            {
                this.Times--;
                image = Morph(image, E);
            }

            Console.WriteLine("[Morphology]        Dilation or Erosion was applied " + this.Times + " time(s) with a " + this.Kernel.GetLength(0) + "x" + this.Kernel.GetLength(1) + " kernel with " + E + " Mask.");
            HelperFunctions.GlobalMask = HelperFunctions.CropImage(HelperFunctions.GlobalMask, this.StartEnd);
            return(HelperFunctions.CropImage(image, this.StartEnd));
        }