public ColorImage Convolution(ColorImage img, Filter f) { int[][] kernel = f.Values; double scale = f.ScaleFactor; int offset = f.Offset; ColorImage ret = new ColorImage(img.Height, img.Width); if(kernel.Length != kernel[0].Length) throw new ArgumentException("Kernel must be quadratic in shape (n x n)"); int low = -kernel.Length / 2; int high = kernel.Length / 2; for(int i = high; i < img.Height - high; i++) { for(int j = high; j < img.Width - high; j++) { int newR = 0, newG = 0, newB = 0; for(int i_k = low; i_k <= high; i_k++) { for(int j_k = low; j_k <= high; j_k++) { // TODO Edge problem int r_i = 0, g_i = 0, b_i = 0; r_i = img.Red[i + i_k, j + j_k]; g_i = img.Green[i + i_k, j + j_k]; b_i = img.Blue[i + i_k, j + j_k]; newR += (r_i * kernel[i_k + high][j_k + high]); newG += (g_i * kernel[i_k + high][j_k + high]); newB += (b_i * kernel[i_k + high][j_k + high]); } } double r = (double) newR * scale + offset; double g = (double) newG * scale + offset; double b = (double) newB * scale + offset; ret.Red[i, j] = Clamp((int) r, 0, 255); ret.Green[i, j] = Clamp((int) g, 0, 255); ret.Blue[i, j] = Clamp((int) b, 0, 255); } } return ret; }
static void Main() { // You probably have to change the path to point to the supplied // image "river.jpg". // Because of a bug in Visual studio this project should not be run // inside the debugger. It will be extremely slow. Bitmap image = new Bitmap(@"river.jpg"); // Filters can be added and removed here. Filter[] filters = new Filter[] { Filter.MEDIAN_FILTER, Filter.MEAN_FILTER, Filter.EDGE_DETECTION }; // Do the processing using the pipeline // Note that the image will be converted to gray scale. Bitmap result = ImageProcessing.ApplyFiltersPipelined(image, filters, 8); // ... or use the sequential method // Bitmap result = ImageProcessing.ApplyFilters(image, filters); // Show the resulting image Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new ImageForm(new ImagePanel(result))); // For a text based version uncomment the line below. // Remember to change the "Output type" of the project // to "Console application" // ImageProcessingConsole(image); }
public void Apply(Filter filter, Bitmap target) { Action<byte[], byte[]> action = (bytesSource, bytesDest) => { var stride = target.GetStride(); Run(bytesSource, bytesDest, stride, stride / target.Width, filter.Matrix, filter.Size, filter.Bias); }; target.ExecuteTransformAction(action); }
public void Apply(Filter filter, Bitmap target) { Action<byte[], byte[]> action = (bytesSource, bytesDest) => { var stride = target.GetStride(); var method = CreateFilterMethodIL(bytesSource, bytesDest, stride, stride / target.Width, filter.Matrix, filter.Size, filter.Bias); method.Invoke(null, new object[] { bytesSource, bytesDest }); }; target.ExecuteTransformAction(action); }
private static void ImageProcessingConsole(Bitmap image) { // we apply a filter 50 times int numFilters = 50; // in the pipelined version the image // is divided into 30 strips int strips = 30; Filter[] filters = new Filter[numFilters]; for (int i = 0; i < numFilters; i++) { filters[i] = Filter.MEDIAN_FILTER; } // Let the JIT compilation kick in ImageProcessing.ApplyFilters(image, filters); ImageProcessing.ApplyFiltersPipelined(image, filters, strips); long start = DateTime.Now.Ticks; ImageProcessing.ApplyFilters(image, filters); long end = DateTime.Now.Ticks; long tSeq = (end - start) / 10000; Console.WriteLine("Time spent " + tSeq); start = System.DateTime.Now.Ticks; ImageProcessing.ApplyFiltersPipelined(image, filters, strips); end = System.DateTime.Now.Ticks; long tPar = (end - start) / 10000; Console.WriteLine("Time spent " + tPar); Console.WriteLine("Speed up " + (double)tSeq / tPar); }
/************************************************ * Applies an array of filters to an image. * Sequential. ************************************************/ public static Bitmap ApplyFilters(Bitmap image, Filter[] filters) { int width = image.Width; int height = image.Height; int[] pixels = GetPixels(image); int[] resultPixels = new int[pixels.Length]; for (int i = 0; i < filters.Length; i++) { Process(filters[i], pixels, resultPixels, width, height, 0, height); // swap the arrays int[] temp = pixels; pixels = resultPixels; resultPixels = temp; } Bitmap result = new Bitmap(width, height); SetPixels(result, pixels); return result; }
/************************************************ * Uses the Pipeline Future to apply an array of * filters to an image. * Parallel. ************************************************/ public static Bitmap ApplyFiltersPipelined(Bitmap image, Filter[] filters, int strips) { return new Pipeline(image, filters, strips).Result(); }
/************************************************ * Convenience method, that applies a filter to an * image. ************************************************/ public static void Process(Filter filter, int[] srcPixels, int[] resultPixels, int width, int height, int yStart, int yEnd) { switch (filter) { case Filter.EDGE_DETECTION: ImageProcessing.EdgeDetection(srcPixels, resultPixels, width, height, yStart, yEnd); break; case Filter.MEDIAN_FILTER: ImageProcessing.MedianFilter(srcPixels, resultPixels, width, height, yStart, yEnd); break; case Filter.MEAN_FILTER: ImageProcessing.MeanFilter(srcPixels, resultPixels, width, height, yStart, yEnd); break; } }
private void initFilters() { int[][] kernel = new int[3][]; kernel[0] = new int[] { 1, 1, 1 }; kernel[1] = new int[] { 1, 1, 1 }; kernel[2] = new int[] { 1, 1, 1 }; average = new Filter(kernel, 1.0 / 9.0, 0); int[][] kernel2 = new int[3][]; kernel2[0] = new int[] { 1, 2, 1 }; kernel2[1] = new int[] { 2, 4, 2 }; kernel2[2] = new int[] { 1, 2, 1 }; gauss = new Filter(kernel2, 1.0 / 16.0, 0); int[][] kernel3 = new int[3][]; kernel3[0] = new int[] { 1, 2, 1 }; kernel3[1] = new int[] { 0, 0, 0 }; kernel3[2] = new int[] { -1, -2, -1 }; sobel1 = new Filter(kernel3, 1.0, 128); int[][] kernel4 = new int[3][]; kernel4[0] = new int[] { 1, 0, -1 }; kernel4[1] = new int[] { 2, 0, -2 }; kernel4[2] = new int[] { 1, 0, -1 }; sobel2 = new Filter(kernel4, 1.0, 128); }