public static List <Color> MedianCut(Bitmap bitmap, int count) { List <List <Color> > colors = new List <List <Color> >() { BitmapConvert.ColorArrayFromBitmap(bitmap).ToList() }; while (colors.Count * 2 <= count) { List <List <Color> > nextColors = new List <List <Color> >(); Parallel.ForEach(colors, pixels => { var splitted = SplitColors(pixels); nextColors.Add(splitted.Item1); nextColors.Add(splitted.Item2); }); colors = nextColors; } while (colors.Count < count) { var splitted = SplitColors(colors[colors.Count - 1]); colors.RemoveAt(colors.Count - 1); colors.Add(splitted.Item1); colors.Add(splitted.Item2); } List <Color> resultColors = new List <Color>(); foreach (var pixels in colors) { resultColors.Add(ColorHelpers.AverageColors(pixels)); } return(resultColors); //return colors.Select(l => AverageColors(l)).ToList(); }
//initialization could be improved public static List <Color> KMeans(Bitmap bitmap, int count, int maxSteps) { Color[] colors = BitmapConvert.ColorArrayFromBitmap(bitmap); int[] clusters = new int[colors.Length]; Color[] means = new Color[count]; { List <Color> sorted = colors.ToList(); sorted.Sort((a, b) => a.GetHue().CompareTo(b.GetHue())); for (int i = 0; i < count; i++) { means[i] = sorted[i * (sorted.Count / count) + (sorted.Count / count) / 2]; } } bool changed = false; for (int step = 0; step < maxSteps; step++) { Parallel.For(0, colors.Length, i => { int newCluster = ColorHelpers.GetMinDistanceIndex(colors[i], means); if (newCluster != clusters[i]) { changed = true; clusters[i] = newCluster; } }); if (!changed) { break; } int[] clusterCounts = new int[count]; (int R, int G, int B)[] clusterSums = new (int R, int G, int B)[count];
public static Bitmap SortColors(Bitmap bitmap, int count) { DirectBitmap result = new DirectBitmap(bitmap.Width, bitmap.Height); List <List <Color> > colors = new List <List <Color> >() { BitmapConvert.ColorArrayFromBitmap(bitmap).ToList() }; while (colors.Count * 2 <= count) { List <List <Color> > nextColors = new List <List <Color> >(); Parallel.ForEach(colors, pixels => { var splitted = SplitColors(pixels); nextColors.Add(splitted.Item1); nextColors.Add(splitted.Item2); }); colors = nextColors; } while (colors.Count < count) { var splitted = PaletteGeneration.SplitColors(colors[colors.Count - 1]); colors.RemoveAt(colors.Count - 1); colors.Add(splitted.Item1); colors.Add(splitted.Item2); } var resColors = new List <Color>(); foreach (var pixels in colors) { resColors.AddRange(pixels); } int width = bitmap.Width; int height = bitmap.Height; Parallel.For(0, bitmap.Width, x => { for (int y = 0; y < height; y++) { if (y > 0 && y % (height / count) == 0) { result.SetPixel(x, y, Color.Black); } else { result.SetPixel(x, y, resColors[x + y * width]); } } }); return(result.Bitmap); }
public static Bitmap ClosestColor(Bitmap bitmap, Color[] colorPalette) { Color[] colors = BitmapConvert.ColorArrayFromBitmap(bitmap); DirectBitmap result = new DirectBitmap(bitmap.Width, bitmap.Height); int width = bitmap.Width; int height = bitmap.Height; Parallel.For(0, bitmap.Width, x => { for (int y = 0; y < height; y++) { Color pixel = colors[x + y * width]; result.SetPixel(x, y, ColorHelpers.GetMinDistance(pixel, colorPalette)); //result.SetPixel(x, y, pixel); } }); return(result.Bitmap); }
public static Bitmap ShiftHsl(Bitmap bitmap, float hueShift, float saturation, float lightness) { Color[] colors = BitmapConvert.ColorArrayFromBitmap(bitmap); DirectBitmap result = new DirectBitmap(bitmap.Width, bitmap.Height); for (int x = 0; x < bitmap.Width; x++) { for (int y = 0; y < bitmap.Height; y++) { var hsl = ColorConvertors.ColorToHsl(colors[x + y * bitmap.Width]); hsl.H = MathF.Max(hsl.H + hueShift, 0) % 360; hsl.S = MathF.Min(MathF.Max((hsl.S) * (1 + saturation), 0), 1); hsl.L = MathF.Min(MathF.Max((hsl.L) * (1 + lightness), 0), 1); result.SetPixel(x, y, ColorConvertors.HslToColor(hsl)); } } return(result.Bitmap); }
public static Bitmap BlurImage(Bitmap bitmap, float sigma) { int range = (int)(1 + sigma * 2f); float c = 1 / MathF.Sqrt(sigma * sigma * 2 * MathF.PI); float[] blurMatrix = new float[range]; for (int i = 0; i < range; i++) { blurMatrix[i] = MathF.Pow(MathF.E, -(i * i) / (2 * sigma * sigma)) * c; } Color[] colors = BitmapConvert.ColorArrayFromBitmap(bitmap); Color[] colors2 = new Color[colors.Length]; DirectBitmap result = new DirectBitmap(bitmap.Width, bitmap.Height); int width = bitmap.Width; int height = bitmap.Height; Parallel.For(0, bitmap.Width, x => { for (int y = 0; y < height; y++) { float r = 0; float g = 0; float b = 0; for (int i = x - range + 1; i < x + range; i++) { if (i < 0 || i >= width) { r += colors[x + y * width].R * blurMatrix[Math.Abs(x - i)]; g += colors[x + y * width].G * blurMatrix[Math.Abs(x - i)]; b += colors[x + y * width].B * blurMatrix[Math.Abs(x - i)]; } else { r += colors[i + y * width].R * blurMatrix[Math.Abs(x - i)]; g += colors[i + y * width].G * blurMatrix[Math.Abs(x - i)]; b += colors[i + y * width].B * blurMatrix[Math.Abs(x - i)]; } } colors2[x + y * width] = ColorConvertors.ClampRgbToColor((int)r, (int)g, (int)b); } }); Parallel.For(0, bitmap.Height, y => { for (int x = 0; x < width; x++) { float r = 0; float g = 0; float b = 0; for (int j = y - range + 1; j < y + range; j++) { if (j < 0 || j >= height) { r += colors[x + y * width].R * blurMatrix[Math.Abs(y - j)]; g += colors[x + y * width].G * blurMatrix[Math.Abs(y - j)]; b += colors[x + y * width].B * blurMatrix[Math.Abs(y - j)]; } else { r += colors2[x + j * width].R * blurMatrix[Math.Abs(y - j)]; g += colors2[x + j * width].G * blurMatrix[Math.Abs(y - j)]; b += colors2[x + j * width].B * blurMatrix[Math.Abs(y - j)]; } } result.SetPixel(x, y, ColorConvertors.ClampRgbToColor((int)r, (int)g, (int)b)); } }); return(result.Bitmap); }