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#

Creating Marble Like Textures Procedurally

4/26/2008

One of the items I recently added to the library that I've been working on is a turbulence function. It basically takes an image as input, creates two Perlin noise images, and uses them to determine the pixel offset between the output image and the input image... It's similar to using a sin wave but the resulting image, instead of having a wave through it, looks similar to marble. The reason we use Perlin noise instead of straight random numbers is we want the noise to be coherent. The smoother the noise, the more the final image is going to look like something coherent instead of random. And since marble, wood textures, etc. all need some semblance of coherency, we need it to act in this manner. Anyway, I'm sure that you're interested in the code:

   1: /// <summary>
   2: /// Does turbulence manipulation of the image
   3: /// </summary>
   4: /// <param name="OriginalImage">Image to transform</param>
   5: /// <param name="Roughness">Roughness of the movement</param>
   6: /// <param name="Power">How strong the movement is</param>
   7: /// <param name="Seed">Random seed</param>
   8: /// <returns>A bitmap object containing the new image</returns>
   9: public static Bitmap Turbulence(Bitmap OriginalImage, int Roughness, float Power, int Seed)
  10: {
  11:     int Width = OriginalImage.Width;
  12:     int Height = OriginalImage.Height;
  13:     BitmapData OriginalData = Image.LockImage(OriginalImage);
  14:     int OriginalPixelSize = Image.GetPixelSize(OriginalData);
  15:     Bitmap ReturnValue = new Bitmap(Width, Height);
  16:     BitmapData ReturnData = Image.LockImage(ReturnValue);
  17:     int ReturnPixelSize = Image.GetPixelSize(ReturnData);
  18:     using (Bitmap XNoise = PerlinNoise.Generate(Width, Height, 255, 0, 0.0625f, 1.0f, 0.5f, Roughness, Seed))
  19:     {
  20:         BitmapData XNoiseData = Image.LockImage(XNoise);
  21:         int XNoisePixelSize = Image.GetPixelSize(XNoiseData);
  22:         using (Bitmap YNoise = PerlinNoise.Generate(Width, Height, 255, 0, 0.0625f, 1.0f, 0.5f, Roughness, Seed * 2))
  23:         {
  24:             BitmapData YNoiseData = Image.LockImage(YNoise);
  25:             int YNoisePixelSize = Image.GetPixelSize(YNoiseData);
  26:             for (int y = 0; y < Height; ++y)
  27:             {
  28:                 for (int x = 0; x < Width; ++x)
  29:                 {
  30:                     float XDistortion = x + (GetHeight(x, y, XNoiseData, XNoisePixelSize) * Power);
  31:                     float YDistortion = y + (GetHeight(x, y, YNoiseData, YNoisePixelSize) * Power);
  32:                     int X1 = Math.MathHelper.Clamp((int)XDistortion, Width - 1, 0);
  33:                     int Y1 = Math.MathHelper.Clamp((int)YDistortion, Height - 1, 0);
  34:                     Image.SetPixel(ReturnData, x, y, GetPixel(OriginalData, X1, Y1, OriginalPixelSize), ReturnPixelSize);
  35:                 }
  36:             }
  37:             UnlockImage(YNoise, YNoiseData);
  38:         }
  39:         UnlockImage(XNoise, XNoiseData);
  40:     }
  41:     UnlockImage(ReturnValue, ReturnData);
  42:     UnlockImage(OriginalImage, OriginalData);
  43:     return ReturnValue;
  44: }
   1: private static float GetHeight(int x, int y, BitmapData BlackAndWhiteData, int BlackAndWhitePixelSize)
   2: {
   3:     Color TempColor = Image.GetPixel(BlackAndWhiteData, x, y, BlackAndWhitePixelSize);
   4:     return GetHeight(TempColor);
   5: }
   1: private static float GetHeight(Color Color)
   2: {
   3:     return (float)Color.R / 255.0f;
   4: }

The code uses a couple of functions from my utility library to speed things up (namely locking/unlocking the bitmap and a clamp function from my MathHelper class), but they can be replaced with a simple GetPixel/SetPixel if you would like (and your own clamping function). On top of that it uses my Perlin noise code. You will need that in order for it to work. So try out the code, leave feedback, and as always happy coding.



Comments

Josh Parnell
February 04, 2010 1:48 PM

Excellent demonstration, and very nice results. Thanks for this.