Example #1
0
        public static PinnedBitmap Convolute(Bitmap source, double[,] kernel)
        {
            var kernelHeight = kernel.GetUpperBound(0) + 1;
            var kernelWidth  = kernel.GetUpperBound(1) + 1;

            if ((kernelWidth % 2) == 0 || (kernelHeight % 2) == 0)
            {
                throw new InvalidOperationException("Invalid kernel size");
            }

            using (var pinnedSource = PinnedBitmap.FromBitmap(source))
            {
                var width  = source.Width;
                var height = source.Height;
                var result = new PinnedBitmap(width, height);

                var index            = 0;
                var halfKernelWidth  = kernelWidth >> 1;
                var halfKernelHeight = kernelHeight >> 1;

                for (var y = 0; y < height; y++)
                {
                    for (var x = 0; x < width; x++)
                    {
                        var a = 0.0;
                        var r = 0.0;
                        var g = 0.0;
                        var b = 0.0;

                        for (var kernelX = -halfKernelWidth; kernelX <= halfKernelWidth; kernelX++)
                        {
                            var pixelX = kernelX + x;
                            if (pixelX < 0)
                            {
                                pixelX = 0;
                            }
                            else if (pixelX >= width)
                            {
                                pixelX = width - 1;
                            }

                            for (var kernelY = -halfKernelHeight; kernelY <= halfKernelHeight; kernelY++)
                            {
                                var pixelY = kernelY + y;
                                if (pixelY < 0)
                                {
                                    pixelY = 0;
                                }
                                else if (pixelY >= height)
                                {
                                    pixelY = height - 1;
                                }

                                var col = pinnedSource.Data[pixelY * width + pixelX];
                                var k   = kernel[kernelY + halfKernelWidth, kernelX + halfKernelHeight];
                                a += ((col >> 24) & 0x000000FF) * k;
                                r += ((col >> 16) & 0x000000FF) * k;
                                g += ((col >> 8) & 0x000000FF) * k;
                                b += ((col) & 0x000000FF) * k;
                            }
                        }

                        var alphaInt = (int)a;
                        var alpha    = (byte)((alphaInt > 255) ? 255 : ((alphaInt < 0) ? 0 : alphaInt));
                        if (alpha == 1)
                        {
                            alpha = 0;
                        }

                        var redInt = (int)r;
                        var red    = (byte)((redInt > 255) ? 255 : ((redInt < 0) ? 0 : redInt));

                        var greenInt = (int)g;
                        var green    = (byte)((greenInt > 255) ? 255 : ((greenInt < 0) ? 0 : greenInt));

                        var blueInt = (int)b;
                        var blue    = (byte)((blueInt > 255) ? 255 : ((blueInt < 0) ? 0 : blueInt));

                        result.Data[index++] = (alpha << 24) | (red << 16) | (green << 8) | blue;
                    }
                }

                return(result);
            }
        }