Compare commits
4 Commits
6b392ab1e7
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ba70ef468 | |||
| 25fc4df156 | |||
| d90b9d40ef | |||
| 99bf493b71 |
@@ -48,8 +48,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Effect.cs" />
|
||||
<Compile Include="EffectArythmeticOperations.cs" />
|
||||
<Compile Include="EffectGrayScale.cs" />
|
||||
<Compile Include="EffectMedianFilter.cs" />
|
||||
<Compile Include="EffectScale.cs" />
|
||||
<Compile Include="Form1.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
namespace AgraV2
|
||||
{
|
||||
internal class EffectArythmeticOperations : Effect
|
||||
{
|
||||
private readonly object balancelock = new object();
|
||||
public static List<string> Operations = new List<string>() { "Substract","Add" };
|
||||
|
||||
private string _operationType;
|
||||
private Bitmap _imageToCompare;
|
||||
public Bitmap ImageToCompare { get => _imageToCompare; set => _imageToCompare = value; }
|
||||
public string OperationType { get => _operationType; set => _operationType = value; }
|
||||
|
||||
public EffectArythmeticOperations(string name, Panel toolBox) : base(name, toolBox)
|
||||
{
|
||||
ImageToCompare = new Bitmap(1,1);
|
||||
OperationType = Operations[0];
|
||||
}
|
||||
|
||||
public override void populatePannel()
|
||||
{
|
||||
base.populatePannel();
|
||||
|
||||
const int UI_MARGIN = 10;
|
||||
|
||||
PictureBox pictureBox = new PictureBox();
|
||||
pictureBox.Width = ToolBox.Width;
|
||||
pictureBox.Height = ToolBox.Width;
|
||||
pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
|
||||
pictureBox.Location = new Point(0,0);
|
||||
|
||||
if (ImageToCompare.Size != new Size(1,1))
|
||||
{
|
||||
pictureBox.Image = ImageToCompare;
|
||||
}
|
||||
|
||||
Button button = new Button();
|
||||
button.Click += LoadImage;
|
||||
button.Location = new Point(0,pictureBox.Location.Y + pictureBox.Height + UI_MARGIN);
|
||||
|
||||
ListBox listBox = new ListBox();
|
||||
listBox.DataSource = Operations;
|
||||
listBox.SelectedIndexChanged += operationChange;
|
||||
listBox.Location = new Point(0,button.Location.Y + button.Height + UI_MARGIN);
|
||||
|
||||
ToolBox.Controls.Add(pictureBox);
|
||||
ToolBox.Controls.Add(button);
|
||||
ToolBox.Controls.Add(listBox);
|
||||
}
|
||||
private void operationChange(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is ListBox)
|
||||
{
|
||||
OperationType = Operations[(sender as ListBox).SelectedIndex];
|
||||
}
|
||||
}
|
||||
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<double>();
|
||||
|
||||
Bitmap[] result = new Bitmap[] { Substract(inputBmp,ImageToCompare) };
|
||||
return result;
|
||||
}
|
||||
public unsafe Bitmap Substract(Bitmap image,Bitmap imageToSubstract)
|
||||
{
|
||||
Chrono.Restart();
|
||||
|
||||
Size imageSize = image.Size;
|
||||
|
||||
Bitmap result = new Bitmap(imageSize.Width,imageSize.Height);
|
||||
|
||||
BitmapData xData = result.LockBits(new Rectangle(0, 0, imageSize.Width, imageSize.Height), ImageLockMode.ReadWrite, image.PixelFormat);
|
||||
BitmapData firstData = image.LockBits(new Rectangle(0, 0, imageSize.Width, imageSize.Height), ImageLockMode.ReadWrite, image.PixelFormat);
|
||||
BitmapData secondData = imageToSubstract.LockBits(new Rectangle(0, 0, imageSize.Width, imageSize.Height), ImageLockMode.ReadWrite, image.PixelFormat);
|
||||
|
||||
|
||||
int bytesPerPixel = Bitmap.GetPixelFormatSize(image.PixelFormat) / 8;
|
||||
int byteCount = xData.Stride * image.Height;
|
||||
int offset = xData.Stride - bytesPerPixel * image.Width;
|
||||
|
||||
lock (balancelock)
|
||||
{
|
||||
byte* ResultStartPx = (byte*)xData.Scan0.ToPointer();
|
||||
byte* FirstStartPx = (byte*)firstData.Scan0.ToPointer();
|
||||
byte* SecondStartPx = (byte*)secondData.Scan0.ToPointer();
|
||||
|
||||
byte* ResultCursor = ResultStartPx;
|
||||
byte* FirstCursor = FirstStartPx;
|
||||
byte* SecondCursor = SecondStartPx;
|
||||
|
||||
for (int x = 0; x < imageSize.Width; x++)
|
||||
{
|
||||
for (int y = 0; y < imageSize.Height; y++)
|
||||
{
|
||||
int firstBlue = FirstCursor[0];
|
||||
int firstGreen = FirstCursor[1];
|
||||
int firstRed = FirstCursor[2];
|
||||
|
||||
int secondBlue = SecondCursor[0];
|
||||
int secondGreen = SecondCursor[1];
|
||||
int secondRed = SecondCursor[2];
|
||||
|
||||
switch (OperationType)
|
||||
{
|
||||
case "Substract":
|
||||
ResultCursor[0] = (byte)Math.Max(0, firstBlue - secondBlue);
|
||||
ResultCursor[1] = (byte)Math.Max(0, firstGreen - secondGreen);
|
||||
ResultCursor[2] = (byte)Math.Max(0, firstRed - secondRed);
|
||||
break;
|
||||
case "Add":
|
||||
ResultCursor[0] = (byte)Math.Min(255, firstBlue + secondBlue);
|
||||
ResultCursor[1] = (byte)Math.Min(255, firstGreen + secondGreen);
|
||||
ResultCursor[2] = (byte)Math.Min(255, firstRed + secondRed);
|
||||
break;
|
||||
default:
|
||||
ResultCursor[0] = (byte)0;
|
||||
ResultCursor[1] = (byte)0;
|
||||
ResultCursor[2] = (byte)0;
|
||||
break;
|
||||
}
|
||||
|
||||
ResultCursor += bytesPerPixel;
|
||||
FirstCursor += bytesPerPixel;
|
||||
SecondCursor += bytesPerPixel;
|
||||
}
|
||||
//Taking care of the offset
|
||||
ResultCursor += offset;
|
||||
FirstCursor += offset;
|
||||
SecondCursor += offset;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
result.UnlockBits(xData);
|
||||
image.UnlockBits(firstData);
|
||||
imageToSubstract.UnlockBits(secondData);
|
||||
|
||||
ProcessingDuration.Add(Chrono.ElapsedMilliseconds / 1000.0);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void LoadImage(object sender, EventArgs e)
|
||||
{
|
||||
OpenFileDialog dialog = new OpenFileDialog();
|
||||
if (dialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
FileInfo file = new FileInfo(dialog.FileName);
|
||||
|
||||
ImageToCompare = (Bitmap)Image.FromFile(file.FullName);
|
||||
|
||||
populatePannel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,9 @@ namespace AgraV2
|
||||
if (inputBmp == null)
|
||||
return null;
|
||||
|
||||
//This is important for when the user wants to re apply an effet
|
||||
ProcessingDuration = new List<double>();
|
||||
|
||||
Bitmap[] result = new Bitmap[] { useGetSetPixel(inputBmp), useByteArray(inputBmp), usePointers(inputBmp)};
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -46,6 +49,12 @@ namespace AgraV2
|
||||
}
|
||||
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<double>();
|
||||
|
||||
Bitmap[] result = new Bitmap[] { medianFilter(inputBmp) };
|
||||
return result;
|
||||
}
|
||||
@@ -80,7 +89,7 @@ namespace AgraV2
|
||||
List<int> Greens = new List<int>();
|
||||
List<int> Reds = new List<int>();
|
||||
|
||||
List<Point> surroundingPixels = getSurroundingPixels(new Point(x, y), 2, imgSize.Width, inputBmp.Height);
|
||||
List<Point> surroundingPixels = getSurroundingPixels(new Point(x, y), Radius, imgSize.Width, inputBmp.Height);
|
||||
|
||||
foreach (Point pixel in surroundingPixels)
|
||||
{
|
||||
|
||||
@@ -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<double>();
|
||||
|
||||
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<Point> getSurroundingPixels(Point centerPoint, int Radius, int imageWidth, int imageHeight)
|
||||
{
|
||||
List<Point> result = new List<Point>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+1
@@ -287,6 +287,7 @@
|
||||
//
|
||||
// pnlEffectToolbox
|
||||
//
|
||||
this.pnlEffectToolbox.AutoScroll = true;
|
||||
this.pnlEffectToolbox.Location = new System.Drawing.Point(6, 24);
|
||||
this.pnlEffectToolbox.Name = "pnlEffectToolbox";
|
||||
this.pnlEffectToolbox.Size = new System.Drawing.Size(188, 250);
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace AgraV2
|
||||
effects = new List<Effect>();
|
||||
effects.Add(new EffectGrayScale("GrayScale", pnlEffectToolbox));
|
||||
effects.Add(new EffectMedianFilter("Median Filter", pnlEffectToolbox));
|
||||
effects.Add(new EffectScale("Scaling", pnlEffectToolbox));
|
||||
effects.Add(new EffectArythmeticOperations("Arithmetic Operations", pnlEffectToolbox));
|
||||
RefreshUi();
|
||||
}
|
||||
private void RefreshUi()
|
||||
@@ -43,6 +45,7 @@ namespace AgraV2
|
||||
FolderBrowserDialog dialog = new FolderBrowserDialog();
|
||||
if (dialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
pnlFiles.Controls.Clear();
|
||||
selectedDirectory = new DirectoryInfo(dialog.SelectedPath);
|
||||
|
||||
List<FileInfo> images = new List<FileInfo>();
|
||||
|
||||
Reference in New Issue
Block a user