public WTStipple(Image source, WangTileSet tileSet, int tonalRange, Bitmap dest) { // Convert source image to grayscale Bitmap bmp = new Bitmap(source.Width, source.Height); Graphics g = Graphics.FromImage(bmp); g.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height)); float[,] grayscale = ToDensity(bmp); this.tileSet = tileSet; // Subdivide image recusively as long as we need more density on each leave's tile // to account for the underlying sampled region on the image ImageTreeNode root = new ImageTreeNode(); Random r = new Random(tileSet.tiles.Count); root.tile = r.Next(tileSet.tiles.Count); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); int minSize = 8; Graphics g2 = Graphics.FromImage(dest); g2.Clear(Color.White); Refine_r(root, rect, grayscale, minSize, 0, 5, tonalRange, dest); }
public WTStipple(Image source, WangTileSet tileSet, int tonalRange, Bitmap dest ) { // Convert source image to grayscale Bitmap bmp = new Bitmap(source.Width, source.Height); Graphics g = Graphics.FromImage(bmp); g.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height)); float[,] grayscale = ToDensity(bmp); this.tileSet = tileSet; // Subdivide image recusively as long as we need more density on each leave's tile // to account for the underlying sampled region on the image ImageTreeNode root = new ImageTreeNode(); Random r = new Random(tileSet.tiles.Count); root.tile = r.Next(tileSet.tiles.Count); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); int minSize = 8; Graphics g2 = Graphics.FromImage(dest); g2.Clear(Color.White); Refine_r(root, rect, grayscale, minSize, 0, 5, tonalRange, dest ); }
private void Refine_r(ImageTreeNode node, Rectangle rect, float[,] density, int minSize, int depth, int maxDepth, int toneScale, Bitmap dest) { Debug.Assert(node.tile != -1); List<PoissonDist.PoissonSample> distribution = tileSet.tiles[node.tile].distribution; float tileMaxDensity = (float)distribution.Count; float requiredDensity = AreaDensity(density, rect); // Cover the area with the current tile float tileAvgDensity = Math.Min(1.0f, tileMaxDensity / (rect.Width * rect.Height)); for (int i = 0; i < distribution.Count; i++) { int stippleX = rect.Left + (int)(rect.Width * distribution[i].x); int stippleY = rect.Top + (int)(rect.Height * distribution[i].y); float r = 1;//Math.Max(1, (distribution[i].radius * rect.Width)); float area = (float)(r*r * Math.PI); float diskDensity = DiskDensity(density, new Point(stippleX, stippleY), (int)r); float diskAvgDensity = diskDensity / area; float factor = (float)(0.1f / Math.Pow(1, -2) * Math.Pow(4, 2.0f * depth) / toneScale); if (diskAvgDensity < (float)i * factor) continue; dest.SetPixel(stippleX, stippleY, Color.Black); } // Check whether we need to keep subdividing if (rect.Width <= minSize || rect.Height <= minSize || depth == maxDepth) return; if (Math.Pow(0.1, -2) / Math.Pow(4, 2 * depth) * toneScale - tileMaxDensity > 16 * tileMaxDensity ) { // we need to subdivide int[,] subd; int splitsPerDimension; tileSet.GetSubdivisions(node.tile, out subd, out splitsPerDimension); node.children = new ImageTreeNode[splitsPerDimension, splitsPerDimension]; Size childRectSize = new Size((int)Math.Floor((float)rect.Width / splitsPerDimension), (int)Math.Floor((float)rect.Height / splitsPerDimension)); for (int j = 0; j < splitsPerDimension; j++) { for (int i = 0; i < splitsPerDimension; i++) { node.children[i, j] = new ImageTreeNode(); node.children[i, j].tile = subd[i, j]; Rectangle childRect = new Rectangle(rect.X + i * childRectSize.Width, rect.Y + j * childRectSize.Height, childRectSize.Width, childRectSize.Height); if (i == splitsPerDimension - 1) // adjust borders childRect.Width = rect.Right - childRect.X; if (j == splitsPerDimension - 1) // adjust borders childRect.Height = rect.Bottom - childRect.Y; Refine_r(node.children[i, j], childRect, density, minSize, depth + 1, maxDepth, toneScale, dest); } } } }
private void Refine_r(ImageTreeNode node, Rectangle rect, float[,] density, int minSize, int depth, int maxDepth, int toneScale, Bitmap dest) { Debug.Assert(node.tile != -1); List <PoissonDist.PoissonSample> distribution = tileSet.tiles[node.tile].distribution; float tileMaxDensity = (float)distribution.Count; float requiredDensity = AreaDensity(density, rect); // Cover the area with the current tile float tileAvgDensity = Math.Min(1.0f, tileMaxDensity / (rect.Width * rect.Height)); for (int i = 0; i < distribution.Count; i++) { int stippleX = rect.Left + (int)(rect.Width * distribution[i].x); int stippleY = rect.Top + (int)(rect.Height * distribution[i].y); float r = 1;//Math.Max(1, (distribution[i].radius * rect.Width)); float area = (float)(r * r * Math.PI); float diskDensity = DiskDensity(density, new Point(stippleX, stippleY), (int)r); float diskAvgDensity = diskDensity / area; float factor = (float)(0.1f / Math.Pow(1, -2) * Math.Pow(4, 2.0f * depth) / toneScale); if (diskAvgDensity < (float)i * factor) { continue; } dest.SetPixel(stippleX, stippleY, Color.Black); } // Check whether we need to keep subdividing if (rect.Width <= minSize || rect.Height <= minSize || depth == maxDepth) { return; } if (Math.Pow(0.1, -2) / Math.Pow(4, 2 * depth) * toneScale - tileMaxDensity > 16 * tileMaxDensity) { // we need to subdivide int[,] subd; int splitsPerDimension; tileSet.GetSubdivisions(node.tile, out subd, out splitsPerDimension); node.children = new ImageTreeNode[splitsPerDimension, splitsPerDimension]; Size childRectSize = new Size((int)Math.Floor((float)rect.Width / splitsPerDimension), (int)Math.Floor((float)rect.Height / splitsPerDimension)); for (int j = 0; j < splitsPerDimension; j++) { for (int i = 0; i < splitsPerDimension; i++) { node.children[i, j] = new ImageTreeNode(); node.children[i, j].tile = subd[i, j]; Rectangle childRect = new Rectangle(rect.X + i * childRectSize.Width, rect.Y + j * childRectSize.Height, childRectSize.Width, childRectSize.Height); if (i == splitsPerDimension - 1) // adjust borders { childRect.Width = rect.Right - childRect.X; } if (j == splitsPerDimension - 1) // adjust borders { childRect.Height = rect.Bottom - childRect.Y; } Refine_r(node.children[i, j], childRect, density, minSize, depth + 1, maxDepth, toneScale, dest); } } } }