image generation

This commit is contained in:
Nadina Siddiqui 2020-11-29 18:13:14 +01:00
parent 74b4ad83e3
commit af4246f481
5 changed files with 151 additions and 2 deletions

1
.gitignore vendored
View file

@ -8,3 +8,4 @@
/.vs/LegoArt /.vs/LegoArt
/LegoArtTool/bin/Debug/netcoreapp3.1 /LegoArtTool/bin/Debug/netcoreapp3.1
/LegoArtTool/obj /LegoArtTool/obj
/.idea

View file

@ -0,0 +1,18 @@
namespace LegoArtTool
{
public class LegoArtColorOffset
{
public LegoArtColorInfo LegoArtColorInfo { get; private set; }
public decimal ColorOffset { get; private set; }
public bool IsAvailable { get; set; }
public LegoArtColorOffset( decimal colorOffset, LegoArtColorInfo legoArtColorInfo)
{
ColorOffset = colorOffset;
LegoArtColorInfo = legoArtColorInfo;
IsAvailable = true;
}
}
}

View file

@ -29,11 +29,10 @@ namespace LegoArtTool
LegoColors.Add(new LegoArtColorInfo(Color.FromArgb(66, 23, 3), 15, 554)); LegoColors.Add(new LegoArtColorInfo(Color.FromArgb(66, 23, 3), 15, 554));
} }
public List<LegoArtColorInfo> ParseImage(string imagePath) public static List<LegoArtColorInfo> ParseImage(Bitmap bitmap)
{ {
var parsedLegoColors = new List<LegoArtColorInfo>(LegoColors); var parsedLegoColors = new List<LegoArtColorInfo>(LegoColors);
var bitmap = new Bitmap(imagePath);
var width = bitmap.Width; var width = bitmap.Width;
var height = bitmap.Height; var height = bitmap.Height;
for (int h = 0; h < height; h++) for (int h = 0; h < height; h++)

View file

@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Linq;
namespace LegoArtTool
{
public class LegoArtImageGenerationService
{
[SuppressMessage("ReSharper.DPA", "DPA0002: Excessive memory allocations in SOH", MessageId = "type: WhereListIterator`1[LegoArtTool.LegoArtColorOffset]")]
public Bitmap GenerateLegoArtImageFromFullColorImage(Bitmap bitmap)
{
var width = bitmap.Width;
var height = bitmap.Height;
var pixels = new List<Pixel>();
for (int h = 0; h < height; h++)
{
for (int w = 0; w < width; w++)
{
var color = bitmap.GetPixel(h, w);
var pixel = MapPixel(color, h ,w);
pixels.Add(pixel);
}
}
var reducedBitmap = new Bitmap(bitmap.Width, bitmap.Height);
var legoArtColorInfos = LegoArtColorService.LegoColors;
var remainingColors = legoArtColorInfos.ToDictionary(k => k.LegoNumber, v => v.HaveCount);
while (pixels.Count(p => !p.IsAssigned) > 0)
{
var minOffset = pixels.Where(p => !p.IsAssigned).SelectMany(p => p.LegoArtColorOffsets.Where(o => o.IsAvailable)
.Select(o => o.ColorOffset))
.Min(x => x);
var pixel = pixels.Where(p => !p.IsAssigned).First(p => p.LegoArtColorOffsets.Any(o => o.ColorOffset == minOffset));
var legoArtColorInfo = pixel.LegoArtColorOffsets.First(o => o.ColorOffset == minOffset).LegoArtColorInfo;
reducedBitmap.SetPixel(pixel.X, pixel.Y, legoArtColorInfo.Color);
remainingColors[legoArtColorInfo.LegoNumber]--;
pixel.IsAssigned = true;
if (remainingColors[legoArtColorInfo.LegoNumber] < 1)
{
var legoArtColorOffsets = pixels.SelectMany(p => p.LegoArtColorOffsets
.Where(o => o.LegoArtColorInfo.LegoNumber == legoArtColorInfo.LegoNumber)).ToList();
legoArtColorOffsets.ForEach(o => o.IsAvailable = false);
}
}
return reducedBitmap;
}
private Pixel MapPixel(
Color inputColor,
int xPosition,
int yPosition)
{
var legoArtColorInfos = LegoArtColorService.LegoColors;
var legoArtColorOffsets = legoArtColorInfos.Select(i => ColorOffset(inputColor, i)).ToList();
return new Pixel(xPosition, yPosition, legoArtColorOffsets);
}
private static LegoArtColorOffset ColourDistance(Color inputColor, LegoArtColorInfo colorInfo)
{
var targetColor = colorInfo.Color;
var rmean = ((long)inputColor.R + (long)targetColor.R) / 2;
var r = (long)inputColor.R - (long)targetColor.R;
var g = (long)inputColor.G - (long)targetColor.G;
var b = (long)inputColor.B - (long)targetColor.B;
var offset = (decimal) Math.Sqrt((((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8));
return new LegoArtColorOffset((decimal) offset, colorInfo);
}
private LegoArtColorOffset ColorOffset(Color inputColor, LegoArtColorInfo colorInfo)
{
var offset = Math.Abs(
ColorNum(inputColor) - ColorNum(colorInfo.Color)) +
GetHueDistance(inputColor.GetHue(), colorInfo.Color.GetHue());
return new LegoArtColorOffset((decimal) offset, colorInfo);
}
private static float GetBrightness(Color c)
{
return (c.R * 0.299f + c.G * 0.587f + c.B *0.114f) / 256f;
}
private static float GetHueDistance(float hue1, float hue2)
{
var d = Math.Abs(hue1 - hue2);
return d > 180 ? 360 - d : d;
}
private static float ColorNum(Color c)
{
return c.GetSaturation() + GetBrightness(c);
}
}
}

22
LegoArtTool/Pixel.cs Normal file
View file

@ -0,0 +1,22 @@
using System.Collections.Generic;
namespace LegoArtTool
{
public class Pixel
{
public int X { get; private set; }
public int Y { get; private set; }
public List<LegoArtColorOffset> LegoArtColorOffsets { get; private set; }
public bool IsAssigned { get; set; }
public Pixel(int x, int y, List<LegoArtColorOffset> legoArtColorOffsets)
{
X = x;
Y = y;
LegoArtColorOffsets = legoArtColorOffsets;
IsAssigned = false;
}
}
}