From 25fc4df156b0fce23041b9a172d91f7030601e16 Mon Sep 17 00:00:00 2001 From: maxluli Date: Wed, 28 Sep 2022 13:52:14 +0200 Subject: [PATCH] Added scaling, and this is the checkpoint before trying to add arythmetic operations on images --- AgraV2/AgraV2.csproj | 1 + AgraV2/EffectMedianFilter.cs | 3 + AgraV2/EffectScale.cs | 244 +++++++++++++++++++++++++++++++++++ AgraV2/Form1.cs | 2 + 4 files changed, 250 insertions(+) create mode 100644 AgraV2/EffectScale.cs diff --git a/AgraV2/AgraV2.csproj b/AgraV2/AgraV2.csproj index 0285f59..1cff558 100644 --- a/AgraV2/AgraV2.csproj +++ b/AgraV2/AgraV2.csproj @@ -50,6 +50,7 @@ + Form diff --git a/AgraV2/EffectMedianFilter.cs b/AgraV2/EffectMedianFilter.cs index 9f301f3..d666abb 100644 --- a/AgraV2/EffectMedianFilter.cs +++ b/AgraV2/EffectMedianFilter.cs @@ -23,8 +23,11 @@ namespace AgraV2 } public override void populatePannel() { + base.populatePannel(); + Label label = new Label(); label.Text = "Radius : "; + label.BackColor = Color.Transparent; NumericUpDown nup = new NumericUpDown(); nup.Minimum = 1; diff --git a/AgraV2/EffectScale.cs b/AgraV2/EffectScale.cs new file mode 100644 index 0000000..895e5f0 --- /dev/null +++ b/AgraV2/EffectScale.cs @@ -0,0 +1,244 @@ +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 EffectScale : Effect + { + private readonly object balancelock = new object(); + private int _radius; + private float _scale; + + public int Radius { get => _radius; set => _radius = value; } + public float Scale { get => _scale; set => _scale = value; } + + public EffectScale(string name, Panel toolBox) : base(name, toolBox) + { + //Default values + Radius = 1; + Scale = 1; + } + public override void populatePannel() + { + base.populatePannel(); + + Label label = new Label(); + label.Text = "Range : "; + label.BackColor = Color.Transparent; + label.Location = new Point(0, 0); + + Label label2 = new Label(); + label2.Text = "Scale ratio : "; + label2.BackColor = Color.Transparent; + label2.Location = new Point(0, label.Height); + + NumericUpDown nupRange = new NumericUpDown(); + nupRange.Minimum = 1; + nupRange.Maximum = 100; + nupRange.Increment = 1; + nupRange.ValueChanged += nupRange_ValueChanged; + nupRange.Location = new Point(label.Location.X + label.Width, label.Location.Y); + + NumericUpDown nupScale = new NumericUpDown(); + nupScale.Minimum = 1; + nupScale.Maximum = 100; + nupScale.Increment = 0.1M; + nupScale.ValueChanged += nupScale_ValueChanged; + nupScale.Location = new Point(label2.Location.X + label2.Width, label2.Location.Y); + + ToolBox.Controls.Add(label); + ToolBox.Controls.Add(nupRange); + ToolBox.Controls.Add(label2); + ToolBox.Controls.Add(nupScale); + } + private void nupRange_ValueChanged(object sender, EventArgs e) + { + if (sender is NumericUpDown) + { + NumericUpDown nup = (NumericUpDown)sender; + Radius = (int)nup.Value; + } + } + private void nupScale_ValueChanged(object sender, EventArgs e) + { + if (sender is NumericUpDown) + { + NumericUpDown nup = (NumericUpDown)sender; + Scale = (float)nup.Value; + } + } + public override Bitmap[] apply(Bitmap inputBmp) + { + if (inputBmp == null) + return null; + + //This is important for when the user wants to re apply an effet + ProcessingDuration = new List(); + + Bitmap[] result = new Bitmap[] { NearestNeighbor(inputBmp)}; + return result; + } + public unsafe Bitmap NearestNeighbor(Bitmap inputBmp) + { + Chrono.Restart(); + + Size imgSize = new Size(inputBmp.Width, inputBmp.Height); + Size newSize = new Size((int)(imgSize.Width * Scale), (int)(imgSize.Height * Scale)); + + Bitmap result = new Bitmap(newSize.Width, newSize.Height); + BitmapData resultData = result.LockBits(new Rectangle(0, 0, newSize.Width, newSize.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 = inputData.Stride * inputBmp.Height; + int offset = inputData.Stride - bytesPerPixel * imgSize.Width; + int newOffset = resultData.Stride - bytesPerPixel * newSize.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 < newSize.Height; y++) + { + for (int x = 0; x < newSize.Width; x++) + { + //We want to know what the pixel on the old x and y was + + int oldX = (int)Math.Floor((float)x / Scale); + int oldY = (int)Math.Floor((float)y / Scale); + + if (bytesPerPixel == 3 && oldX == 2 && oldY == 2) + Console.WriteLine("coucou"); + + //Now we would like to know what the color on this pixel was + //transfer x,y to linear : y*(width + offset) + x + + int oldPosition = oldY * imgSize.Width + oldX; + oldPosition = oldPosition * bytesPerPixel + oldY * offset; + int oldBlue = (originalStartPx + oldPosition)[0]; + int oldGreen = (originalStartPx + oldPosition)[1]; + int oldRed = (originalStartPx + oldPosition)[2]; + + resultCursor[0] = (byte)oldBlue; + resultCursor[1] = (byte)oldGreen; + resultCursor[2] = (byte)oldRed; + + //originalCursor += bytesPerPixel; + resultCursor += bytesPerPixel; + } + //Taking care of the offset + //originalCursor += offset; + resultCursor += newOffset; + } + + } + result.UnlockBits(resultData); + inputBmp.UnlockBits(inputData); + + Chrono.Stop(); + ProcessingDuration.Add(Chrono.ElapsedMilliseconds / 1000.0); + + return result; + } + public unsafe Bitmap BiLinear(Bitmap inputBmp) + { + Chrono.Restart(); + + Size imgSize = new Size(inputBmp.Width, inputBmp.Height); + Size newSize = new Size((int)(imgSize.Width * Scale), (int)(imgSize.Height * Scale)); + + Bitmap result = new Bitmap(newSize.Width, newSize.Height); + BitmapData resultData = result.LockBits(new Rectangle(0, 0, newSize.Width, newSize.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 = inputData.Stride * inputBmp.Height; + int offset = inputData.Stride - bytesPerPixel * imgSize.Width; + int newOffset = resultData.Stride - bytesPerPixel * newSize.Width; + + + lock (balancelock) + { + byte* resultStartPx = (byte*)resultData.Scan0.ToPointer(); + byte* resultCursor = resultStartPx; + byte* originalStartPx = (byte*)inputData.Scan0.ToPointer(); + byte* originalCursor = originalStartPx; + + float tx = imgSize.Width / newSize.Width; + float ty = imgSize.Height / newSize.Height; + + for (int y = 0; y < newSize.Height; y++) + { + for (int x = 0; x < newSize.Width; x++) + { + + int newX = (int)(tx * x); + int newY = (int)(ty * y); + + float x_diff = ((tx *x)-newX); + float y_diff = ((ty *y)-newY); + + //int value = + + //THIS METHOD IS NOT FINISHED + + //originalCursor += bytesPerPixel; + resultCursor += bytesPerPixel; + + } + //Taking care of the offset + //originalCursor += offset; + resultCursor += newOffset; + } + + } + result.UnlockBits(resultData); + inputBmp.UnlockBits(inputData); + + Chrono.Stop(); + ProcessingDuration.Add(Chrono.ElapsedMilliseconds / 1000.0); + + return result; + } + public int ConvertPointToLinear(Point position,Size imageSize,int bytesPerPixel, int offset) + { + int linearPosition = position.Y * imageSize.Width + position.X; + linearPosition = linearPosition * bytesPerPixel + position.Y * offset; + + return linearPosition; + } + 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; + } + } +} diff --git a/AgraV2/Form1.cs b/AgraV2/Form1.cs index beab2a9..1412239 100644 --- a/AgraV2/Form1.cs +++ b/AgraV2/Form1.cs @@ -26,6 +26,7 @@ namespace AgraV2 effects = new List(); effects.Add(new EffectGrayScale("GrayScale", pnlEffectToolbox)); effects.Add(new EffectMedianFilter("Median Filter", pnlEffectToolbox)); + effects.Add(new EffectScale("Scaling", pnlEffectToolbox)); RefreshUi(); } private void RefreshUi() @@ -43,6 +44,7 @@ namespace AgraV2 FolderBrowserDialog dialog = new FolderBrowserDialog(); if (dialog.ShowDialog() == DialogResult.OK) { + pnlFiles.Controls.Clear(); selectedDirectory = new DirectoryInfo(dialog.SelectedPath); List images = new List();