commit
21395633d2
5 changed files with 160 additions and 4 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -8,3 +8,4 @@
|
||||||
/.vs/LegoArt
|
/.vs/LegoArt
|
||||||
/LegoArtTool/bin/Debug/netcoreapp3.1
|
/LegoArtTool/bin/Debug/netcoreapp3.1
|
||||||
/LegoArtTool/obj
|
/LegoArtTool/obj
|
||||||
|
/.idea
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ namespace LegoArt
|
||||||
private readonly LegoArtColorService legoArtColorService;
|
private readonly LegoArtColorService legoArtColorService;
|
||||||
private readonly BitmapHelperService bitmapHelperService;
|
private readonly BitmapHelperService bitmapHelperService;
|
||||||
private readonly ImageHelperService imageHelperService;
|
private readonly ImageHelperService imageHelperService;
|
||||||
|
private LegoArtImageGenerationService legoArtImageGenerationService;
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
|
|
@ -25,6 +26,7 @@ namespace LegoArt
|
||||||
legoArtColorService = new LegoArtColorService();
|
legoArtColorService = new LegoArtColorService();
|
||||||
bitmapHelperService = new BitmapHelperService();
|
bitmapHelperService = new BitmapHelperService();
|
||||||
imageHelperService = new ImageHelperService();
|
imageHelperService = new ImageHelperService();
|
||||||
|
legoArtImageGenerationService = new LegoArtImageGenerationService();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnImageChooser_Click(object sender, RoutedEventArgs e)
|
private void btnImageChooser_Click(object sender, RoutedEventArgs e)
|
||||||
|
|
@ -51,13 +53,15 @@ namespace LegoArt
|
||||||
private void LoadImage(string path)
|
private void LoadImage(string path)
|
||||||
{
|
{
|
||||||
var bitmap = new System.Drawing.Bitmap(path);
|
var bitmap = new System.Drawing.Bitmap(path);
|
||||||
var legoArtColors = legoArtColorService.ParseImage(bitmap);
|
var reducedBitMap = legoArtImageGenerationService.GenerateLegoArtImageFromFullColorImage(bitmap);
|
||||||
|
|
||||||
|
var legoArtColors = legoArtColorService.ParseImage(reducedBitMap);
|
||||||
if (legoArtColors != null)
|
if (legoArtColors != null)
|
||||||
{
|
{
|
||||||
var sourceBitamp = bitmapHelperService.Scale(bitmap, 1);
|
var sourceBitmap = bitmapHelperService.Scale(reducedBitMap, 1);
|
||||||
sourceImage.Source = imageHelperService.LoadToImage(sourceBitamp);
|
sourceImage.Source = imageHelperService.LoadToImage(sourceBitmap);
|
||||||
|
|
||||||
var convertedBitmap = bitmapHelperService.ConvertToPixelMatrix(sourceBitamp, 20);
|
var convertedBitmap = bitmapHelperService.ConvertToPixelMatrix(sourceBitmap, 20);
|
||||||
scaledImage.Source = imageHelperService.LoadToImage(convertedBitmap);
|
scaledImage.Source = imageHelperService.LoadToImage(convertedBitmap);
|
||||||
|
|
||||||
parentStackPanel.Children.Clear();
|
parentStackPanel.Children.Clear();
|
||||||
|
|
|
||||||
18
LegoArtTool/LegoArtColorOffset.cs
Normal file
18
LegoArtTool/LegoArtColorOffset.cs
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
111
LegoArtTool/LegoArtImageGenerationService.cs
Normal file
111
LegoArtTool/LegoArtImageGenerationService.cs
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace LegoArtTool
|
||||||
|
{
|
||||||
|
public class LegoArtImageGenerationService
|
||||||
|
{
|
||||||
|
private readonly List<LegoArtColorInfo> legoArtColorInfos;
|
||||||
|
|
||||||
|
public LegoArtImageGenerationService()
|
||||||
|
{
|
||||||
|
var legoArtColorService = new LegoArtColorService();
|
||||||
|
legoArtColorInfos = legoArtColorService.GetLegoColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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 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
22
LegoArtTool/Pixel.cs
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue