Commit 7e7e39a8 authored by BORNON Théophile's avatar BORNON Théophile

Better faster stronger

parent 77e62751
......@@ -3,7 +3,7 @@ using System.Threading;
namespace S04_Projet
{
class MultiThreadedTask
unsafe class MultiThreadedTask
{
#region Attributs
public enum Operation
......@@ -20,6 +20,8 @@ namespace S04_Projet
}
private byte[] file;
private byte[] NewRMatrix, NewGMatrix, NewBMatrix;
byte* rPixelPtr, gPixelPtr, bPixelPtr;
private int nbPixel;
private int nbProcessors;
private Options opt;
......@@ -49,8 +51,11 @@ namespace S04_Projet
this.opt = opt;
this.filter = filter;
this.factor = factor;
this.rPixelPtr = rPixelPtr;
this.gPixelPtr = gPixelPtr;
this.bPixelPtr = bPixelPtr;
size = filter.GetLength(0);
nbProcessors = Environment.ProcessorCount;
nbProcessors = 4;
}
public void Start()
......@@ -96,10 +101,14 @@ namespace S04_Projet
#endregion
#region Filter
public void ApplyFilter()
public MyImage ApplyFilter()
{
int pixelNumber = opt.width * opt.height;
int pixelPerThread = pixelNumber / nbProcessors;
NewRMatrix = new byte[pixelNumber];
NewGMatrix = new byte[pixelNumber];
NewBMatrix = new byte[pixelNumber];
Thread[] threads = new Thread[nbProcessors];
Console.WriteLine("Creating {0} thread(s)", nbProcessors);
......@@ -114,9 +123,11 @@ namespace S04_Projet
{
threads[i].Join();
}
return new MyImage(opt, NewRMatrix, NewGMatrix, NewBMatrix);
}
public unsafe void ApplyFilterTask(object i)
private unsafe void ApplyFilterTask(object i)
{
int x, y;
int start = opt.width * opt.height / nbProcessors * (int)i;
......@@ -141,7 +152,10 @@ namespace S04_Projet
r = ConvolutionalResult(rMatrixPtr, filterPtr, size, factor);
g = ConvolutionalResult(gMatrixPtr, filterPtr, size, factor);
b = ConvolutionalResult(bMatrixPtr, filterPtr, size, factor);
NewRMatrix[j] = r;
NewGMatrix[j] = g;
NewBMatrix[j] = b;
}
}
}
......@@ -167,12 +181,12 @@ namespace S04_Projet
if (y < 0) y = 0;
else if (y >= opt.height) y = opt.height - 1;
if (rgb == RGB.R) ;
// *(matrixPtr + i) = Pixels[x, y].r;
else if (rgb == RGB.G) ;
// *(matrixPtr + i) = Pixels[x, y].g;
else if (rgb == RGB.B) ;
// *(matrixPtr + i) = Pixels[x, y].b;
if (rgb == RGB.R)
*(matrixPtr + i) = *(rPixelPtr + x + y * opt.width);
else if (rgb == RGB.G)
*(matrixPtr + i) = *(gPixelPtr + x + y * opt.width);
else if (rgb == RGB.B)
*(matrixPtr + i) = *(bPixelPtr + x + y * opt.width);
}
}
......
......@@ -9,6 +9,7 @@ namespace S04_Projet
private Options opt;
byte[] rPixels, gPixels, bPixels;
byte[] file;
private int nbProcessors;
public enum GrayFilterType
{
......@@ -16,7 +17,7 @@ namespace S04_Projet
LUMINOSITY
}
private enum RGB
public enum RGB
{
R,
G,
......@@ -49,6 +50,7 @@ namespace S04_Projet
{
if (file.Length != 0)
{
nbProcessors = Environment.ProcessorCount;
FromFileToImage();
}
}
......@@ -83,7 +85,7 @@ namespace S04_Projet
private unsafe void FromFileToImage()
{
opt = new Options();
#region Header
opt.format = (char)file[0] + "" + (char)file[1];
opt.fileSize = EndianToInt(file, 2);
......@@ -146,13 +148,13 @@ namespace S04_Projet
/// Sauvegarde l'image vers le chemin passé en paramètres
/// </summary>
/// <param name="output">Chemin de sortie de l'image</param>
private void FromImageToFile(string output)
private unsafe void FromImageToFile(string output)
{
int nbPixel = (opt.height * opt.width);
int bytesNumber = nbPixel * 3 + opt.offset + opt.height * opt.padding; // Multiply by 3 because 3 bytes / pixel
byte[] file = new byte[bytesNumber];
#region HEADER
// FORMAT
ASCIIEncoding encoding = new ASCIIEncoding();
......@@ -162,7 +164,7 @@ namespace S04_Projet
// OFFSET
MixArrays(file, IntToEndian(opt.offset), 10);
#endregion
#region File Info Header
MixArrays(file, IntToEndian(opt.fileInfoHeaderSize), 14);
MixArrays(file, IntToEndian(opt.width), 18);
......@@ -176,18 +178,21 @@ namespace S04_Projet
MixArrays(file, IntToEndian(opt.nbColor), 46);
MixArrays(file, IntToEndian(0), 50); // Number of important colors
#endregion
#region Pixel array
int x;
int y;
for (int i = 0; i < nbPixel; i++)
fixed (byte* filePtr = file)
{
x = i % opt.width;
y = i / opt.width;
for (int i = 0; i < nbPixel; i++)
{
x = i % opt.width;
y = i / opt.width;
file[i * 3 + opt.padding * y + opt.offset] = bPixels[i];
file[i * 3 + opt.padding * y + opt.offset + 1] = gPixels[i];
file[i * 3 + opt.padding * y + opt.offset + 2] = rPixels[i];
*(filePtr + i * 3 + opt.padding * y + opt.offset) = bPixels[i];
*(filePtr + i * 3 + opt.padding * y + opt.offset + 1) = gPixels[i];
*(filePtr + i * 3 + opt.padding * y + opt.offset + 2) = rPixels[i];
}
}
#endregion
......@@ -265,76 +270,76 @@ namespace S04_Projet
/// </summary>
/// <param name="coeff">Coefficient d'agrandissement de l'image</param>
/// <returns>Image élargie</returns>
/* public MyImage Enlarge(int coeff)
{
Options options = opt.Copy();
options.width *= coeff;
options.height *= coeff;
Pixel[,] PixelArr = new Pixel[opt.width * 2, opt.height * 2];
for (int i = 0; i < options.width * options.height; i++)
{
int x = i % options.width;
int y = i % options.height;
byte[] fromX = Pixels[x, y].getRGB();
byte[] toX;
byte[] toY;
byte[] toXY;
if (x + 1 < options.width) toX = Pixels[x + 1, y].getRGB();
if (y + 1 < options.height) toY = Pixels[x, y + 1].getRGB();
if (y + 1 < options.height && x + 1 < options.width) toXY = Pixels[x + 1, y + 1].getRGB();
}
return null;
}*/
/* public MyImage Enlarge(int coeff)
{
Options options = opt.Copy();
options.width *= coeff;
options.height *= coeff;
Pixel[,] PixelArr = new Pixel[opt.width * 2, opt.height * 2];
for (int i = 0; i < options.width * options.height; i++)
{
int x = i % options.width;
int y = i % options.height;
byte[] fromX = Pixels[x, y].getRGB();
byte[] toX;
byte[] toY;
byte[] toXY;
if (x + 1 < options.width) toX = Pixels[x + 1, y].getRGB();
if (y + 1 < options.height) toY = Pixels[x, y + 1].getRGB();
if (y + 1 < options.height && x + 1 < options.width) toXY = Pixels[x + 1, y + 1].getRGB();
}
return null;
}*/
/// <summary>
/// Rétrécit l'image par rapport au coefficient passé en paramètres
/// </summary>
/// <param name="coeff">Coefficient de rétrécissement de l'image</param>
/// <returns>Image rétrécie</returns>
/* public MyImage Shrink(int coeff)
{
Options options = opt.Copy();
options.width /= coeff;
options.height /= coeff;
options.padding = options.width % 4;
options.imgSize = options.width * options.height * 3 + options.padding * options.height;
options.fileSize = options.imgSize + options.fileInfoHeaderSize;
/* public MyImage Shrink(int coeff)
{
Options options = opt.Copy();
options.width /= coeff;
options.height /= coeff;
options.padding = options.width % 4;
options.imgSize = options.width * options.height * 3 + options.padding * options.height;
options.fileSize = options.imgSize + options.fileInfoHeaderSize;
Pixel[,] PixelArr = new Pixel[options.width, options.height];
Pixel[,] PixelArr = new Pixel[options.width, options.height];
int x0, y0, x, y;
int[] rgb;
byte[] _rgb;
int x0, y0, x, y;
int[] rgb;
byte[] _rgb;
for (int i = 0; i < options.width * options.height; i++)
{
x0 = i % options.width;
y0 = i / options.width;
for (int i = 0; i < options.width * options.height; i++)
{
x0 = i % options.width;
y0 = i / options.width;
rgb = new int[] { 0, 0, 0 };
rgb = new int[] { 0, 0, 0 };
for (int j = 0; j < coeff * coeff; j++)
{
x = x0 * coeff + j % coeff;
y = y0 * coeff + j / coeff;
for (int j = 0; j < coeff * coeff; j++)
{
x = x0 * coeff + j % coeff;
y = y0 * coeff + j / coeff;
_rgb = Pixels[x, y].getRGB();
for (int k = 0; k < 3; k++)
rgb[k] += _rgb[k];
}
_rgb = Pixels[x, y].getRGB();
for (int k = 0; k < 3; k++)
rgb[k] += _rgb[k];
}
for (int j = 0; j < 3; j++)
rgb[j] = (byte)(rgb[j] / (coeff * coeff));
for (int j = 0; j < 3; j++)
rgb[j] = (byte)(rgb[j] / (coeff * coeff));
PixelArr[x0, y0] = new Pixel(rgb);
}
PixelArr[x0, y0] = new Pixel(rgb);
}
return new MyImage(options, PixelArr);
}*/
return new MyImage(options, PixelArr);
}*/
/// <summary>
/// Passe l'image en nuances de gris
......@@ -342,135 +347,33 @@ namespace S04_Projet
/// <param name="scale">Nombre de nuances de gris désirées (entre 2 et 255) (2 = noir et blanc)</param>
/// <param name="type">Type de transformation. Linéaire ou en fonction de la luminosité de la couleur</param>
/// <returns>Image en nuances de gris</returns>
/*
public MyImage ToGrayScale(byte scale, GrayFilterType type)
{
Options options = opt.Copy();
opt.nbColor = scale;
Pixel[,] PixelArr = new Pixel[opt.width, opt.height];
for (int i = 0; i < opt.width * opt.height; i++)
{
int x = i % opt.width;
int y = i / opt.width;
if (type == GrayFilterType.LINEAR)
PixelArr[x, y] = Pixels[x, y].getGrayScale(scale);
else if (type == GrayFilterType.LUMINOSITY)
PixelArr[x, y] = Pixels[x, y].getGrayScaleLuminosity(scale);
}
return new MyImage(options, PixelArr);
}*/
/// <summary>
/// Applique un filtre de convolution à l'image
/// </summary>
/// <param name="filter">Filtre de convolution</param>
/// <param name="factor">Facteur de normalisation</param>
/// <returns>Image avec le filtre de convolution appliqué</returns>
/*public MyImage ApplyConvFilter(short[,] filter, double factor)
{
if (filter.GetLength(0) == filter.GetLength(1) && filter.GetLength(0) % 2 == 1)
{
int size = filter.GetLength(0);
Options options = opt.Copy();
int nbPixel = options.height * options.width;
Pixel[,] PixelArr = new Pixel[options.width, options.height];
if (!Program.MULTITHREADING)
{
int x, y;
byte[,] rMatrix, gMatrix, bMatrix;
byte r, g, b;
for (int i = 0; i < nbPixel; i++)
{
x = i % options.width;
y = i / options.width;
rMatrix = GetMatrix(x, y, size, RGB.R);
gMatrix = GetMatrix(x, y, size, RGB.G);
bMatrix = GetMatrix(x, y, size, RGB.B);
r = ConvolutionalResult(rMatrix, filter, size, factor);
g = ConvolutionalResult(gMatrix, filter, size, factor);
b = ConvolutionalResult(bMatrix, filter, size, factor);
PixelArr[x, y] = new Pixel(r, g, b);
}
}
else
{
MultiThreadedTask FilterImageTask =
new MultiThreadedTask(MultiThreadedTask.Operation.Filter, Pixels, opt, filter, factor);
FilterImageTask.Start();
Pixel[,] _Pixels = FilterImageTask.getFilteredMatrix();
return new MyImage(opt, _Pixels);
}
return new MyImage(options, PixelArr);
}
else if (filter.GetLength(0) != filter.GetLength(1))
{
throw new Exception("Matrice non carrée");
}
else
{
throw new Exception("Matrice de taille paire");
}
}
/// <summary>
/// Retourne la matrice de pixels de taille size ,de milieu (x0,y0) et de couleur RGB
/// </summary>
/// <param name="x0">Coordonnée verticale du pixel milieu</param>
/// <param name="y0">Coordonnée horizontale du pixel milieu</param>
/// <param name="size">Taille de la matrice de pixel désirée</param>
/// <param name="rgb">Couleur souhaitée</param>
/// <returns>Matrice de pixels de taille size ,de milieu (x0,y0) et de couleur RGB</returns>
private byte[,] GetMatrix(int x0, int y0, int size, RGB rgb)
/*
public MyImage ToGrayScale(byte scale, GrayFilterType type)
{
Options options = opt.Copy();
opt.nbColor = scale;
Pixel[,] PixelArr = new Pixel[opt.width, opt.height];
for (int i = 0; i < opt.width * opt.height; i++)
{
int x = i % opt.width;
int y = i / opt.width;
if (type == GrayFilterType.LINEAR)
PixelArr[x, y] = Pixels[x, y].getGrayScale(scale);
else if (type == GrayFilterType.LUMINOSITY)
PixelArr[x, y] = Pixels[x, y].getGrayScaleLuminosity(scale);
}
return new MyImage(options, PixelArr);
}*/
public unsafe MyImage Filter(short[,] filter, double factor)
{
byte[,] matrix = new byte[size, size];
for (int i = 0; i < size * size; i++)
fixed (byte* rPixelPtr = rPixels, gPixelPtr = gPixels, bPixelPtr = bPixels)
{
int x = x0 + (i % size) - ((size - 1) / 2);
int y = y0 + (i / size) - ((size - 1) / 2);
if (x < 0) x = 0;
else if (x >= opt.width) x = opt.width - 1;
if (y < 0) y = 0;
else if (y >= opt.height) y = opt.height - 1;
if (rgb == RGB.R)
matrix[(i % size), (i / size)] = Pixels[x, y].r;
else if (rgb == RGB.G)
matrix[(i % size), (i / size)] = Pixels[x, y].g;
else if (rgb == RGB.B)
matrix[(i % size), (i / size)] = Pixels[x, y].b;
MultiThreadedTask multiThreadedTask = new MultiThreadedTask(MultiThreadedTask.Operation.Filter, rPixelPtr, gPixelPtr, bPixelPtr, opt, filter, factor);
return multiThreadedTask.ApplyFilter();
}
return matrix;
}
/// <summary>
/// Calcul convolutionnel
/// </summary>
/// <param name="matrix">Matrice</param>
/// <param name="conv">Convolution</param>
/// <param name="size">Taille du filtre</param>
/// <param name="factor">Factor de normalisation</param>
/// <returns>Résultat du calcul convolutinnel</returns>
public static byte ConvolutionalResult(byte[,] matrix, short[,] conv, int size, double factor)
{
short r = 0; ;
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
r += (short)(matrix[x, y] * conv[x, y]);
r = (short)Math.Round(r * factor);
if (r > 255) return 255;
else if (r < 0) return 0;
else return (byte)r;
}*/
/// <summary>
/// Passe d'un nombre au format Endian à un nombre entier
/// </summary>
......
......@@ -60,12 +60,12 @@ namespace S04_Projet
Stopwatch sw = new Stopwatch();
MyImage imgg = new MyImage("img/image.bmp");
Console.WriteLine("Loading done");
sw.Start();
MyImage imgg = new MyImage("img/flocon.bmp");
MyImage newImg = imgg.Filter(sharpenFilter, 1);
sw.Stop();
imgg.Save("test.bmp");
Console.WriteLine("Loading done");
//imgg.ApplyConvFilter(edgeDetect1Filter, 1);
newImg.Save("filter.bmp");
Console.WriteLine(sw.ElapsedMilliseconds);
Console.Read();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment