public Bitmap ProcessPicture(ImageLoader loader) { var src = (Bitmap)loader.Image; int width = src.Width; int height = src.Height; var dest = new Bitmap(width, height, src.PixelFormat); using (var srcBMP = new ConcurrentBitmap(src)) { using (var newBMP = new ConcurrentBitmap(dest)) { // For each line Parallel.For( 0, height, y => { // For each pixel for (var x = 0; x < width; x++) { Color currentColor = srcBMP.GetPixel(x, y); var I = (int)(currentColor.R * 0.299 + currentColor.G * 0.587 + currentColor.B * 0.114); var res = (int)(I + distribution.Sample()).Clamp(byte.MinValue, byte.MaxValue); Color output = Color.FromArgb(res, res, res); newBMP.SetPixel(x, y, output); } } ); } } //src.Dispose(); return(dest); }
using System; using System.Drawing; using System.Threading.Tasks; using ImageFilter.Extensions; namespace ImageFilter { public class Tranformation { private readonly double stdDev = 1.4; public Tranformation() { } public Tranformation(double stdDev) { this.stdDev = stdDev; } private int Threshold { get; set; } private double Divider { get; set; } private bool UseDynamicDividerForEdges { get; } = true; public double[,] CreateLaplacianFilter(double alpha) { if (Math.Abs(alpha) < 0.0001) { return new double[,] { { 0, -1, 0 }, { -1, 4, -1}, { 0, -1, 0 } }; } else { return new double[,] { { 0, -1, 0 }, { -1, alpha + 4, -1 }, { 0, -1, 0 } }; } } public double[,] CreateBoxBlurFilter(int maskSize) { int maskLength = 2 * maskSize + 1; var mask = new double[maskLength, maskLength]; double divider = 0; for (var i = 0; i < maskLength; i++) { for (var j = 0; j < maskLength; j++) { mask[i, j] = 1; divider++; } } Divider = divider; return mask; } public double[,] CreateGaussFilter(int maskSize) { int maskLength = 2 * maskSize + 1; var mask = new double[maskLength, maskLength]; double z = 0.0; for (int i = 0; i < maskLength; i++) { for (int j = 0; j < maskLength; j++) { int x = i - maskSize; int y = j - maskSize; mask[i, j] = Math.Exp(-(Math.Pow(x, 2) + Math.Pow(y, 2)) / (2.0 * Math.Pow(stdDev, 2))); z += mask[i, j]; } } Divider = z; return mask; } public Bitmap ProcessMask(Bitmap src, double[,] mask, bool fixGamma) { int width = src.Width; int height = src.Height; var dest = new Bitmap(width, height, src.PixelFormat); using (var srcBMP = new ConcurrentBitmap(src)) { using (var destBMP = new ConcurrentBitmap(dest)) { int maskLength = mask.GetLength(0); int radius = maskLength >> 1; int maskSize = maskLength * maskLength; int threshold = Threshold; // For each line Parallel.For( 0, height, y => { // For each pixel for (var x = 0; x < width; x++) { // The number of mask elements taken into account int processedSize; // Color sums double blue; double divider; double green; double red = green = blue = divider = processedSize = 0; // For each kernel row for (var i = 0; i < maskLength; i++) { int ir = i - radius; int offsetY = y + ir; // Skip the current row if (offsetY < 0) { continue; } // Outwith the current bounds so break. if (offsetY >= height) { break; } // For each kernel column for (var j = 0; j < maskLength; j++) { int jr = j - radius; int offsetX = x + jr; // Skip the column if (offsetX < 0 || offsetX >= width) { continue; } // ReSharper disable once AccessToDisposedClosure Color sourceColor = srcBMP.GetPixel(offsetX, offsetY); double k = mask[i, j]; divider += k; red += k * sourceColor.R; green += k * sourceColor.G; blue += k * sourceColor.B; processedSize++; } } // Check to see if all kernel elements were processed if (processedSize == maskSize) { // All kernel elements are processed; we are not on the edge. divider = Divider; } else { // We are on an edge; do we need to use dynamic divider or not? if (!UseDynamicDividerForEdges) { // Apply the set divider. divider = Divider; } } // Check and apply the divider if ((long) divider != 0) { red /= divider; green /= divider; blue /= divider; } // Add any applicable threshold. red += threshold; green += threshold; blue += threshold; Color destinationColor = Color.FromArgb( Convert.ToByte(red.Clamp(0, 255)), Convert.ToByte(green.Clamp(0, 255)), Convert.ToByte(blue.Clamp(0, 255))); // ReSharper disable once AccessToDisposedClosure destBMP.SetPixel(x, y, destinationColor); } } ); } } return dest; } public double[,] ProcessMaskDouble(Bitmap src, double[,] mask, bool fixGamma) { int width = src.Width; int height = src.Height; var dest = new double[height, width]; using (var srcBMP = new ConcurrentBitmap(src)) { int maskLength = mask.GetLength(0); int radius = maskLength >> 1; int maskSize = maskLength * maskLength; int threshold = Threshold; // For each line Parallel.For( 0, height, y => { // For each pixel for (var x = 0; x < width; x++) { // The number of mask elements taken into account int processedSize; // Color sums double blue; double divider; double green; double red = green = blue = divider = processedSize = 0; // For each kernel row for (var i = 0; i < maskLength; i++) { int ir = i - radius; int offsetY = y + ir; // Skip the current row if (offsetY < 0) { continue; } // Outwith the current bounds so break. if (offsetY >= height) { break; } // For each kernel column for (var j = 0; j < maskLength; j++) { int jr = j - radius; int offsetX = x + jr; // Skip the column if (offsetX < 0 || offsetX >= width) { continue; } // ReSharper disable once AccessToDisposedClosure Color sourceColor = srcBMP.GetPixel(offsetX, offsetY); double k = mask[i, j]; divider += k; red += k * sourceColor.R; green += k * sourceColor.G; blue += k * sourceColor.B; processedSize++; } } // Check to see if all kernel elements were processed if (processedSize == maskSize) { // All kernel elements are processed; we are not on the edge. divider = Divider; } else { // We are on an edge; do we need to use dynamic divider or not? if (!UseDynamicDividerForEdges) { // Apply the set divider. divider = Divider; } } // Check and apply the divider if ((long)divider != 0) { red /= divider; green /= divider; blue /= divider; } dest[y, x] = red; } } ); } return dest; } } }
using System; using System.Drawing; using System.IO; using ImageFilter.Filters; using ImageFilter.Noises; using ImageFilter.Extensions; using OxyPlot; using OxyPlot.WindowsForms; using OxyPlot.Axes; using OxyPlot.Series; using System.Collections.Generic; namespace ImageFilter { public class ImageLoader : IDisposable { #region Fields private bool isDisposed; #endregion #region Propeties public Image Image { get; set; } public string ImagePath { get; private set; } #endregion #region Methods public double CalculatePSNR(Image image) { var img1 = (Bitmap) Image; var img2 = (Bitmap) image; int width = image.Width; int height = image.Height; double psnrY = 0; using (var img1BMP = new ConcurrentBitmap(img1)) { using (var img2BMP = new ConcurrentBitmap(img2)) { // For each line for (var y = 0; y < height; y++) { // For each pixel for (var x = 0; x < width; x++) { Color img1Color = img1BMP.GetPixel(x, y); // Assumes that img2 is not in Y component Color tmpColor = img2BMP.GetPixel(x, y); var I = (int) (tmpColor.R * 0.299 + tmpColor.G * 0.587 + tmpColor.B * 0.114); Color img2Color = Color.FromArgb(I, I, I); psnrY += Math.Pow(img1Color.R - img2Color.R, 2); } } } } psnrY = 10 * Math.Log10(width * height * Math.Pow(Math.Pow(2, 8) - 1, 2) / psnrY); /*Console.WriteLine($"Y: {psnrY}");*/ return psnrY; } public ImageLoader Load(string filePath) { var fileInfo = new FileInfo(filePath); if (!fileInfo.Exists) { throw new FileNotFoundException(filePath); } ImagePath = filePath; // Open a file stream using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { var stream = new MemoryStream(); fileStream.CopyTo(stream); stream.Position = 0; Image = Image.FromStream(stream); } return this; } public ImageLoader Save(string filePath) { var dirInfo = new DirectoryInfo(Path.GetDirectoryName(filePath)); if (!dirInfo.Exists) { dirInfo.Create(); } Image.Save(filePath); return this; } public ImageLoader AddImage(Image I, double[,] img) { Bitmap one = (Bitmap) I; //Bitmap two = (Bitmap) img; Bitmap res = new Bitmap(one.Width, one.Height); int height = Image.Height; int width = Image.Width; for (int y = 0; y < height; y++) { for (var x = 0; x < width; x++) { double blue; double green; double red = green = blue = 0; Color colorOne = one.GetPixel(x, y); int colorTwo = (int) img[y, x];//two.GetPixel(x, y); red = colorOne.R + colorTwo; green = colorOne.G + colorTwo; blue = colorOne.B + colorTwo; Color destinationColor = Color.FromArgb( Convert.ToByte(red.Clamp(0, 255)), Convert.ToByte(green.Clamp(0, 255)), Convert.ToByte(blue.Clamp(0, 255))); res.SetPixel(x, y, destinationColor); } } Image = res; return this; } public ImageLoader Add128(double[,] I) { Bitmap image = (Bitmap) Image; Bitmap res = new Bitmap(Image.Width, Image.Height); int height = Image.Height; int width = Image.Width; for (int y = 0; y < height; y++) { for (var x = 0; x < width; x++) { double blue; double green; double red = green = blue = 0; red = I[y, x];// 128; blue = I[y, x];// + 128; green = I[y, x];// red += 128; blue += 128; green += 128; Color destinationColor = Color.FromArgb( Convert.ToByte(red.Clamp(0, 255)), Convert.ToByte(green.Clamp(0, 255)), Convert.ToByte(blue.Clamp(0, 255))); res.SetPixel(x, y, destinationColor); } } Image = res; return this; } public ImageLoader AddNoise(INoise noise) { Image = noise.ProcessPicture(this); return this; } public ImageLoader AddBoxFilter(int size) { var boxFilter = new BoxFilter(size); Image = boxFilter.ProcessPicture(this); return this; } public ImageLoader AddGaussFilter(int size, double sigma) { var boxFilter = new GaussFilter(size, sigma); Image = boxFilter.ProcessPicture(this); return this; } public ImageLoader AddMedianFilter(int size) { var medianFilter = new MedianFilter(size); Image = medianFilter.ProcessPicture(this); return this; } public ImageLoader AddLaplacianFilter(double alpha) { var laplacianFilter = new LaplacianFilter(alpha); Image = laplacianFilter.ProcessPicture(this); return this; } public double[,] AddLaplacianFilterAlpha0() { var laplacianFilter = new LaplacianFilter(0); double[,] res = laplacianFilter.ProcessPictureAlpha0(this); return res; } public ImageLoader AddSobelFilter(string direction) { var sobelFilter = new SobelFilter(direction == "V" ? 1 : 0); Image = sobelFilter.ProcessPicture(this); return this; } public double[,] GetSobelFilterDouble(string direction) { var sobelFilter = new SobelFilter(direction == "V" ? 1 : 0); return sobelFilter.Get(this); } public double CalculateAvgLuminocity() { double luminocity = 0; Bitmap image = (Bitmap)Image; int height = image.Height; int width = image.Width; for (int y = 0; y < height; y++) { for (var x = 0; x < width; x++) { luminocity += image.GetPixel(x, y).R; } } return luminocity / (double) (height * width); } private SortedDictionary<int, int> GetFrequency() { Bitmap image = (Bitmap)Image; int height = image.Height; int width = image.Width; var result = new SortedDictionary<int, int>(); for (int y = 0; y < height; y++) { for (var x = 0; x < width; x++) { int Y = image.GetPixel(x, y).R; if (result.ContainsKey(Y)) { result[Y] = result[Y] + 1; } else { result.Add(Y, 1); } } } return result; } public void PlotHistogram(string name, string outputPath, FileInfo fileInfo) { PngExporter pngExporter = new PngExporter { Width = 1280, Height = 720, Background = OxyColors.White }; var freq = GetFrequency(); var x = freq.Values; var y = freq.Keys; var plotGauss = new PlotModel { Title = $"Histogram for {name}" }; plotGauss.Axes.Add(new LinearAxis { Title = "x", Position = AxisPosition.Bottom }); plotGauss.Axes.Add(new LinearAxis { Title = "y", Position = AxisPosition.Left }); var barSeries = new LinearBarSeries { }; foreach (var item in freq) { barSeries.Points.Add(new DataPoint(item.Key, item.Value)); } plotGauss.Series.Add(barSeries); pngExporter.ExportToFile(plotGauss, $"{outputPath}/{fileInfo.Name}/histograms/{name}{fileInfo.Extension}"); } #region Dispose ~ImageLoader() { Dispose(false); } public void Dispose() { Dispose(true); // Already cleaned up in dispose method, supress GC GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (isDisposed) { return; } if (disposing) { if (Image != null) { Image.Dispose(); Image = null; } } isDisposed = true; } #endregion #endregion } }