diff --git a/OSCADSharp/OSCADSharp/OSCADSharp.csproj b/OSCADSharp/OSCADSharp/OSCADSharp.csproj index 3a6e163..d04d7ac 100644 --- a/OSCADSharp/OSCADSharp/OSCADSharp.csproj +++ b/OSCADSharp/OSCADSharp/OSCADSharp.csproj @@ -55,6 +55,7 @@ + diff --git a/OSCADSharp/OSCADSharp/Utility/Images/CubistImageProcessor.cs b/OSCADSharp/OSCADSharp/Utility/Images/CubistImageProcessor.cs index f7c7977..b3d5527 100644 --- a/OSCADSharp/OSCADSharp/Utility/Images/CubistImageProcessor.cs +++ b/OSCADSharp/OSCADSharp/Utility/Images/CubistImageProcessor.cs @@ -49,7 +49,7 @@ namespace OSCADSharp.Utility.Images { Bitmap img = new Bitmap(Image.FromFile(this.imagePath)); this.setColorArray(img); - this.simlifyColors(img); + this.simplifyColors(img); this.setHeightMappings(img); this.ImageBounds = new Bounds(new Vector3(), new Vector3(img.Width, img.Height, 1)); @@ -85,55 +85,12 @@ namespace OSCADSharp.Utility.Images return cubes; } - private void simlifyColors(Bitmap img) + private void simplifyColors(Bitmap img) { - if (this.simplificationAmount == 0) - { - return; - } - // These calls color values from their originals to new ones based upon the color's proximity to the simpification amount - // the channelSelector and colorFactory functions allow us to use the same function for each. - // TODO: Refactor into a class - mapColors(img, (c) => { return c.R; }, (orig, retained) => { return Color.FromArgb(orig.A, retained.R, orig.G, orig.B); }); - mapColors(img, (c) => { return c.G; }, (orig, retained) => { return Color.FromArgb(orig.A, orig.R, retained.G, orig.B); }); - mapColors(img, (c) => { return c.B; }, (orig, retained) => { return Color.FromArgb(orig.A, orig.R, orig.G, retained.B); }); - } - - private void mapColors(Bitmap img, Func channelSelector, Func colorFactory) - { - Dictionary colorsRetained = new Dictionary(); - - for (int x = 0; x < img.Width; x++) - { - for (int y = 0; y < img.Height; y++) - { - Color curColor; - bool colorMatched = false; - curColor = this.pixels[x, y]; - for (int simVal = 0; simVal < this.simplificationAmount; simVal++) - { - int upperLimit = channelSelector(curColor) + simVal; - int lowerLimit = channelSelector(curColor) - simVal; - if (upperLimit <= 255 && colorsRetained.ContainsKey((byte)upperLimit)) - { - this.pixels[x, y] = colorFactory(curColor, colorsRetained[(byte)upperLimit]); - colorMatched = true; - } - else if (lowerLimit >= 0 && colorsRetained.ContainsKey((byte)lowerLimit)) - { - this.pixels[x, y] = colorFactory(curColor, colorsRetained[(byte)lowerLimit]); - colorMatched = true; - } - } - - if (!colorMatched) - { - colorsRetained[channelSelector(curColor)] = curColor; - } - } - } - } + var simplifier = new ImageSimplifier(img.Width, img.Height, pixels); + simplifier.GlobalReduction(this.simplificationAmount); + } private void setColorArray(Bitmap img) { diff --git a/OSCADSharp/OSCADSharp/Utility/Images/ImageSimplifier.cs b/OSCADSharp/OSCADSharp/Utility/Images/ImageSimplifier.cs new file mode 100644 index 0000000..08402a9 --- /dev/null +++ b/OSCADSharp/OSCADSharp/Utility/Images/ImageSimplifier.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OSCADSharp.Utility.Images +{ + internal class ImageSimplifier + { + private int height; + private Color[,] pixels; + private int width; + + public ImageSimplifier(int width, int height, Color[,] pixels) + { + this.width = width; + this.height = height; + this.pixels = pixels; + } + + internal void GlobalReduction(byte simplificationAmount) + { + if (simplificationAmount == 0) + { + return; + } + + // These calls color values from their originals to new ones based upon the color's proximity to the simpification amount + // the channelSelector and colorFactory functions allow us to use the same function for each. + // TODO: Refactor into a class + mapColors(width, height, simplificationAmount, (c) => { return c.R; }, (orig, retained) => { return Color.FromArgb(orig.A, retained.R, orig.G, orig.B); }); + mapColors(width, height, simplificationAmount, (c) => { return c.G; }, (orig, retained) => { return Color.FromArgb(orig.A, orig.R, retained.G, orig.B); }); + mapColors(width, height, simplificationAmount, (c) => { return c.B; }, (orig, retained) => { return Color.FromArgb(orig.A, orig.R, orig.G, retained.B); }); + } + + private void mapColors(int width, int height, int simplificationAmount, Func channelSelector, Func colorFactory) + { + Dictionary colorsRetained = new Dictionary(); + + for (int x = 0; x < width; x++) + { + for (int y = 0; y < height; y++) + { + Color curColor; + bool colorMatched = false; + curColor = this.pixels[x, y]; + for (int simVal = 0; simVal < simplificationAmount; simVal++) + { + int upperLimit = channelSelector(curColor) + simVal; + int lowerLimit = channelSelector(curColor) - simVal; + if (upperLimit <= 255 && colorsRetained.ContainsKey((byte)upperLimit)) + { + this.pixels[x, y] = colorFactory(curColor, colorsRetained[(byte)upperLimit]); + colorMatched = true; + } + else if (lowerLimit >= 0 && colorsRetained.ContainsKey((byte)lowerLimit)) + { + this.pixels[x, y] = colorFactory(curColor, colorsRetained[(byte)lowerLimit]); + colorMatched = true; + } + } + + if (!colorMatched) + { + colorsRetained[channelSelector(curColor)] = curColor; + } + } + } + } + } +}