using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace AgraV2 { internal class EffectMedianFilter : Effect { private readonly object balancelock = new object(); private int _Radius; public int Radius { get => _Radius; set => _Radius = value; } public EffectMedianFilter(string name, Panel toolBox) : base(name, toolBox) { //This is just the default value Radius = 1; } public override void populatePannel() { Label label = new Label(); label.Text = "Radius : "; NumericUpDown nup = new NumericUpDown(); nup.Minimum = 1; nup.Maximum = 100; nup.Increment = 1; nup.ValueChanged += nup_ValueChanged; nup.Location = new Point(label.Location.X + label.Width,label.Location.Y); ToolBox.Controls.Add(label); ToolBox.Controls.Add(nup); } private void nup_ValueChanged(object sender, EventArgs e) { if (sender is NumericUpDown) { NumericUpDown nup = (NumericUpDown)sender; Radius = (int)nup.Value; } } public override Bitmap[] apply(Bitmap inputBmp) { Bitmap[] result = new Bitmap[] { medianFilter(inputBmp) }; return result; } public unsafe Bitmap medianFilter(Bitmap inputBmp) { Chrono.Restart(); Size imgSize = new Size(inputBmp.Width,inputBmp.Height); Bitmap result = new Bitmap(imgSize.Width, imgSize.Height); BitmapData resultData = result.LockBits(new Rectangle(0, 0, imgSize.Width, imgSize.Height), ImageLockMode.ReadWrite, inputBmp.PixelFormat); BitmapData inputData = inputBmp.LockBits(new Rectangle(0, 0, imgSize.Width, imgSize.Height), ImageLockMode.ReadWrite, inputBmp.PixelFormat); int bytesPerPixel = Bitmap.GetPixelFormatSize(inputBmp.PixelFormat) / 8; int byteCount = resultData.Stride * inputBmp.Height; int offset = resultData.Stride - bytesPerPixel * imgSize.Width; lock (balancelock) { byte* resultStartPx = (byte*)resultData.Scan0.ToPointer(); byte* resultCursor = resultStartPx; byte* originalStartPx = (byte*)inputData.Scan0.ToPointer(); byte* originalCursor = originalStartPx; for (int y = 0; y < inputBmp.Height; y++) { for (int x = 0; x < imgSize.Width; x++) { //We wont process border pixels if (x > Radius && y > Radius && x < imgSize.Width - Radius && y < inputBmp.Height - Radius) { List Blues = new List(); List Greens = new List(); List Reds = new List(); List surroundingPixels = getSurroundingPixels(new Point(x, y), 2, imgSize.Width, inputBmp.Height); foreach (Point pixel in surroundingPixels) { int relativePosition = (pixel.X) * bytesPerPixel + (pixel.Y * (imgSize.Width * bytesPerPixel + offset)); byte* address = (byte*)(relativePosition + originalStartPx); Blues.Add(address[0]); Greens.Add(address[1]); Reds.Add(address[2]); } Blues.Sort(); Greens.Sort(); Reds.Sort(); resultCursor[0] = (byte)Blues[Blues.Count / 2]; resultCursor[1] = (byte)Greens[Greens.Count / 2]; resultCursor[2] = (byte)Reds[Reds.Count / 2]; } originalCursor += bytesPerPixel; resultCursor += bytesPerPixel; } //Taking care of the offset originalCursor += offset; resultCursor += offset; } } result.UnlockBits(resultData); inputBmp.UnlockBits(inputData); Chrono.Stop(); ProcessingDuration.Add(Chrono.ElapsedMilliseconds / 1000.0); return result; } public List getSurroundingPixels(Point centerPoint, int Radius, int imageWidth, int imageHeight) { List result = new List(); int width = (Radius * 2 + 1); Point cursor = centerPoint; //we place the cursor on the top left of the matrix cursor = new Point(cursor.X - Radius, cursor.Y - Radius); for (int y = 0; y < width; y++) { //This scans top to bottom for (int x = 0; x < width; x++) { //This scans left to right result.Add(cursor); cursor = new Point(cursor.X + 1, cursor.Y); } cursor = new Point(cursor.X - (Radius * 2 + 1), cursor.Y + 1); } return result; } } }