mirror of
https://github.com/eliasstepanik/OSCADSharpDotnet7.git
synced 2026-01-22 18:58:28 +00:00
Added a first-pass naive simplification pass for image simplification.
This commit is contained in:
parent
c6347b0f93
commit
10185ea15e
@ -20,5 +20,10 @@ namespace OSCADSharp.Solids.Imported
|
|||||||
/// Converts the colors in the image to black and white
|
/// Converts the colors in the image to black and white
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UseGrayScale { get; set; } = false;
|
public bool UseGrayScale { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reduces the total number of colors in the image by merging similar colors together.
|
||||||
|
/// </summary>
|
||||||
|
public byte SimplificationAmount { get; set; } = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,7 @@ namespace OSCADSharp.Solids.Imported
|
|||||||
options = new ImageImportOptions();
|
options = new ImageImportOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
processor = new CubistImageProcessor(imagePath, options.HeightMapping, options.UseGrayScale);
|
processor = new CubistImageProcessor(imagePath, options.HeightMapping, options.UseGrayScale, options.SimplificationAmount);
|
||||||
var obj = processor.ProcessImage();
|
var obj = processor.ProcessImage();
|
||||||
|
|
||||||
var img = new ImportedImage()
|
var img = new ImportedImage()
|
||||||
|
|||||||
@ -22,17 +22,19 @@ namespace OSCADSharp.Utility.Images
|
|||||||
List<OSCADObject> cubes = new List<OSCADObject>();
|
List<OSCADObject> cubes = new List<OSCADObject>();
|
||||||
private Color[,] pixels;
|
private Color[,] pixels;
|
||||||
private bool useGrayScale;
|
private bool useGrayScale;
|
||||||
|
private byte simplificationAmount;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Internal Fields
|
#region Internal Fields
|
||||||
public Bounds ImageBounds { get; set; }
|
public Bounds ImageBounds { get; set; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
internal CubistImageProcessor(string imagePath, bool includeHeight = true, bool useGrayScale = false)
|
internal CubistImageProcessor(string imagePath, bool includeHeight = true, bool useGrayScale = false, byte simplificationAmount = 0)
|
||||||
{
|
{
|
||||||
this.includeHeight = includeHeight;
|
this.includeHeight = includeHeight;
|
||||||
this.imagePath = imagePath;
|
this.imagePath = imagePath;
|
||||||
this.useGrayScale = useGrayScale;
|
this.useGrayScale = useGrayScale;
|
||||||
|
this.simplificationAmount = simplificationAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OSCADObject ProcessImage()
|
public OSCADObject ProcessImage()
|
||||||
@ -47,6 +49,7 @@ namespace OSCADSharp.Utility.Images
|
|||||||
{
|
{
|
||||||
Bitmap img = new Bitmap(Image.FromFile(this.imagePath));
|
Bitmap img = new Bitmap(Image.FromFile(this.imagePath));
|
||||||
this.setColorArray(img);
|
this.setColorArray(img);
|
||||||
|
this.simlifyColors(img);
|
||||||
this.setHeightMappings(img);
|
this.setHeightMappings(img);
|
||||||
this.ImageBounds = new Bounds(new Vector3(), new Vector3(img.Width, img.Height, 1));
|
this.ImageBounds = new Bounds(new Vector3(), new Vector3(img.Width, img.Height, 1));
|
||||||
|
|
||||||
@ -82,6 +85,56 @@ namespace OSCADSharp.Utility.Images
|
|||||||
return cubes;
|
return cubes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void simlifyColors(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<Color, byte> channelSelector, Func<Color, Color, Color> colorFactory)
|
||||||
|
{
|
||||||
|
Dictionary<byte, Color> colorsRetained = new Dictionary<byte, Color>();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setColorArray(Bitmap img)
|
private void setColorArray(Bitmap img)
|
||||||
{
|
{
|
||||||
this.pixels = new Color[img.Width, img.Height];
|
this.pixels = new Color[img.Width, img.Height];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user