public int QDist(Rgb color) { return Math.Abs(color.R - R) + Math.Abs(color.G - G) + Math.Abs(color.B - B); }
public static VpNode CreateTree(Rgb[] colors) { var root = new VpNode(); var candidats = new Stack<Tuple<VpNode, Rgb[]>>(); candidats.Push(Tuple.Create(root, colors)); while (candidats.Count > 0) { var candidat = candidats.Pop(); var node = candidat.Item1; var allColors = candidat.Item2; var color = allColors[0]; if (allColors.Length == 1) { node.Value = color; node.IsLeaf = true; continue; } var sorted = allColors.OrderBy(x => color.QDist(x)).ToArray(); var medianIndex = (sorted.Length - 1) / 2; //2 - 0, 3 - 1, 4 - 1, 5 - 2 var inside = new VpNode { Parent = node }; var insideColors = new Rgb[medianIndex + 1]; Array.Copy(sorted, insideColors, medianIndex + 1); candidats.Push(Tuple.Create(inside, insideColors)); var outside = new VpNode { Parent = node }; var outsideColors = new Rgb[sorted.Length - (medianIndex + 1)]; Array.Copy(sorted, medianIndex + 1, outsideColors, 0, sorted.Length - (medianIndex + 1)); candidats.Push(Tuple.Create(outside, outsideColors)); node.Value = color; node.Radius = sorted[medianIndex].QDist(color); node.Insade = inside; node.Outsade = outside; } return root; }
public static VpNode Near(VpNode root, Rgb target) { long bestQDist = uint.MaxValue; VpNode bestCandidat = null; int i=0; var candidats = new Stack<VpNode>(); candidats.Push(root); while (candidats.Count > 0) { i++; var node = candidats.Pop(); long dist = node.Value.QDist(target); if(!node.IsLeaf) dist = dist + node.Radius; Check.Assert(dist >= 0); if (dist <= bestQDist) // = чтобы добраться до листьев { bestQDist = dist; bestCandidat = node; } dist = node.Value.QDist(target); if (node.Outsade != null && !(dist < node.Radius - bestQDist)) candidats.Push(node.Outsade); if (node.Insade != null && !(dist > bestQDist + node.Radius)) candidats.Push(node.Insade); } //Console.WriteLine(i); Check.Assert(bestCandidat.IsLeaf, "Узел не лист"); return bestCandidat; }
static void Main(string[] args) { //2-8 const int colorBits = 8; const int colorCount = 1 << (colorBits); const int width = 4096; const int height = colorCount * colorCount * colorCount / width; var allColors = new List<Rgb>(); for (int r = 0; r < colorCount; ++r) for (int g = 0; g < colorCount; ++g) for (int b = 0; b < colorCount; ++b) allColors.Add(new Rgb((byte)(r * 256 / colorCount), (byte)(g * 256 / colorCount), (byte)(b * 256 / colorCount))); //var tree = VpTree.CreateTree(allColors.ToArray()); var rnd = new Random(); for(int i=allColors.Count - 1; i > 0; --i ) { var rand = rnd.Next(i); var t = allColors[i]; allColors[i] = allColors[rand]; allColors[rand] = t; } var front = new List<YX>(); //front.Add(new YX((ushort)rnd.Next(height), (ushort)rnd.Next(width))); //front.Add(new YX((ushort)rnd.Next(height), (ushort)rnd.Next(width))); //front.Add(new YX((ushort)rnd.Next(height), (ushort)rnd.Next(width))); //front.Add(new YX((ushort)rnd.Next(height), (ushort)rnd.Next(width))); //front.Add(new YX((ushort)rnd.Next(height), (ushort)rnd.Next(width))); //front.Add(new YX((ushort)rnd.Next(height), (ushort)rnd.Next(width))); front.Add(new YX((ushort)(height/2), (ushort)(width/2))); Func<YX> ololo = () => { var rndIndex = rnd.Next(front.Count); var lastIndex = front.Count - 1; var result = front[rndIndex]; front[rndIndex] = front[lastIndex]; front.RemoveAt(lastIndex); return result; }; var neighbors = new YX[8]; var canvas = new Rgb[height, width]; while (front.Count > 0) { var f = ololo(); if(canvas[f.Y, f.X].isAssigned) continue; double r = 0, g = 0, b = 0, count = 0; neighbors[0] = new YX((ushort)(f.Y - 1), (ushort)(f.X - 1)); neighbors[1] = new YX((ushort)(f.Y - 1), (ushort)(f.X + 0)); neighbors[2] = new YX((ushort)(f.Y - 1), (ushort)(f.X + 1)); neighbors[3] = new YX((ushort)(f.Y + 0), (ushort)(f.X - 1)); neighbors[4] = new YX((ushort)(f.Y + 0), (ushort)(f.X + 1)); neighbors[5] = new YX((ushort)(f.Y + 1), (ushort)(f.X - 1)); neighbors[6] = new YX((ushort)(f.Y + 1), (ushort)(f.X + 0)); neighbors[7] = new YX((ushort)(f.Y + 1), (ushort)(f.X + 1)); Rgb qwe = new Rgb(); int randIndex = 1; foreach (var n in neighbors) { if (n.X < 0 || n.Y < 0 || n.X >= width || n.Y >= height) continue; var c = canvas[n.Y, n.X]; if (!c.isAssigned) { front.Add(n); continue; } if (rnd.Next(randIndex) == 0) { r = c.R; g = c.G; b = c.B; } randIndex++; count++; } if (count > 0) { //r /= count; //g /= count; //b /= count; } else { r = rnd.Next(256); g = rnd.Next(256); b = rnd.Next(256); } r = (int)Math.Round(r + (rnd.Next(5) - 2)); g = (int)Math.Round(g + (rnd.Next(5) - 2)); b = (int)Math.Round(b + (rnd.Next(5) - 2)); if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; int minLen = int.MaxValue; //int randIndex = 1; int bestIndex = 0; //for (int i = 0; i < allColors.Count; ++i) //{ // var color = allColors[i]; // var len = Math.Abs(color.R - r) + Math.Abs(color.G - g) + Math.Abs(color.B - b); // if(len < minLen) // { // randIndex = 1; // minLen = len; // bestIndex = i; // } // else if(len == minLen) // { // randIndex++; // if (rnd.Next(randIndex) == 0) // bestIndex = i; // } //} canvas[f.Y, f.X] = new Rgb((byte)r, (byte)g, (byte)b);// allColors[bestIndex]; allColors[bestIndex] = allColors[allColors.Count-1]; allColors.RemoveAt(allColors.Count-1); if (allColors.Count % 10000 == 0) Console.WriteLine(allColors.Count); } using (var bitmap = new Bitmap(width, height)) { for (int y = 0; y < height; ++y) for (int x = 0; x < width; ++x) { var c = canvas[y, x]; bitmap.SetPixel(x, y, Color.FromArgb(c.R, c.G, c.B)); } Directory.CreateDirectory("Out"); bitmap.Save("Out\\Image_" + DateTime.Now.Ticks + ".png"); } }