Other Posts in Image Editing

  1. Perlin Noise
  2. Fault Formation
  3. Cellular Textures
  4. Resizing an Image in C#
  5. Box Blur and Gaussian Blur... Sort of...
  6. Thermal Erosion
  7. Using Mid Point Displacement to Create Cracks
  8. Fluvial Erosion
  9. Creating Marble Like Textures Procedurally
  10. Procedural Textures and Dilation
  11. Converting Image to Black and White in C#
  12. Getting an HTML Based Color Palette from an Image in C#
  13. Adding Noise/Jitter to an Image in C#
  14. Creating Pixelated Images in C#
  15. Edge detection in C#
  16. Using Sin to Get What You Want... In C#...
  17. Noise Reduction of an Image in C# using Median Filters
  18. Image Dilation in C#
  19. Sepia Tone in C#
  20. Kuwahara Filter in C#
  21. Matrix Convolution Filters in C#
  22. Symmetric Nearest Neighbor in C#
  23. Bump Map Creation Using C#
  24. Normal Map Creation Using C#
  25. Creating Negative Images using C#
  26. Red, Blue, and Green Filters in C#
  27. Converting an Image to ASCII Art in C#
  28. Adjusting Brightness of an Image in C#
  29. Adding Noise to an Image in C#
  30. Adjusting the Gamma of an Image Using C#
  31. Adjusting Contrast of an Image in C#
  32. Drawing a Box With Rounded Corners in C#
  33. Anding Two Images Together Using C#
  34. Motion Detection in C#
  35. Creating Thermometer Chart in C#
  36. Colorizing a Black and White Image in C#
  37. Extracting an Icon From a File
  38. Setting the Pixel Format and Image Format of an Image in .Net
  39. Using Unsafe Code for Faster Image Manipulation
  40. Sobel Edge Detection and Laplace Edge Detection in C#

Cellular Textures

3/25/2008

Cellular textures are another form of procedural content generation. In fact it's probably one of the easier ones out there as there is no smoothing, blurring, etc. All we do is create a bunch of random points within the space, determine which one each pixel is closest to, and based on it's distance to that point we change the color. As such it creates what can best be described as cells, with lines separating each one. The lines within the image are created where two or more points of interest border each other. As always, I'm certain that you're interested in the code more than the description so here it is:

   1: /*
   2: Copyright (c) 2010 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System.Drawing;
  24: using System.Drawing.Imaging;
  25: #endregion
  26:  
  27: namespace Utilities.Media.Image
  28: {
  29:     /// <summary>
  30:     /// Cellular texture helper
  31:     /// </summary>
  32:     public static class CellularTexture
  33:     {
  34:         #region Functions
  35:         
  36:         /// <summary>
  37:         /// Generates a cellular texture image
  38:         /// </summary>
  39:         /// <param name="Width">Width</param>
  40:         /// <param name="Height">Height</param>
  41:         /// <param name="NumberOfPoints">Number of points</param>
  42:         /// <param name="Seed">Random seed</param>
  43:         /// <returns>Returns an image of a cellular texture</returns>
  44:         public static Bitmap Generate(int Width, int Height, int NumberOfPoints, int Seed)
  45:         {
  46:             float[,] DistanceBuffer = new float[Width, Height];
  47:             Points[] PointArray = new Points[NumberOfPoints];
  48:             float MinimumDistance = float.MaxValue;
  49:             float MaxDistance = float.MinValue;
  50:             System.Random Generator = new System.Random(Seed);
  51:             for (int x = 0; x < NumberOfPoints; ++x)
  52:             {
  53:                 PointArray[x].X = Generator.Next(0, Width);
  54:                 PointArray[x].Y = Generator.Next(0, Height);
  55:             }
  56:             for (int y = 0; y < Height; ++y)
  57:             {
  58:                 for (int x = 0; x < Width; ++x)
  59:                 {
  60:                     DistanceBuffer[x, y] = DistanceNearestPoint(x, y, PointArray);
  61:                     if (DistanceBuffer[x, y] > MaxDistance)
  62:                         MaxDistance = DistanceBuffer[x, y];
  63:                     else if (DistanceBuffer[x, y] < MinimumDistance)
  64:                         MinimumDistance = DistanceBuffer[x, y];
  65:                 }
  66:             }
  67:             Bitmap ReturnValue = new Bitmap(Width, Height);
  68:             BitmapData ImageData = Image.LockImage(ReturnValue);
  69:             int ImagePixelSize = Image.GetPixelSize(ImageData);
  70:             for (int x = 0; x < Width; ++x)
  71:             {
  72:                 for (int y = 0; y < Height; ++y)
  73:                 {
  74:                     float Value = GetHeight(x, y, DistanceBuffer, MinimumDistance, MaxDistance);
  75:                     Value *= 255;
  76:                     int RGBValue = Math.MathHelper.Clamp((int)Value, 255, 0);
  77:                     Image.SetPixel(ImageData, x, y, Color.FromArgb(RGBValue, RGBValue, RGBValue), ImagePixelSize);
  78:                 }
  79:             }
  80:             Image.UnlockImage(ReturnValue, ImageData);
  81:             return ReturnValue;
  82:         }
  83:  
  84:         private static float GetHeight(float X, float Y, float[,] DistanceBuffer,
  85:             float MinimumDistance,float MaxDistance)
  86:         {
  87:             return (DistanceBuffer[(int)X, (int)Y] - MinimumDistance) / (MaxDistance - MinimumDistance);
  88:         }
  89:  
  90:         private static float DistanceNearestPoint(int x, int y,Points[] PointArray)
  91:         {
  92:             float Lowest = float.MaxValue;
  93:             for (int z = 0; z < PointArray.Length; ++z)
  94:             {
  95:                 float Distance = (float)System.Math.Sqrt(((PointArray[z].X - x) * (PointArray[z].X - x)) + ((PointArray[z].Y - y) * (PointArray[z].Y - y)));
  96:                 if (Distance < Lowest)
  97:                 {
  98:                     Lowest = Distance;
  99:                 }
 100:             }
 101:             return Lowest;
 102:         }
 103:  
 104:         #endregion
 105:     }
 106:  
 107:     #region Structs
 108:  
 109:     internal struct Points
 110:     {
 111:         public float X;
 112:         public float Y;
 113:     }
 114:  
 115:     #endregion
 116: }
The code above is a part of my utility library and as such if you run into any issues you may want to check there for any sort of update. Also the code above uses a bit of code from the utility library for unlocking/locking the bitmap in order to speed it up a bit. That code can be found here. Anyway, this algorithm is great for various tasks including bump mapping, creating certain textures (scales or a rock path for instance), special effects, etc. There's even uses in AI, world creation, etc. So it's definitely an algorithm to take a look at. As always take a look, leave feedback, and happy coding.


Comments