protected void AddColorItem(int red, int green, int blue) { Color c = Color.FromArgb(red, green, blue); ToolStripMenuItem item = new ToolStripMenuItem(); item.BackColor = c; item.Text = String.Format("{0}, {1}, {2}", red, green, blue); item.Click += new EventHandler(refColorMenuItem_Click); refColorMenu.Items.Add(item); refColors.Add(HSVColor.FromRGB(red, green, blue)); }
public float[] DistanceToCenters(HSVColor color) { float[] ret = new float[centers.Length]; Point p = color.HSCartesian; for (int i = 0; i < centers.Length; i++) { ret[i] = centers[i].Distance(p); } return(ret); }
protected HSVColor AverageColor() { // rotate the colors around so that color0 is at h=180 before averaging float normDiff = 180f - baseColors[0].H; HSVColor[] normColors = new HSVColor[4]; for (int i = 0; i < 4; i++) { float nh = baseColors[i].H + normDiff; if (nh < 0f) { nh = nh + 360f; } if (nh >= 360f) { nh = nh - 360f; } normColors[i] = new HSVColor(nh, baseColors[i].S, baseColors[i].V); } // compute average color float avH = 0f; float avS = 0f; float avV = 0f; for (int i = 0; i < 4; i++) { avH = avH + normColors[i].H; avS = avS + normColors[i].S; avV = avV + normColors[i].V; } avH = avH / 4f; avS = avS / 4f; avV = avV / 4f; // shift H back to original location avH = avH - normDiff; if (avH < 0f) { avH = avH + 360f; } if (avH >= 360f) { avH = avH - 360f; } return(new HSVColor(avH, avS, avV)); }
public ColorInfo(int kmIndex, float minV, float maxV, HSVColor hsv) { this.kmIndex = kmIndex; this.minV = minV; this.maxV = maxV; midV = (maxV + minV) / 2.0f; if (midV == 0.0f) { Vmult = 0.0f; } else { Vmult = 0.5f / midV; } this.hsv = new HSVColor(hsv.H, hsv.S, midV); }
/// <summary> /// computes the distance in cartesian space between the HS components of /// two colors. /// </summary> /// <param name="other"></param> /// <returns></returns> public float Distance(HSVColor other) { float hrad = h * (float)Math.PI / 180.0f; float x1 = s * (float)Math.Cos(hrad); float y1 = s * (float)Math.Sin(hrad); hrad = other.h * (float)Math.PI / 180.0f; float x2 = other.s * (float)Math.Cos(hrad); float y2 = other.s * (float)Math.Sin(hrad); float xdelta = x2 - x1; float ydelta = y2 - y1; return((float)Math.Sqrt(xdelta * xdelta + ydelta * ydelta)); }
public void AddEntry(string tileName, string colorName, HSVColor[] colors) { Dictionary<string, HSVColor[]> tileMap; library.TryGetValue(tileName, out tileMap); if (tileMap == null) { tileMap = new Dictionary<string, HSVColor[]>(); library[tileName] = tileMap; } // make sure we have our own copy of the colors HSVColor[] newColors = new HSVColor[4]; tileMap[colorName] = newColors; newColors[0] = colors[0]; newColors[1] = colors[1]; newColors[2] = colors[2]; newColors[3] = colors[3]; dirty = true; }
public void AddEntry(string tileName, string colorName, HSVColor[] colors) { Dictionary <string, HSVColor[]> tileMap; library.TryGetValue(tileName, out tileMap); if (tileMap == null) { tileMap = new Dictionary <string, HSVColor[]>(); library[tileName] = tileMap; } // make sure we have our own copy of the colors HSVColor[] newColors = new HSVColor[4]; tileMap[colorName] = newColors; newColors[0] = colors[0]; newColors[1] = colors[1]; newColors[2] = colors[2]; newColors[3] = colors[3]; dirty = true; }
public int ClosestIndex(HSVColor color) { float distance; float minDist; int minIndex; minDist = lastCenters[0].Distance(color.HSCartesian); minIndex = 0; for (int i = 1; i < k; i++) { distance = lastCenters[i].Distance(color.HSCartesian); if (distance < minDist) { minDist = distance; minIndex = i; } } return(minIndex); }
private void colorToLibraryButton_Click(object sender, EventArgs e) { HSVColor [] colors = new HSVColor[4]; colors[0] = AdjustedColor(0); colors[1] = AdjustedColor(1); colors[2] = AdjustedColor(2); colors[3] = AdjustedColor(3); string tilename; string colorname; TreeNode selectedNode = libraryTreeView.SelectedNode; if (selectedNode.Tag != null) { colorname = selectedNode.Text; tilename = selectedNode.Parent.Text; } else { tilename = Path.GetFileNameWithoutExtension(currentTileName); colorname = ""; } using (TileColorPrompt dlg = new TileColorPrompt()) { dlg.TileName = tilename; dlg.ColorName = colorname; if (dlg.ShowDialog() == DialogResult.OK) { tilename = dlg.TileName; colorname = dlg.ColorName; library.AddEntry(tilename, colorname, colors); LibraryToTreeview(); } } }
public Kmeans(HSVColor[] colors, int k) { r = new Random(); this.k = k; centers = new Point[k]; lastCenters = new Point[k]; centerColors = new HSVColor[k]; accumulators = new Point[k]; accumulatorCounts = new int[k]; allColors = colors; InitCenters(); int n = 1; DumpCenters(0); while (!FoundSolution()) { ClearAccumulators(); CopyCenters(); for (int i = 0; i < allColors.Length; i++) { // find closest point for this color int closest = ClosestIndex(allColors[i]); Point pt = allColors[i].HSCartesian; // add this color's location to the accumulator for the closest point accumulators[closest].X += pt.X; accumulators[closest].Y += pt.Y; accumulatorCounts[closest]++; } CalculateCenters(); DumpCenters(n); n++; } // convert the colors back to HSV for (int i = 0; i < k; i++) { centerColors[i] = new HSVColor(centers[i]); } centerDistances = new float[k, k]; for (int i = 0; i < k; i++) { for (int j = 0; j < k; j++) { if (i == j) { centerDistances[i, j] = 0.0f; } else { centerDistances[i, j] = centers[i].Distance(centers[j]); } } } }
public void FillTile(DDSFile ddsDest) { for (int y = 0; y < dds.Height; y++) { for (int x = 0; x < dds.Width; x++) { HSVColor hsv = HSVColor.FromRGB(dds.GetPixel(x, y)); float[] distances = km.DistanceToCenters(hsv); int nearest, second; float nearestWeight; if (distances[0] < distances[1]) { nearest = 0; second = 1; } else { nearest = 1; second = 0; } if (distances[2] < distances[nearest]) { second = nearest; nearest = 2; } else if (distances[2] < distances[second]) { second = 2; } if (distances[3] < distances[nearest]) { second = nearest; nearest = 3; } else if (distances[3] < distances[second]) { second = 3; } // only weight between the two colors if the current point is nearer to each of them // than they are to each other. otherwise just weight to neartest. if (km.CenterDistances[nearest, second] < distances[second]) { nearestWeight = 1.0f; } else { nearestWeight = distances[second] / (distances[nearest] + distances[second]); } // init color components int[] components = new int[4]; components[0] = 0; components[1] = 0; components[2] = 0; components[3] = 0; nearest = kmColorMap[nearest]; second = kmColorMap[second]; components[nearest] = (int)(hsv.V * colors[nearest].VMult * 255 * nearestWeight); components[second] = (int)(hsv.V * colors[second].VMult * 255 * (1.0f - nearestWeight)); Color c = Color.FromArgb(components[3], components[0], components[1], components[2]); int index = kmColorMap[km.ClosestIndex(hsv)]; ddsDest.SetColor(x, y, c); } } }
public HSVColor ClosestColor(HSVColor color) { int index = ClosestIndex(color); return(new HSVColor(centers[index], color.V)); }
public Kmeans(HSVColor[] colors, int k) { r = new Random(); this.k = k; centers = new Point[k]; lastCenters = new Point[k]; centerColors = new HSVColor[k]; accumulators = new Point[k]; accumulatorCounts = new int[k]; allColors = colors; InitCenters(); int n = 1; DumpCenters(0); while (!FoundSolution()) { ClearAccumulators(); CopyCenters(); for (int i = 0; i < allColors.Length; i++) { // find closest point for this color int closest = ClosestIndex(allColors[i]); Point pt = allColors[i].HSCartesian; // add this color's location to the accumulator for the closest point accumulators[closest].X += pt.X; accumulators[closest].Y += pt.Y; accumulatorCounts[closest]++; } CalculateCenters(); DumpCenters(n); n++; } // convert the colors back to HSV for (int i = 0; i < k; i++) { centerColors[i] = new HSVColor(centers[i]); } centerDistances= new float[k,k]; for (int i = 0; i < k; i++) { for (int j = 0; j < k; j++) { if (i == j) { centerDistances[i,j] = 0.0f; } else { centerDistances[i,j] = centers[i].Distance(centers[j]); } } } }
public void DumpCenters(int iter) { Console.WriteLine("Iteration {0}", iter); for (int i = 0; i < k; i++) { Console.WriteLine(" X: {0}, Y: {1}", centers[i].X, centers[i].Y); HSVColor color = new HSVColor(centers[i]); Console.WriteLine(" H: {0}, S: {1}, V: {2}", color.H, color.S, color.V); } }
public TileMaker(string filename, int numColors) { dds = DDSFile.LoadFile(filename); int numPixels = dds.Width * dds.Height; HSVColor[] pixels = new HSVColor[numPixels]; // create the array of colors in this image int offset = 0; for (int y = 0; y < dds.Height; y++) { for (int x = 0; x < dds.Width; x++) { pixels[offset] = HSVColor.FromRGB(dds.GetPixel(x, y)); offset++; } } // compute the clustering km = new Kmeans(pixels, numColors); float[] minv = new float[numColors]; float[] maxv = new float[numColors]; for (int i = 0; i < numColors; i++) { minv[i] = float.MaxValue; maxv[i] = float.MinValue; } // compute min and max v for each color cluster for (int y = 0; y < dds.Height; y++) { for (int x = 0; x < dds.Width; x++) { HSVColor hsv = HSVColor.FromRGB(dds.GetPixel(x, y)); int index = km.ClosestIndex(hsv); // record min and max v for each channel float v = hsv.V; if (v < minv[index]) { minv[index] = v; } if (v > maxv[index]) { maxv[index] = v; } } } for (int i = 0; i < numColors; i++) { if (minv[i] == float.MaxValue) { minv[i] = 0.0f; } if (maxv[i] == float.MinValue) { maxv[i] = 0.0f; } ColorInfo ci = new ColorInfo(i, minv[i], maxv[i], km.CenterColors[i]); colors.Add(ci); } colors.Sort(); // create the mapping from the kmeans returned colors to the sorted colors kmColorMap = new int[numColors]; for (int i = 0; i < numColors; i++) { kmColorMap[colors[i].KMIndex] = i; } }
protected void SetAllColors(HSVColor[] colors) { for (int i = 0; i < 4; i++) { baseColors[i] = colors[i]; } UpdateButtons(); ColorizeTile(); }
protected HSVColor AverageColor() { // rotate the colors around so that color0 is at h=180 before averaging float normDiff = 180f - baseColors[0].H; HSVColor[] normColors = new HSVColor[4]; for (int i = 0; i < 4; i++) { float nh = baseColors[i].H + normDiff; if (nh < 0f) { nh = nh + 360f; } if (nh >= 360f) { nh = nh - 360f; } normColors[i] = new HSVColor(nh, baseColors[i].S, baseColors[i].V); } // compute average color float avH = 0f; float avS = 0f; float avV = 0f; for (int i = 0; i < 4; i++) { avH = avH + normColors[i].H; avS = avS + normColors[i].S; avV = avV + normColors[i].V; } avH = avH / 4f; avS = avS / 4f; avV = avV / 4f; // shift H back to original location avH = avH - normDiff; if (avH < 0f) { avH = avH + 360f; } if (avH >= 360f) { avH = avH - 360f; } return new HSVColor(avH, avS, avV); }
public void Load(string filename) { bool empty = (library.Count == 0); XmlReaderSettings xmlReaderSettings = new XmlReaderSettings(); XmlReader r = XmlReader.Create(filename, xmlReaderSettings); // read until we find the start of a tile description while (r.Read()) { // look for the start of the tile description if (r.NodeType == XmlNodeType.Element) { if (r.Name == "Tile") { string tileName = r.GetAttribute("Name"); // read until we find the start of a color description while (r.Read()) { // look for the start of the tile description if (r.NodeType == XmlNodeType.Element) { if (r.Name == "Colors") { string colorName = r.GetAttribute("Name"); HSVColor[] colors = new HSVColor[4]; while (r.Read()) { if (r.NodeType == XmlNodeType.Element) { if (r.Name == "HSVColor") { int colorNum = int.Parse(r.GetAttribute("ColorNum")); float h = float.Parse(r.GetAttribute("H")); float s = float.Parse(r.GetAttribute("S")); float v = float.Parse(r.GetAttribute("V")); colors[colorNum] = new HSVColor(h, s, v); } } else if (r.NodeType == XmlNodeType.EndElement) { break; } } AddEntry(tileName, colorName, colors); } } else if (r.NodeType == XmlNodeType.EndElement) { break; } } } } } dirty = !empty; }
protected HSVColor[] ComputeRefColors(HSVColor refColor) { HSVColor applyTo; switch (refColorMode) { case RefColorMode.Average: default: applyTo = AverageColor(); break; case RefColorMode.Color0: applyTo = baseColors[0]; break; case RefColorMode.Color1: applyTo = baseColors[1]; break; case RefColorMode.Color2: applyTo = baseColors[2]; break; case RefColorMode.Color3: applyTo = baseColors[3]; break; } float deltaH = refColor.H - applyTo.H; float deltaS = refColor.S - applyTo.S; HSVColor[] retColors = new HSVColor[4]; for (int i = 0; i < 4; i++) { float h = baseColors[i].H + deltaH; float s = baseColors[i].S + deltaS; // keep h in [0..360) while (h < 0f) { h = h + 360f; } while (h >= 360f) { h = h - 360f; } // clamp s to [0..1] if (s > 1f) { s = 1f; } if (s < 0f) { s = 0f; } retColors[i] = new HSVColor(h, s, baseColors[i].V); } return(retColors); }
protected HSVColor[] ComputeRefColors(HSVColor refColor) { HSVColor applyTo; switch (refColorMode) { case RefColorMode.Average: default: applyTo = AverageColor(); break; case RefColorMode.Color0: applyTo = baseColors[0]; break; case RefColorMode.Color1: applyTo = baseColors[1]; break; case RefColorMode.Color2: applyTo = baseColors[2]; break; case RefColorMode.Color3: applyTo = baseColors[3]; break; } float deltaH = refColor.H - applyTo.H; float deltaS = refColor.S - applyTo.S; HSVColor[] retColors = new HSVColor[4]; for (int i = 0; i < 4; i++) { float h = baseColors[i].H + deltaH; float s = baseColors[i].S + deltaS; // keep h in [0..360) while (h < 0f) { h = h + 360f; } while (h >= 360f) { h = h - 360f; } // clamp s to [0..1] if (s > 1f) { s = 1f; } if (s < 0f) { s = 0f; } retColors[i] = new HSVColor(h, s, baseColors[i].V); } return retColors; }
public HSVColor ClosestColor(HSVColor color) { int index = ClosestIndex(color); return new HSVColor(centers[index], color.V); }
public int ClosestIndex(HSVColor color) { float distance; float minDist; int minIndex; minDist = lastCenters[0].Distance(color.HSCartesian); minIndex = 0; for (int i = 1; i < k; i++) { distance = lastCenters[i].Distance(color.HSCartesian); if (distance < minDist) { minDist = distance; minIndex = i; } } return minIndex; }
/// <summary> /// computes the distance in cartesian space between the HS components of /// two colors. /// </summary> /// <param name="other"></param> /// <returns></returns> public float Distance(HSVColor other) { float hrad = h * (float)Math.PI / 180.0f; float x1 = s * (float)Math.Cos(hrad); float y1 = s * (float)Math.Sin(hrad); hrad = other.h * (float)Math.PI / 180.0f; float x2 = other.s * (float)Math.Cos(hrad); float y2 = other.s * (float)Math.Sin(hrad); float xdelta = x2 - x1; float ydelta = y2 - y1; return (float)Math.Sqrt(xdelta * xdelta + ydelta * ydelta); }
public float[] DistanceToCenters(HSVColor color) { float[] ret = new float[centers.Length]; Point p = color.HSCartesian; for (int i = 0; i < centers.Length; i++) { ret[i] = centers[i].Distance(p); } return ret; }