public ColorTemplate(Bitmap image, Segmentation seg, PaletteData palette) { slots = seg; //TODO: need to copy the segmentation? originalPalette = new PaletteData(palette); int width = image.Width; int height = image.Height; template = new CIELAB[width, height]; //initialize the template for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { template[i, j] = Util.RGBtoLAB(image.GetPixel(i, j)); } } segToColor = new int[seg.numSegments]; //map each segment to the closest palette color, based on its mean color //TODO: if two adjacent segments have the same mean color, we could merge them... for (int i = 0; i < seg.numSegments; i++) { CIELAB lab = seg.segToMeanColor[i]; int bestColor = -1; double bestDist = Double.PositiveInfinity; for (int j = 0; j < palette.lab.Count(); j++) { double dist = palette.lab[j].SqDist(lab); if (dist < bestDist) { bestDist = dist; bestColor = j; } } segToColor[i] = bestColor; } //subtract the mean color from the template for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { int coloridx = segToColor[slots.assignments[i, j]]; template[i, j] -= palette.lab[coloridx]; //template[i, j] /= palette.lab[coloridx]; } } }
CIELAB[,] template; //relative LAB difference (or change to RGB difference?) #endregion Fields #region Constructors public ColorTemplate(Bitmap image, PaletteData palette) { //create the segmentation based on the palette //TODO: There's a problem that sometimes a palette color won't appear in the image (perhaps due to color blending), and so the slot will have no pixels associated with it int width = image.Width; int height = image.Height; slots = new Segmentation(palette.colors.Count(), width, height); segToColor = new int[slots.numSegments]; template = new CIELAB[width, height]; CIELAB[,] recolored = ModeRecolor(Util.Map<Color, CIELAB>(Util.BitmapToArray(image), c => Util.RGBtoLAB(c)), palette); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { template[i, j] = new CIELAB(); int bestIdx = -1; CIELAB lab = recolored[i, j]; double bestDist = Double.PositiveInfinity; for (int c = 0; c < palette.lab.Count(); c++) { double dist = palette.lab[c].SqDist(lab); if (dist < bestDist) { bestDist = dist; bestIdx = c; if (dist < 0.00001) break; } } slots.assignments[i, j] = bestIdx; slots.counts[bestIdx]++; segToColor[bestIdx] = bestIdx; } } originalPalette = new PaletteData(palette); }
private void ExtractTemplate_Click(object sender, EventArgs e) { //extract templates from images in a directory String[] files = Directory.GetFiles(dir, "*.png"); String infile = dir + "\\palettes.tsv"; Dictionary<String, List<PaletteData>> palettes = LoadFilePalettes(infile); Directory.CreateDirectory(dir + "\\templates\\"); Directory.CreateDirectory(dir + "\\recolor\\"); Random random = new Random(); foreach (String f in files) { Bitmap image = new Bitmap(Image.FromFile(f)); Segmentation seg = new Segmentation(); String basename = f.Replace(dir+"\\", ""); String segFile = dir + "/segments/" + basename; seg.LoadFromFile(f, segFile); ColorTemplate template = new ColorTemplate(image, seg, palettes[basename].First()); Bitmap render = template.Render(); render.Save(dir + "\\templates\\" + basename); //testing random color assignments int numSeg = template.NumSlots(); int[] segToColor = new int[numSeg]; for (int t = 0; t < 3; t++) { for (int i = 0; i < numSeg; i++) segToColor[i] = random.Next(palettes[basename].First().colors.Count()); Bitmap recolor = template.ColorWith(palettes[basename].First(), segToColor); recolor.Save(dir + "\\recolor\\" + Util.ConvertFileName(basename,"_"+t)); Bitmap solidcolor = template.SolidColor(palettes[basename].First(), segToColor); solidcolor.Save(dir + "\\recolor\\" + Util.ConvertFileName(basename, "_" + t + "_solid")); } } }
//Load the segmentation file for a particular image private Segmentation LoadSegAssignments(String key, int width, int height, CIELAB[,] imageLAB) { Bitmap map = new Bitmap(dir + "/segments/" + key); Bitmap resized = Util.ResizeBitmapNearest(map, width, height); Segmentation s = new Segmentation(); s.assignments = new int[width, height]; List<Color> unique = new List<Color>(); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { Color c = resized.GetPixel(i, j); if (!unique.Contains(c)) unique.Add(c); int idx = unique.IndexOf(c); s.assignments[i, j] = idx; } } s.numSegments = unique.Count(); s.counts = new int[s.numSegments]; s.segToMeanColor = new CIELAB[s.numSegments]; for (int i = 0; i < s.numSegments; i++) { s.segToMeanColor[i] = new CIELAB(); } for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { int idx = s.assignments[i, j]; s.counts[idx]++; s.segToMeanColor[idx] += imageLAB[i, j]; } } for (int i = 0; i < s.numSegments; i++) { s.segToMeanColor[i] /= s.counts[i]; } return s; }
private void RenderWheels_Click(object sender, EventArgs e) { String[] files = Directory.GetFiles(dir, "*.png"); String infile = dir + "\\palettes.tsv"; Dictionary<String, List<PaletteData>> palettes = LoadFilePalettes(infile); String oinfile = dir + "\\oracle.csv"; Dictionary<String, List<PaletteData>> oracle = LoadFilePalettes(oinfile); Directory.CreateDirectory(dir + "\\wheels\\"); Random random = new Random(); ColorWheel wheel = new ColorWheel(400, 10); foreach (String f in files) { Bitmap image = new Bitmap(Image.FromFile(f)); Segmentation seg = new Segmentation(); String basename = f.Replace(dir + "\\", ""); List<HSV> phsv = new List<HSV>(); List<HSV> ihsv = new List<HSV>(); List<HSV> ohsv = new List<HSV>(); for (int i = 0; i < image.Width; i++) { for (int j = 0; j < image.Height; j++) { ihsv.Add(Util.RGBtoHSV(image.GetPixel(i,j))); } } foreach (Color c in palettes[basename].First().colors) { phsv.Add(Util.RGBtoHSV(c)); } foreach (Color c in oracle[basename].First().colors) { ohsv.Add(Util.RGBtoHSV(c)); } Bitmap iw = wheel.RenderHueHistogram(ihsv); Bitmap pd = wheel.RenderDisk(phsv); Bitmap od = wheel.RenderDisk(ohsv); iw.Save(dir + "\\wheels\\" + Util.ConvertFileName(basename, "_hist")); pd.Save(dir + "\\wheels\\" + Util.ConvertFileName(basename, "_disk")); od.Save(dir + "\\wheels\\" + Util.ConvertFileName(basename, "_disko")); } }