private CIELAB[,] ModeRecolor(CIELAB[,] image, PaletteData palette) { int width = image.GetLength(0); int height = image.GetLength(1); CIELAB[,] result = new CIELAB[width, height]; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { double[] scores = new double[palette.colors.Count()]; //check if the color is in the palette CIELAB color = image[i, j]; if (palette.lab.Contains(color)) { result[i, j] = color; continue; } //otherwise, find the best color by mode for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { int x = i + dx; int y = j + dy; double weight = (dx == 0 && dy == 0) ? 4 : 1; if (Util.InBounds(x, y, width, height)) { int bestc = ClosestColorIndex(image[x, y], palette.lab); scores[bestc] -= weight; } } } //pick the color with the min score double minScore = Double.PositiveInfinity; int bestIdx = 0; for (int c = 0; c < palette.colors.Count(); c++) { if (scores[c] < minScore) { minScore = scores[c]; bestIdx = c; } } result[i, j] = palette.lab[bestIdx]; } } return result; }
private CIELAB[,] EdgeUnmixRecolor(CIELAB[,] image, PaletteData palette) { int width = image.GetLength(0); int height = image.GetLength(1); CIELAB[,] result = new CIELAB[width, height]; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { double[] scores = new double[palette.colors.Count()]; //check if the color is in the palette CIELAB color = image[i, j]; if (palette.lab.Contains(color)) { result[i, j] = color; continue; } //otherwise, find the best color //see if this is an edge //if it is, assign the color to be one of the edge color candidates HashSet<CIELAB> tbCandidates = new HashSet<CIELAB>(); HashSet<CIELAB> lrCandidates = new HashSet<CIELAB>(); List<HashSet<CIELAB>> unmixCandidates = new List<HashSet<CIELAB>> { tbCandidates, lrCandidates }; //check edge types //horizontal and vertical HashSet<CIELAB> oneSide = new HashSet<CIELAB>(); HashSet<CIELAB> otherSide = new HashSet<CIELAB>(); Point[] top = new Point[] { new Point(i - 1, j - 1), new Point(i, j - 1), new Point(i + 1, j - 1) }; Point[] bottom = new Point[] { new Point(i - 1, j + 1), new Point(i - 1, j), new Point(i - 1, j + 1) }; Point[] left = new Point[] { new Point(i - 1, j - 1), new Point(i - 1, j), new Point(i - 1, j + 1) }; Point[] right = new Point[] { new Point(i + 1, j - 1), new Point(i + 1, j), new Point(i + 1, j + 1) }; List<Point[]> oneCompare = new List<Point[]> { top, left }; List<Point[]> otherCompare = new List<Point[]> { bottom, right }; bool edge = false; for (int c = 0; c < oneCompare.Count(); c++) { oneSide.Clear(); otherSide.Clear(); foreach (Point p in oneCompare[c]) { if (Util.InBounds(p.X, p.Y, width, height)) { CIELAB rc = ClosestColor(image[p.X, p.Y], palette.lab); //check if in the set if (oneSide.Contains(rc)) { //yes, we found a majority unmixCandidates[c].Add(image[p.X, p.Y]); break; } else { oneSide.Add(rc); } } } foreach (Point p in otherCompare[c]) { if (Util.InBounds(p.X, p.Y, width, height)) { CIELAB rc = ClosestColor(image[p.X, p.Y], palette.lab); //check if in the set if (otherSide.Contains(rc)) { //yes, we found a majority unmixCandidates[c].Add(rc); break; } else { otherSide.Add(rc); } } } //is it an edge? if (unmixCandidates[c].Count() >= 2) { result[i, j] = ClosestColor(image[i, j], unmixCandidates[c].ToList<CIELAB>()); edge = true; break; } } //TODO: //45 degrees //45 degrees-flipped if (!edge) { for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { int x = i + dx; int y = j + dy; double weight = (dx == 0 && dy == 0) ? 4 : 1; if (Util.InBounds(x, y, width, height)) { int bestc = ClosestColorIndex(image[x, y], palette.lab); scores[bestc] -= weight; } } } //pick the color with the min score double minScore = Double.PositiveInfinity; int bestIdx = 0; for (int c = 0; c < palette.colors.Count(); c++) { if (scores[c] < minScore) { minScore = scores[c]; bestIdx = c; } } result[i, j] = palette.lab[bestIdx]; } } } return result; }